1/*
2 * Copyright (c) 2013-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <string.h>
30#include <sys/systm.h>
31#include <sys/types.h>
32#include <sys/syslog.h>
33#include <sys/queue.h>
34#include <sys/malloc.h>
35#include <libkern/OSMalloc.h>
36#include <sys/kernel.h>
37#include <sys/kern_control.h>
38#include <sys/mbuf.h>
39#include <sys/kpi_mbuf.h>
40#include <sys/proc_uuid_policy.h>
41#include <net/if.h>
42#include <sys/protosw.h>
43#include <sys/socket.h>
44#include <sys/socketvar.h>
45#include <netinet/ip.h>
46#include <netinet/ip6.h>
47#include <netinet/tcp.h>
48#include <netinet/udp.h>
49#include <netinet/in_pcb.h>
50#include <net/flowhash.h>
51#include <net/if_var.h>
52#include <sys/kauth.h>
53#include <sys/sysctl.h>
54#include <sys/sysproto.h>
55#include <sys/priv.h>
56#include <net/necp.h>
57
58/*
59 * NECP - Network Extension Control Policy database
60 * ------------------------------------------------
61 * The goal of this module is to allow clients connecting via a
62 * kernel control socket to create high-level policy sessions, which
63 * are ingested into low-level kernel policies that control and tag
64 * traffic at the application, socket, and IP layers.
65 *
66 * ------------------------------------------------
67 * Sessions
68 * ------------------------------------------------
69 * Each session owns a list of session policies, each of which can
70 * specify any combination of conditions and a single result. Each
71 * session also has a priority level (such as High, Default, or Low)
72 * which is requested by the client. Based on the requested level,
73 * a session order value is assigned to the session, which will be used
74 * to sort kernel policies generated by the session. The session client
75 * can specify the sub-order for each policy it creates which will be
76 * used to further sort the kernel policies.
77 *
78 *  Kernel Control Socket --> 1 necp_session --> list of necp_session_policy structs
79 *
80 * ------------------------------------------------
81 * Kernel Policies
82 * ------------------------------------------------
83 * Whenever a session send the Apply command, its policies are ingested
84 * and generate kernel policies. There are two phases of kernel policy
85 * ingestion.
86 *
87 * 1. The session policy is parsed to create kernel policies at the socket
88 *	  and IP layers, when applicable. For example, a policy that requires
89 *    all traffic from App1 to Pass will generate a socket kernel policy to
90 *    match App1 and mark packets with ID1, and also an IP policy to match
91 *    ID1 and let the packet pass. This is handled in necp_apply_policy. The
92 *    resulting kernel policies are added to the global socket and IP layer
93 *    policy lists.
94 *  necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
95 *                                      ||                             ||
96 *                                      \/                             \/
97 *                          necp_kernel_socket_policies   necp_kernel_ip_output_policies
98 *
99 * 2. Once the global lists of kernel policies have been filled out, each
100 *    list is traversed to create optimized sub-lists ("Maps") which are used during
101 *    data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
102 *    which hashes incoming packets based on marked socket-layer policies, and removes
103 *    duplicate or overlapping polcies. Socket policies are sent into two maps,
104 *    necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
105 *    The app layer map is used for policy checks coming in from user space, and is one
106 *    list with duplicate and overlapping policies removed. The socket map hashes based
107 *    on app UUID, and removes duplicate and overlapping policies.
108 *  necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
109 *                            |-> necp_kernel_socket_policies_map
110 *
111 *  necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
112 *
113 * ------------------------------------------------
114 * Drop All Level
115 * ------------------------------------------------
116 * The Drop All Level is a sysctl that controls the level at which policies are allowed
117 * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
118 * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
119 * by a session with a priority level better than (numerically less than) the
120 * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
121 * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
122 * session orders to be dropped.
123 */
124
125u_int32_t necp_drop_all_order = 0;
126u_int32_t necp_drop_all_level = 0;
127
128u_int32_t necp_pass_loopback = 1; // 0=Off, 1=On
129u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
130
131u_int32_t necp_debug = 0; // 0=None, 1=Basic, 2=EveryMatch
132
133static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
134
135SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
136SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
137SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
138SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
139SYSCTL_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", "");
140
141#define	NECPLOG(level, format, ...) do {											\
142	log((level > LOG_NOTICE ? LOG_NOTICE : level), "%s: " format "\n", __FUNCTION__, __VA_ARGS__); 	\
143} while (0)
144
145#define	NECPLOG0(level, msg) do {											\
146	log((level > LOG_NOTICE ? LOG_NOTICE : level), "%s: %s\n", __FUNCTION__, msg); 	\
147} while (0)
148
149#define	LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do {		\
150	if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) {	\
151		LIST_INSERT_HEAD((head), elm, field);										\
152	} else {																		\
153		LIST_FOREACH(tmpelm, head, field) {											\
154			if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) {	\
155				LIST_INSERT_AFTER(tmpelm, elm, field);								\
156				break;																\
157			}																		\
158		}																			\
159	}																				\
160} while (0)
161
162#define	LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do {	\
163	if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) {														\
164		LIST_INSERT_HEAD((head), elm, field);										\
165	} else {																		\
166		LIST_FOREACH(tmpelm, head, field) {											\
167			if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield))) {		\
168				LIST_INSERT_AFTER(tmpelm, elm, field);								\
169				break;																\
170			}																		\
171		}																			\
172	}																				\
173} while (0)
174
175#define	LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
176	if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield == (elm)->secondsortfield) && (LIST_FIRST(head)->thirdsortfield >= (elm)->thirdsortfield))) {															\
177		LIST_INSERT_HEAD((head), elm, field);										\
178	} else {																		\
179		LIST_FOREACH(tmpelm, head, field) {											\
180			if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield == (elm)->secondsortfield) && (LIST_NEXT(tmpelm, field)->thirdsortfield >= (elm)->thirdsortfield)))	{ \
181				LIST_INSERT_AFTER(tmpelm, elm, field);								\
182				break;																\
183			}																		\
184		}																			\
185	}																				\
186} while (0)
187
188#define	NECP_KERNEL_CONDITION_ALL_INTERFACES	0x00001
189#define	NECP_KERNEL_CONDITION_BOUND_INTERFACE	0x00002
190#define	NECP_KERNEL_CONDITION_PROTOCOL			0x00004
191#define	NECP_KERNEL_CONDITION_LOCAL_START		0x00008
192#define	NECP_KERNEL_CONDITION_LOCAL_END			0x00010
193#define	NECP_KERNEL_CONDITION_LOCAL_PREFIX		0x00020
194#define	NECP_KERNEL_CONDITION_REMOTE_START		0x00040
195#define	NECP_KERNEL_CONDITION_REMOTE_END		0x00080
196#define	NECP_KERNEL_CONDITION_REMOTE_PREFIX		0x00100
197#define	NECP_KERNEL_CONDITION_APP_ID			0x00200
198#define	NECP_KERNEL_CONDITION_REAL_APP_ID		0x00400
199#define	NECP_KERNEL_CONDITION_DOMAIN			0x00800
200#define	NECP_KERNEL_CONDITION_ACCOUNT_ID		0x01000
201#define	NECP_KERNEL_CONDITION_POLICY_ID			0x02000
202#define	NECP_KERNEL_CONDITION_PID				0x04000
203#define	NECP_KERNEL_CONDITION_UID				0x08000
204#define	NECP_KERNEL_CONDITION_LAST_INTERFACE	0x10000			// Only set from packets looping between interfaces
205#define NECP_KERNEL_CONDITION_TRAFFIC_CLASS		0x20000
206#define NECP_KERNEL_CONDITION_ENTITLEMENT		0x40000
207
208struct necp_service_registration {
209	LIST_ENTRY(necp_service_registration)	session_chain;
210	LIST_ENTRY(necp_service_registration)	kernel_chain;
211	u_int32_t								service_id;
212};
213
214struct necp_session {
215	u_int32_t					control_unit;
216	u_int32_t					session_priority; // Descriptive priority rating
217	u_int32_t					session_order;
218
219	bool						proc_locked; // Messages must come from proc_uuid
220	uuid_t						proc_uuid;
221
222	bool						dirty;
223	LIST_HEAD(_policies, necp_session_policy) policies;
224
225	LIST_HEAD(_services, necp_service_registration) services;
226};
227
228struct necp_socket_info {
229	pid_t pid;
230	uid_t uid;
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;
235	u_int16_t protocol;
236	u_int32_t application_id;
237	u_int32_t real_application_id;
238	u_int32_t account_id;
239	char *domain;
240	errno_t cred_result;
241};
242
243static kern_ctl_ref	necp_kctlref;
244static u_int32_t	necp_family;
245static OSMallocTag	necp_malloc_tag;
246static	lck_grp_attr_t	*necp_kernel_policy_grp_attr	= NULL;
247static	lck_attr_t		*necp_kernel_policy_mtx_attr	= NULL;
248static	lck_grp_t		*necp_kernel_policy_mtx_grp		= NULL;
249decl_lck_rw_data(static, necp_kernel_policy_lock);
250
251static necp_policy_id necp_last_policy_id = 0;
252static necp_kernel_policy_id necp_last_kernel_policy_id = 0;
253static u_int32_t necp_last_uuid_id = 0;
254static u_int32_t necp_last_string_id = 0;
255
256/*
257 * On modification, invalidate cached lookups by bumping the generation count.
258 * Other calls will need to take the slowpath of taking
259 * the subsystem lock.
260 */
261static volatile int32_t necp_kernel_socket_policies_gencount;
262#define	BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do {							\
263	if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) {	\
264		necp_kernel_socket_policies_gencount = 1;										\
265	}																				\
266} while (0)
267
268static u_int32_t necp_kernel_application_policies_condition_mask;
269static size_t necp_kernel_application_policies_count;
270static u_int32_t necp_kernel_socket_policies_condition_mask;
271static size_t necp_kernel_socket_policies_count;
272static size_t necp_kernel_socket_policies_non_app_count;
273static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
274#define	NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
275#define	NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
276static struct necp_kernel_socket_policy **necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
277static struct necp_kernel_socket_policy **necp_kernel_socket_policies_app_layer_map;
278/*
279 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
280 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
281 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
282 *
283 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
284 */
285
286static u_int32_t necp_kernel_ip_output_policies_condition_mask;
287static size_t necp_kernel_ip_output_policies_count;
288static size_t necp_kernel_ip_output_policies_non_id_count;
289static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
290#define	NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
291#define	NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
292static struct necp_kernel_ip_output_policy **necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
293
294static struct necp_session *necp_create_session(u_int32_t control_unit);
295static void necp_delete_session(struct necp_session *session);
296
297static void necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
298static void necp_handle_policy_get(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
299static void necp_handle_policy_delete(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
300static void necp_handle_policy_apply_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
301static void necp_handle_policy_list_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
302static void necp_handle_policy_delete_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
303static void necp_handle_set_session_priority(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
304static void necp_handle_lock_session_to_proc(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
305static void necp_handle_register_service(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
306static void necp_handle_unregister_service(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
307
308static struct necp_session_policy *necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t *conditions_array, size_t conditions_array_size, u_int8_t *result, size_t result_size);
309static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
310static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
311static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
312static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
313static void necp_policy_apply_all(struct necp_session *session);
314
315static necp_kernel_policy_id necp_kernel_socket_policy_add(necp_policy_id parent_policy_id, necp_policy_order order, u_int32_t session_order, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, u_int32_t cond_account_id, char *domain, pid_t cond_pid, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
316static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
317static bool necp_kernel_socket_policies_reprocess(void);
318static bool necp_kernel_socket_policies_update_uuid_table(void);
319static inline struct necp_kernel_socket_policy *necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy **policy_search_array, struct necp_socket_info *info, necp_kernel_policy_filter *return_filter, necp_kernel_policy_result *return_service_action, necp_kernel_policy_service *return_service);
320
321static necp_kernel_policy_id necp_kernel_ip_output_policy_add(necp_policy_id parent_policy_id, necp_policy_order order, necp_policy_order suborder, u_int32_t session_order, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_kernel_policy_id cond_policy_id, ifnet_t cond_bound_interface, u_int32_t cond_last_interface_index, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
322static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
323static bool necp_kernel_ip_output_policies_reprocess(void);
324
325static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
326static bool necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end);
327static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
328static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
329static bool necp_buffer_compare_with_bit_prefix(u_int8_t *p1, u_int8_t *p2, u_int32_t bits);
330static bool necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet);
331
332struct necp_uuid_id_mapping {
333	LIST_ENTRY(necp_uuid_id_mapping) chain;
334	uuid_t		uuid;
335	u_int32_t	id;
336	u_int32_t	refcount;
337	u_int32_t	table_refcount; // Add to UUID policy table count
338};
339static size_t necp_num_uuid_app_id_mappings;
340static bool necp_uuid_app_id_mappings_dirty;
341#define	NECP_UUID_APP_ID_HASH_SIZE 64
342static u_long necp_uuid_app_id_hash_mask;
343static u_long necp_uuid_app_id_hash_num_buckets;
344static LIST_HEAD(necp_uuid_id_mapping_head, necp_uuid_id_mapping) *necp_uuid_app_id_hashtbl, necp_uuid_service_id_list; // App map is real hash table, service map is just mapping
345#define	APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
346static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
347static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
348
349static struct necp_uuid_id_mapping *necp_uuid_lookup_service_id_locked(uuid_t uuid);
350static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
351static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
352static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
353
354struct necp_string_id_mapping {
355	LIST_ENTRY(necp_string_id_mapping) chain;
356	char		*string;
357	necp_app_id	id;
358	u_int32_t	refcount;
359};
360static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
361static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain);
362static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain);
363
364static LIST_HEAD(_necp_kernel_service_list, necp_service_registration) necp_registered_service_list;
365
366static char *necp_create_trimmed_domain(char *string, size_t length);
367static inline int necp_count_dots(char *string, size_t length);
368
369// Session order allocation
370static u_int32_t
371necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
372{
373	u_int32_t new_order = 0;
374
375	// For now, just allocate 1000 orders for each priority
376	if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
377		priority = NECP_SESSION_PRIORITY_DEFAULT;
378	}
379
380	// Use the control unit to decide the offset into the priority list
381	new_order = (control_unit) + ((priority - 1) * 1000);
382
383	return (new_order);
384}
385
386static inline u_int32_t
387necp_get_first_order_for_priority(u_int32_t priority)
388{
389	return (((priority - 1) * 1000) + 1);
390}
391
392// Sysctl handler
393static int
394sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
395{
396#pragma unused(arg1, arg2)
397	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
398	if (necp_drop_all_level == 0) {
399		necp_drop_all_order = 0;
400	} else {
401		necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
402	}
403	return (error);
404}
405
406
407// Kernel Control functions
408static errno_t necp_register_control(void);
409static errno_t necp_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo);
410static errno_t necp_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo);
411static errno_t necp_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t m, int flags);
412static void necp_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags);
413static errno_t necp_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t *len);
414static errno_t necp_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len);
415
416static bool necp_send_ctl_data(struct necp_session *session, u_int8_t *buffer, size_t buffer_size);
417
418errno_t
419necp_init(void)
420{
421	errno_t result = 0;
422
423	result = necp_register_control();
424	if (result != 0) {
425		goto done;
426	}
427
428	necp_kernel_policy_grp_attr = lck_grp_attr_alloc_init();
429	if (necp_kernel_policy_grp_attr == NULL) {
430		NECPLOG0(LOG_ERR, "lck_grp_attr_alloc_init failed");
431		result = ENOMEM;
432		goto done;
433	}
434
435	necp_kernel_policy_mtx_grp = lck_grp_alloc_init(NECP_CONTROL_NAME, necp_kernel_policy_grp_attr);
436	if (necp_kernel_policy_mtx_grp == NULL) {
437		NECPLOG0(LOG_ERR, "lck_grp_alloc_init failed");
438		result = ENOMEM;
439		goto done;
440	}
441
442	necp_kernel_policy_mtx_attr = lck_attr_alloc_init();
443	if (necp_kernel_policy_mtx_attr == NULL) {
444		NECPLOG0(LOG_ERR, "lck_attr_alloc_init failed");
445		result = ENOMEM;
446		goto done;
447	}
448
449	lck_rw_init(&necp_kernel_policy_lock, necp_kernel_policy_mtx_grp, necp_kernel_policy_mtx_attr);
450
451	LIST_INIT(&necp_kernel_socket_policies);
452	LIST_INIT(&necp_kernel_ip_output_policies);
453
454	LIST_INIT(&necp_account_id_list);
455
456	LIST_INIT(&necp_uuid_service_id_list);
457
458	LIST_INIT(&necp_registered_service_list);
459
460	necp_uuid_app_id_hashtbl = hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask);
461	necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
462	necp_num_uuid_app_id_mappings = 0;
463	necp_uuid_app_id_mappings_dirty = FALSE;
464
465	necp_kernel_application_policies_condition_mask = 0;
466	necp_kernel_socket_policies_condition_mask = 0;
467	necp_kernel_ip_output_policies_condition_mask = 0;
468
469	necp_kernel_application_policies_count = 0;
470	necp_kernel_socket_policies_count = 0;
471	necp_kernel_socket_policies_non_app_count = 0;
472	necp_kernel_ip_output_policies_count = 0;
473	necp_kernel_ip_output_policies_non_id_count = 0;
474
475	necp_last_policy_id = 0;
476	necp_last_kernel_policy_id = 0;
477
478	necp_kernel_socket_policies_gencount = 1;
479
480	memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
481	memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
482	necp_kernel_socket_policies_app_layer_map = NULL;
483
484done:
485	if (result != 0) {
486		if (necp_kernel_policy_mtx_attr != NULL) {
487			lck_attr_free(necp_kernel_policy_mtx_attr);
488			necp_kernel_policy_mtx_attr = NULL;
489		}
490		if (necp_kernel_policy_mtx_grp != NULL) {
491			lck_grp_free(necp_kernel_policy_mtx_grp);
492			necp_kernel_policy_mtx_grp = NULL;
493		}
494		if (necp_kernel_policy_grp_attr != NULL) {
495			lck_grp_attr_free(necp_kernel_policy_grp_attr);
496			necp_kernel_policy_grp_attr = NULL;
497		}
498		if (necp_kctlref != NULL) {
499			ctl_deregister(necp_kctlref);
500			necp_kctlref = NULL;
501		}
502	}
503	return (result);
504}
505
506static errno_t
507necp_register_control(void)
508{
509	struct kern_ctl_reg	kern_ctl;
510	errno_t				result = 0;
511
512	// Create a tag to allocate memory
513	necp_malloc_tag = OSMalloc_Tagalloc(NECP_CONTROL_NAME, OSMT_DEFAULT);
514
515	// Find a unique value for our interface family
516	result = mbuf_tag_id_find(NECP_CONTROL_NAME, &necp_family);
517	if (result != 0) {
518		NECPLOG(LOG_ERR, "mbuf_tag_id_find_internal failed: %d", result);
519		return (result);
520	}
521
522	bzero(&kern_ctl, sizeof(kern_ctl));
523	strlcpy(kern_ctl.ctl_name, NECP_CONTROL_NAME, sizeof(kern_ctl.ctl_name));
524	kern_ctl.ctl_name[sizeof(kern_ctl.ctl_name) - 1] = 0;
525	kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED; // Require root
526	kern_ctl.ctl_sendsize = 64 * 1024;
527	kern_ctl.ctl_recvsize = 64 * 1024;
528	kern_ctl.ctl_connect = necp_ctl_connect;
529	kern_ctl.ctl_disconnect = necp_ctl_disconnect;
530	kern_ctl.ctl_send = necp_ctl_send;
531	kern_ctl.ctl_rcvd = necp_ctl_rcvd;
532	kern_ctl.ctl_setopt = necp_ctl_setopt;
533	kern_ctl.ctl_getopt = necp_ctl_getopt;
534
535	result = ctl_register(&kern_ctl, &necp_kctlref);
536	if (result != 0) {
537		NECPLOG(LOG_ERR, "ctl_register failed: %d", result);
538		return (result);
539	}
540
541	return (0);
542}
543
544static errno_t
545necp_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo)
546{
547#pragma unused(kctlref)
548	*unitinfo = necp_create_session(sac->sc_unit);
549	if (*unitinfo == NULL) {
550		// Could not allocate session
551		return (ENOBUFS);
552	}
553
554	return (0);
555}
556
557static errno_t
558necp_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo)
559{
560#pragma unused(kctlref, unit)
561	struct necp_session *session = (struct necp_session *)unitinfo;
562	if (session != NULL) {
563		necp_policy_mark_all_for_deletion(session);
564		necp_policy_apply_all(session);
565		necp_delete_session((struct necp_session *)unitinfo);
566	}
567
568	return (0);
569}
570
571
572// Message handling
573static int
574necp_packet_find_tlv(mbuf_t packet, int offset, u_int8_t type, int *err, int next)
575{
576	size_t	cursor			= offset;
577	int		error			= 0;
578	size_t	curr_length;
579	u_int8_t	curr_type;
580
581	*err = 0;
582
583	do {
584		if (!next) {
585			error = mbuf_copydata(packet, cursor, sizeof(curr_type), &curr_type);
586			if (error) {
587				*err = ENOENT;
588				return (-1);
589			}
590		} else {
591			next = 0;
592			curr_type = NECP_TLV_NIL;
593		}
594
595		if (curr_type != type) {
596			cursor += sizeof(curr_type);
597			error = mbuf_copydata(packet, cursor, sizeof(curr_length), &curr_length);
598			if (error) {
599				*err = error;
600				return (-1);
601			}
602			cursor += (sizeof(curr_length) + curr_length);
603		}
604	} while (curr_type != type);
605
606	return (cursor);
607}
608
609static int
610necp_packet_get_tlv_at_offset(mbuf_t packet, int tlv_offset, size_t buff_len, void *buff, size_t *value_size)
611{
612	int		error		= 0;
613	size_t	length;
614
615	if (tlv_offset < 0) {
616		return (error);
617	}
618
619	error = mbuf_copydata(packet, tlv_offset + sizeof(u_int8_t), sizeof(length), &length);
620	if (error) {
621		return (error);
622	}
623
624	if (value_size != NULL) {
625		*value_size = length;
626	}
627
628	if (buff != NULL && buff_len > 0) {
629		size_t to_copy = (length < buff_len) ? length : buff_len;
630		error = mbuf_copydata(packet, tlv_offset + sizeof(u_int8_t) + sizeof(length), to_copy, buff);
631		if (error) {
632			return (error);
633		}
634	}
635
636	return (0);
637}
638
639static int
640necp_packet_get_tlv(mbuf_t packet, int offset, u_int8_t type, size_t buff_len, void *buff, size_t *value_size)
641{
642	int		error		= 0;
643	int		tlv_offset;
644
645	tlv_offset = necp_packet_find_tlv(packet, offset, type, &error, 0);
646	if (tlv_offset < 0) {
647		return (error);
648	}
649
650	return (necp_packet_get_tlv_at_offset(packet, tlv_offset, buff_len, buff, value_size));
651}
652
653static u_int8_t *
654necp_buffer_write_packet_header(u_int8_t *buffer, u_int8_t packet_type, u_int8_t flags, u_int32_t message_id)
655{
656	((struct necp_packet_header *)(void *)buffer)->packet_type = packet_type;
657	((struct necp_packet_header *)(void *)buffer)->flags = flags;
658	((struct necp_packet_header *)(void *)buffer)->message_id = message_id;
659	return (buffer + sizeof(struct necp_packet_header));
660}
661
662static u_int8_t *
663necp_buffer_write_tlv(u_int8_t *buffer, u_int8_t type, size_t length, const void *value)
664{
665	*(u_int8_t *)(buffer) = type;
666	*(size_t *)(void *)(buffer + sizeof(type)) = length;
667	if (length > 0) {
668		memcpy((u_int8_t *)(buffer + sizeof(type) + sizeof(length)), value, length);
669	}
670
671	return ((u_int8_t *)(buffer + sizeof(type) + sizeof(length) + length));
672}
673
674static u_int8_t
675necp_buffer_get_tlv_type(u_int8_t *buffer, int tlv_offset)
676{
677	u_int8_t *type = NULL;
678
679	if (buffer == NULL) {
680		return (0);
681	}
682
683	type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
684	return (type ? *type : 0);
685}
686
687static size_t
688necp_buffer_get_tlv_length(u_int8_t *buffer, int tlv_offset)
689{
690	size_t *length = NULL;
691
692	if (buffer == NULL) {
693		return (0);
694	}
695
696	length = (size_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
697	return (length ? *length : 0);
698}
699
700static u_int8_t *
701necp_buffer_get_tlv_value(u_int8_t *buffer, int tlv_offset, size_t *value_size)
702{
703	u_int8_t *value = NULL;
704	size_t length = necp_buffer_get_tlv_length(buffer, tlv_offset);
705	if (length == 0) {
706		return (value);
707	}
708
709	if (value_size) {
710		*value_size = length;
711	}
712
713	value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(size_t));
714	return (value);
715}
716
717static int
718necp_buffer_find_tlv(u_int8_t *buffer, size_t buffer_length, int offset, u_int8_t type, int next)
719{
720	size_t cursor = offset;
721	size_t curr_length;
722	u_int8_t curr_type;
723
724	do {
725		if (cursor >= buffer_length) {
726			return (-1);
727		}
728		if (!next) {
729			curr_type = necp_buffer_get_tlv_type(buffer, cursor);
730		} else {
731			next = 0;
732			curr_type = NECP_TLV_NIL;
733		}
734		if (curr_type != type) {
735			curr_length = necp_buffer_get_tlv_length(buffer, cursor);
736			cursor += (sizeof(curr_type) + sizeof(curr_length) + curr_length);
737		}
738	} while (curr_type != type);
739
740	return (cursor);
741}
742
743static bool
744necp_send_ctl_data(struct necp_session *session, u_int8_t *buffer, size_t buffer_size)
745{
746	int		error;
747
748	if (necp_kctlref == NULL || session == NULL || buffer == NULL || buffer_size == 0) {
749		return (FALSE);
750	}
751
752	error = ctl_enqueuedata(necp_kctlref, session->control_unit, buffer, buffer_size, CTL_DATA_EOR);
753
754	return (error == 0);
755}
756
757static bool
758necp_send_success_response(struct necp_session *session, u_int8_t packet_type, u_int32_t message_id)
759{
760	bool success = TRUE;
761	u_int8_t *response = NULL;
762	u_int8_t *cursor = NULL;
763	size_t response_size = sizeof(struct necp_packet_header) + sizeof(u_int8_t) + sizeof(size_t);
764	MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
765	if (response == NULL) {
766		return (FALSE);
767	}
768	cursor = response;
769	cursor = necp_buffer_write_packet_header(cursor, packet_type, NECP_PACKET_FLAGS_RESPONSE, message_id);
770	cursor = necp_buffer_write_tlv(cursor, NECP_TLV_NIL, 0, NULL);
771
772	if (!(success = necp_send_ctl_data(session, (u_int8_t *)response, response_size))) {
773		NECPLOG0(LOG_ERR, "Failed to send response");
774	}
775
776	FREE(response, M_NECP);
777	return (success);
778}
779
780static bool
781necp_send_error_response(struct necp_session *session, u_int8_t packet_type, u_int32_t message_id, u_int32_t error)
782{
783	bool success = TRUE;
784	u_int8_t *response = NULL;
785	u_int8_t *cursor = NULL;
786	size_t response_size = sizeof(struct necp_packet_header) + sizeof(u_int8_t) + sizeof(size_t) + sizeof(u_int32_t);
787	MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
788	if (response == NULL) {
789		return (FALSE);
790	}
791	cursor = response;
792	cursor = necp_buffer_write_packet_header(cursor, packet_type, NECP_PACKET_FLAGS_RESPONSE, message_id);
793	cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ERROR, sizeof(error), &error);
794
795	if (!(success = necp_send_ctl_data(session, (u_int8_t *)response, response_size))) {
796		NECPLOG0(LOG_ERR, "Failed to send response");
797	}
798
799	FREE(response, M_NECP);
800	return (success);
801}
802
803static bool
804necp_send_policy_id_response(struct necp_session *session, u_int8_t packet_type, u_int32_t message_id, necp_policy_id policy_id)
805{
806	bool success = TRUE;
807	u_int8_t *response = NULL;
808	u_int8_t *cursor = NULL;
809	size_t response_size = sizeof(struct necp_packet_header) + sizeof(u_int8_t) + sizeof(size_t) + sizeof(u_int32_t);
810	MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
811	if (response == NULL) {
812		return (FALSE);
813	}
814	cursor = response;
815	cursor = necp_buffer_write_packet_header(cursor, packet_type, NECP_PACKET_FLAGS_RESPONSE, message_id);
816	cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy_id), &policy_id);
817
818	if (!(success = necp_send_ctl_data(session, (u_int8_t *)response, response_size))) {
819		NECPLOG0(LOG_ERR, "Failed to send response");
820	}
821
822	FREE(response, M_NECP);
823	return (success);
824}
825
826static errno_t
827necp_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t packet, int flags)
828{
829#pragma unused(kctlref, unit, flags)
830	struct necp_session *session = (struct necp_session *)unitinfo;
831	struct necp_packet_header header;
832	int error = 0;
833
834	if (session == NULL) {
835		NECPLOG0(LOG_ERR, "Got a NULL session");
836		error = EINVAL;
837		goto done;
838	}
839
840	if (mbuf_pkthdr_len(packet) < sizeof(header)) {
841		NECPLOG(LOG_ERR, "Got a bad packet, length (%lu) < sizeof header (%lu)", mbuf_pkthdr_len(packet), sizeof(header));
842		error = EINVAL;
843		goto done;
844	}
845
846	error = mbuf_copydata(packet, 0, sizeof(header), &header);
847	if (error) {
848		NECPLOG(LOG_ERR, "mbuf_copydata failed for the header: %d", error);
849		error = ENOBUFS;
850		goto done;
851	}
852
853	if (session->proc_locked) {
854		// Verify that the calling process is allowed to send messages
855		uuid_t proc_uuid;
856		proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
857		if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
858			necp_send_error_response(session, header.packet_type, header.message_id, NECP_ERROR_INVALID_PROCESS);
859			goto done;
860		}
861	}
862
863	switch (header.packet_type) {
864		case NECP_PACKET_TYPE_POLICY_ADD: {
865			necp_handle_policy_add(session, header.message_id, packet, sizeof(header));
866			break;
867		}
868		case NECP_PACKET_TYPE_POLICY_GET: {
869			necp_handle_policy_get(session, header.message_id, packet, sizeof(header));
870			break;
871		}
872		case NECP_PACKET_TYPE_POLICY_DELETE: {
873			necp_handle_policy_delete(session, header.message_id, packet, sizeof(header));
874			break;
875		}
876		case NECP_PACKET_TYPE_POLICY_APPLY_ALL: {
877			necp_handle_policy_apply_all(session, header.message_id, packet, sizeof(header));
878			break;
879		}
880		case NECP_PACKET_TYPE_POLICY_LIST_ALL: {
881			necp_handle_policy_list_all(session, header.message_id, packet, sizeof(header));
882			break;
883		}
884		case NECP_PACKET_TYPE_POLICY_DELETE_ALL: {
885			necp_handle_policy_delete_all(session, header.message_id, packet, sizeof(header));
886			break;
887		}
888		case NECP_PACKET_TYPE_SET_SESSION_PRIORITY: {
889			necp_handle_set_session_priority(session, header.message_id, packet, sizeof(header));
890			break;
891		}
892		case NECP_PACKET_TYPE_LOCK_SESSION_TO_PROC: {
893			necp_handle_lock_session_to_proc(session, header.message_id, packet, sizeof(header));
894			break;
895		}
896		case NECP_PACKET_TYPE_REGISTER_SERVICE: {
897			necp_handle_register_service(session, header.message_id, packet, sizeof(header));
898			break;
899		}
900		case NECP_PACKET_TYPE_UNREGISTER_SERVICE: {
901			necp_handle_unregister_service(session, header.message_id, packet, sizeof(header));
902			break;
903		}
904		default: {
905			NECPLOG(LOG_ERR, "Received unknown message type %d", header.packet_type);
906			necp_send_error_response(session, header.packet_type, header.message_id, NECP_ERROR_UNKNOWN_PACKET_TYPE);
907			break;
908		}
909	}
910
911done:
912	mbuf_freem(packet);
913	return (error);
914}
915
916static void
917necp_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags)
918{
919#pragma unused(kctlref, unit, unitinfo, flags)
920	return;
921}
922
923static errno_t
924necp_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t *len)
925{
926#pragma unused(kctlref, unit, unitinfo, opt, data, len)
927	return (0);
928}
929
930static errno_t
931necp_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len)
932{
933#pragma unused(kctlref, unit, unitinfo, opt, data, len)
934	return (0);
935}
936
937// Session Management
938static struct necp_session *
939necp_create_session(u_int32_t control_unit)
940{
941	struct necp_session *new_session = NULL;
942
943	MALLOC(new_session, struct necp_session *, sizeof(*new_session), M_NECP, M_WAITOK);
944	if (new_session == NULL) {
945		goto done;
946	}
947	if (necp_debug) {
948		NECPLOG(LOG_DEBUG, "Create NECP session, control unit %d", control_unit);
949	}
950	memset(new_session, 0, sizeof(*new_session));
951	new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
952	new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
953	new_session->control_unit = control_unit;
954	new_session->dirty = FALSE;
955	LIST_INIT(&new_session->policies);
956
957done:
958	return (new_session);
959}
960
961static void
962necp_delete_session(struct necp_session *session)
963{
964	if (session != NULL) {
965		struct necp_service_registration *service = NULL;
966		struct necp_service_registration *temp_service = NULL;
967		LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
968			LIST_REMOVE(service, session_chain);
969			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
970			LIST_REMOVE(service, kernel_chain);
971			lck_rw_done(&necp_kernel_policy_lock);
972			FREE(service, M_NECP);
973		}
974		if (necp_debug) {
975			NECPLOG0(LOG_DEBUG, "Deleted NECP session");
976		}
977		FREE(session, M_NECP);
978	}
979}
980
981// Session Policy Management
982static inline u_int8_t
983necp_policy_result_get_type_from_buffer(u_int8_t *buffer, size_t length)
984{
985	return ((buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0);
986}
987
988static inline size_t
989necp_policy_result_get_parameter_length_from_buffer(u_int8_t *buffer, size_t length)
990{
991	return ((buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0);
992}
993
994static inline u_int8_t *
995necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t *buffer, size_t length)
996{
997	return ((buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL);
998}
999
1000static bool
1001necp_policy_result_is_valid(u_int8_t *buffer, size_t length)
1002{
1003	bool validated = FALSE;
1004	u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
1005	size_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
1006	switch (type) {
1007		case NECP_POLICY_RESULT_PASS: {
1008			validated = TRUE;
1009			break;
1010		}
1011		case NECP_POLICY_RESULT_SKIP: {
1012			if (parameter_length >= sizeof(u_int32_t)) {
1013				validated = TRUE;
1014			}
1015			break;
1016		}
1017		case NECP_POLICY_RESULT_DROP: {
1018			validated = TRUE;
1019			break;
1020		}
1021		case NECP_POLICY_RESULT_SOCKET_DIVERT: {
1022			if (parameter_length >= sizeof(u_int32_t)) {
1023				validated = TRUE;
1024			}
1025			break;
1026		}
1027		case NECP_POLICY_RESULT_SOCKET_SCOPED: {
1028			if (parameter_length > 0) {
1029				validated = TRUE;
1030			}
1031			break;
1032		}
1033		case NECP_POLICY_RESULT_IP_TUNNEL: {
1034			if (parameter_length > sizeof(u_int32_t)) {
1035				validated = TRUE;
1036			}
1037			break;
1038		}
1039		case NECP_POLICY_RESULT_SOCKET_FILTER: {
1040			if (parameter_length >= sizeof(u_int32_t)) {
1041				validated = TRUE;
1042			}
1043			break;
1044		}
1045		case NECP_POLICY_RESULT_TRIGGER:
1046		case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED:
1047		case NECP_POLICY_RESULT_TRIGGER_SCOPED:
1048		case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED: {
1049			if (parameter_length >= sizeof(uuid_t)) {
1050				validated = TRUE;
1051			}
1052			break;
1053		}
1054		default: {
1055			validated = FALSE;
1056			break;
1057		}
1058	}
1059
1060	if (necp_debug) {
1061		NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
1062	}
1063
1064	return (validated);
1065}
1066
1067static inline u_int8_t
1068necp_policy_condition_get_type_from_buffer(u_int8_t *buffer, size_t length)
1069{
1070	return ((buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0);
1071}
1072
1073static inline u_int8_t
1074necp_policy_condition_get_flags_from_buffer(u_int8_t *buffer, size_t length)
1075{
1076	return ((buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0);
1077}
1078
1079static inline size_t
1080necp_policy_condition_get_value_length_from_buffer(u_int8_t *buffer, size_t length)
1081{
1082	return ((buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0);
1083}
1084
1085static inline u_int8_t *
1086necp_policy_condition_get_value_pointer_from_buffer(u_int8_t *buffer, size_t length)
1087{
1088	return ((buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL);
1089}
1090
1091static inline bool
1092necp_policy_condition_is_default(u_int8_t *buffer, size_t length)
1093{
1094	return (necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT);
1095}
1096
1097static inline bool
1098necp_policy_condition_is_application(u_int8_t *buffer, size_t length)
1099{
1100	return (necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION);
1101}
1102
1103static inline bool
1104necp_policy_condition_requires_application(u_int8_t *buffer, size_t length)
1105{
1106	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
1107	return (type == NECP_POLICY_CONDITION_REAL_APPLICATION ||
1108			type == NECP_POLICY_CONDITION_ENTITLEMENT);
1109}
1110
1111static bool
1112necp_policy_condition_is_valid(u_int8_t *buffer, size_t length, u_int8_t policy_result_type)
1113{
1114	bool validated = FALSE;
1115	bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
1116										policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
1117										policy_result_type == NECP_POLICY_RESULT_TRIGGER ||
1118										policy_result_type == NECP_POLICY_RESULT_TRIGGER_IF_NEEDED ||
1119										policy_result_type == NECP_POLICY_RESULT_TRIGGER_SCOPED ||
1120										policy_result_type == NECP_POLICY_RESULT_NO_TRIGGER_SCOPED ||
1121										policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED) ? TRUE : FALSE;
1122	size_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
1123	u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
1124	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
1125	u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
1126	switch (type) {
1127		case NECP_POLICY_CONDITION_APPLICATION:
1128		case NECP_POLICY_CONDITION_REAL_APPLICATION: {
1129			if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
1130				condition_length >= sizeof(uuid_t) &&
1131				condition_value != NULL &&
1132				!uuid_is_null(condition_value)) {
1133				validated = TRUE;
1134			}
1135			break;
1136		}
1137		case NECP_POLICY_CONDITION_DOMAIN:
1138		case NECP_POLICY_CONDITION_ACCOUNT:
1139		case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
1140			if (condition_length > 0) {
1141				validated = TRUE;
1142			}
1143			break;
1144		}
1145		case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
1146			if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
1147				validated = TRUE;
1148			}
1149			break;
1150		}
1151		case NECP_POLICY_CONDITION_DEFAULT:
1152		case NECP_POLICY_CONDITION_ALL_INTERFACES:
1153		case NECP_POLICY_CONDITION_ENTITLEMENT: {
1154			if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
1155				validated = TRUE;
1156			}
1157			break;
1158		}
1159		case NECP_POLICY_CONDITION_IP_PROTOCOL: {
1160			if (condition_length >= sizeof(u_int16_t)) {
1161				validated = TRUE;
1162			}
1163			break;
1164		}
1165		case NECP_POLICY_CONDITION_PID: {
1166			if (condition_length >= sizeof(pid_t) &&
1167				condition_value != NULL &&
1168				*((pid_t *)(void *)condition_value) != 0) {
1169				validated = TRUE;
1170			}
1171			break;
1172		}
1173		case NECP_POLICY_CONDITION_UID: {
1174			if (condition_length >= sizeof(uid_t)) {
1175				validated = TRUE;
1176			}
1177			break;
1178		}
1179		case NECP_POLICY_CONDITION_LOCAL_ADDR:
1180		case NECP_POLICY_CONDITION_REMOTE_ADDR: {
1181			if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr)) {
1182				validated = TRUE;
1183			}
1184			break;
1185		}
1186		case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
1187		case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
1188			if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range)) {
1189				validated = TRUE;
1190			}
1191			break;
1192		}
1193		default: {
1194			validated = FALSE;
1195			break;
1196		}
1197	}
1198
1199	if (necp_debug) {
1200		NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
1201	}
1202
1203	return (validated);
1204}
1205
1206static void
1207necp_handle_set_session_priority(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1208{
1209	int error;
1210	struct necp_session_policy *policy = NULL;
1211	struct necp_session_policy *temp_policy = NULL;
1212	u_int32_t response_error = NECP_ERROR_INTERNAL;
1213	u_int32_t requested_session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
1214
1215	// Read policy id
1216	error = necp_packet_get_tlv(packet, offset, NECP_TLV_SESSION_PRIORITY, sizeof(requested_session_priority), &requested_session_priority, NULL);
1217	if (error) {
1218		NECPLOG(LOG_ERR, "Failed to get session priority: %d", error);
1219		response_error = NECP_ERROR_INVALID_TLV;
1220		goto fail;
1221	}
1222
1223	if (session == NULL) {
1224		NECPLOG0(LOG_ERR, "Failed to find session");
1225		response_error = NECP_ERROR_INTERNAL;
1226		goto fail;
1227	}
1228
1229	// Enforce special session priorities with entitlements
1230	if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1231		requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL) {
1232		errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1233		if (cred_result != 0) {
1234			NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1235			goto fail;
1236		}
1237	}
1238
1239	if (session->session_priority != requested_session_priority) {
1240		session->session_priority = requested_session_priority;
1241		session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1242		session->dirty = TRUE;
1243
1244		// Mark all policies as needing updates
1245		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1246			policy->pending_update = TRUE;
1247		}
1248	}
1249
1250	necp_send_success_response(session, NECP_PACKET_TYPE_SET_SESSION_PRIORITY, message_id);
1251	return;
1252
1253fail:
1254	necp_send_error_response(session, NECP_PACKET_TYPE_SET_SESSION_PRIORITY, message_id, response_error);
1255}
1256
1257static void
1258necp_handle_lock_session_to_proc(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1259{
1260#pragma unused(packet, offset)
1261	proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1262	session->proc_locked = TRUE;
1263	necp_send_success_response(session, NECP_PACKET_TYPE_LOCK_SESSION_TO_PROC, message_id);
1264}
1265
1266static void
1267necp_handle_register_service(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1268{
1269	int error;
1270	struct necp_service_registration *new_service = NULL;
1271	u_int32_t response_error = NECP_ERROR_INTERNAL;
1272	uuid_t service_uuid;
1273	uuid_clear(service_uuid);
1274
1275	if (session == NULL) {
1276		NECPLOG0(LOG_ERR, "Failed to find session");
1277		response_error = NECP_ERROR_INTERNAL;
1278		goto fail;
1279	}
1280
1281	// Enforce entitlements
1282	errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1283	if (cred_result != 0) {
1284		NECPLOG0(LOG_ERR, "Session does not hold necessary entitlement to register service");
1285		goto fail;
1286	}
1287
1288	// Read service uuid
1289	error = necp_packet_get_tlv(packet, offset, NECP_TLV_SERVICE_UUID, sizeof(uuid_t), service_uuid, NULL);
1290	if (error) {
1291		NECPLOG(LOG_ERR, "Failed to get service UUID: %d", error);
1292		response_error = NECP_ERROR_INVALID_TLV;
1293		goto fail;
1294	}
1295
1296	MALLOC(new_service, struct necp_service_registration *, sizeof(*new_service), M_NECP, M_WAITOK);
1297	if (new_service == NULL) {
1298		NECPLOG0(LOG_ERR, "Failed to allocate service registration");
1299		response_error = NECP_ERROR_INTERNAL;
1300		goto fail;
1301	}
1302
1303	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1304	memset(new_service, 0, sizeof(*new_service));
1305	new_service->service_id = necp_create_uuid_service_id_mapping(service_uuid);
1306	LIST_INSERT_HEAD(&session->services, new_service, session_chain);
1307	LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
1308	lck_rw_done(&necp_kernel_policy_lock);
1309
1310	necp_send_success_response(session, NECP_PACKET_TYPE_REGISTER_SERVICE, message_id);
1311	return;
1312fail:
1313	necp_send_error_response(session, NECP_PACKET_TYPE_REGISTER_SERVICE, message_id, response_error);
1314}
1315
1316static void
1317necp_handle_unregister_service(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1318{
1319	int error;
1320	struct necp_service_registration *service = NULL;
1321	struct necp_service_registration *temp_service = NULL;
1322	u_int32_t response_error = NECP_ERROR_INTERNAL;
1323	struct necp_uuid_id_mapping *mapping = NULL;
1324	uuid_t service_uuid;
1325	uuid_clear(service_uuid);
1326
1327	if (session == NULL) {
1328		NECPLOG0(LOG_ERR, "Failed to find session");
1329		response_error = NECP_ERROR_INTERNAL;
1330		goto fail;
1331	}
1332
1333	// Read service uuid
1334	error = necp_packet_get_tlv(packet, offset, NECP_TLV_SERVICE_UUID, sizeof(uuid_t), service_uuid, NULL);
1335	if (error) {
1336		NECPLOG(LOG_ERR, "Failed to get service UUID: %d", error);
1337		response_error = NECP_ERROR_INVALID_TLV;
1338		goto fail;
1339	}
1340
1341	// Mark remove all matching services for this session
1342	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1343	mapping = necp_uuid_lookup_service_id_locked(service_uuid);
1344	if (mapping != NULL) {
1345		LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1346			if (service->service_id == mapping->id) {
1347				LIST_REMOVE(service, session_chain);
1348				LIST_REMOVE(service, kernel_chain);
1349				FREE(service, M_NECP);
1350			}
1351		}
1352		necp_remove_uuid_service_id_mapping(service_uuid);
1353	}
1354	lck_rw_done(&necp_kernel_policy_lock);
1355
1356	necp_send_success_response(session, NECP_PACKET_TYPE_REGISTER_SERVICE, message_id);
1357	return;
1358fail:
1359	necp_send_error_response(session, NECP_PACKET_TYPE_REGISTER_SERVICE, message_id, response_error);
1360}
1361
1362static void
1363necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1364{
1365	bool has_default_condition = FALSE;
1366	bool has_non_default_condition = FALSE;
1367	bool has_application_condition = FALSE;
1368	bool requires_application_condition = FALSE;
1369	u_int8_t *conditions_array = NULL;
1370	size_t conditions_array_size = 0;
1371	int conditions_array_cursor;
1372
1373	int cursor;
1374	int error = 0;
1375	u_int32_t response_error = NECP_ERROR_INTERNAL;
1376
1377	necp_policy_order order = 0;
1378	struct necp_session_policy *policy = NULL;
1379	u_int8_t *policy_result = NULL;
1380	size_t policy_result_size = 0;
1381
1382	// Read policy order
1383	error = necp_packet_get_tlv(packet, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
1384	if (error) {
1385		NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
1386		response_error = NECP_ERROR_INVALID_TLV;
1387		goto fail;
1388	}
1389
1390	// Read policy result
1391	cursor = necp_packet_find_tlv(packet, offset, NECP_TLV_POLICY_RESULT, &error, 0);
1392	error = necp_packet_get_tlv_at_offset(packet, cursor, 0, NULL, &policy_result_size);
1393	if (error || policy_result_size == 0) {
1394		NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
1395		response_error = NECP_ERROR_INVALID_TLV;
1396		goto fail;
1397	}
1398	MALLOC(policy_result, u_int8_t *, policy_result_size, M_NECP, M_WAITOK);
1399	if (policy_result == NULL) {
1400		NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
1401		response_error = NECP_ERROR_INTERNAL;
1402		goto fail;
1403	}
1404	error = necp_packet_get_tlv_at_offset(packet, cursor, policy_result_size, policy_result, NULL);
1405	if (error) {
1406		NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
1407		response_error = NECP_ERROR_POLICY_RESULT_INVALID;
1408		goto fail;
1409	}
1410	if (!necp_policy_result_is_valid(policy_result, policy_result_size)) {
1411		NECPLOG0(LOG_ERR, "Failed to validate policy result");
1412		response_error = NECP_ERROR_POLICY_RESULT_INVALID;
1413		goto fail;
1414	}
1415
1416	// Read policy conditions
1417	for (cursor = necp_packet_find_tlv(packet, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
1418		cursor >= 0;
1419		cursor = necp_packet_find_tlv(packet, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
1420		size_t condition_size = 0;
1421		necp_packet_get_tlv_at_offset(packet, cursor, 0, NULL, &condition_size);
1422
1423		if (condition_size > 0) {
1424			conditions_array_size += (sizeof(u_int8_t) + sizeof(size_t) + condition_size);
1425		}
1426	}
1427
1428	if (conditions_array_size == 0) {
1429		NECPLOG0(LOG_ERR, "Failed to get policy conditions");
1430		response_error = NECP_ERROR_INVALID_TLV;
1431		goto fail;
1432	}
1433	MALLOC(conditions_array, u_int8_t *, conditions_array_size, M_NECP, M_WAITOK);
1434	if (conditions_array == NULL) {
1435		NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
1436		response_error = NECP_ERROR_INTERNAL;
1437		goto fail;
1438	}
1439
1440	conditions_array_cursor = 0;
1441	for (cursor = necp_packet_find_tlv(packet, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
1442		cursor >= 0;
1443		cursor = necp_packet_find_tlv(packet, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
1444		u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
1445		size_t condition_size = 0;
1446		necp_packet_get_tlv_at_offset(packet, cursor, 0, NULL, &condition_size);
1447		if (condition_size > 0 && condition_size <= (conditions_array_size - conditions_array_cursor)) {
1448			// Add type
1449			memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
1450			conditions_array_cursor += sizeof(condition_type);
1451
1452			// Add length
1453			memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
1454			conditions_array_cursor += sizeof(condition_size);
1455
1456			// Add value
1457			necp_packet_get_tlv_at_offset(packet, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
1458			if (!necp_policy_condition_is_valid((conditions_array + conditions_array_cursor), condition_size, necp_policy_result_get_type_from_buffer(policy_result, policy_result_size))) {
1459				NECPLOG0(LOG_ERR, "Failed to validate policy condition");
1460				response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
1461				goto fail;
1462			}
1463
1464			if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
1465				has_default_condition = TRUE;
1466			} else {
1467				has_non_default_condition = TRUE;
1468			}
1469			if (has_default_condition && has_non_default_condition) {
1470				NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
1471				response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
1472				goto fail;
1473			}
1474
1475			if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
1476				has_application_condition = TRUE;
1477			}
1478
1479			if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
1480				requires_application_condition = TRUE;
1481			}
1482
1483			conditions_array_cursor += condition_size;
1484		}
1485	}
1486
1487	if (requires_application_condition && !has_application_condition) {
1488		NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
1489		response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
1490		goto fail;
1491	}
1492
1493	if ((policy = necp_policy_create(session, order, conditions_array, conditions_array_size, policy_result, policy_result_size)) == NULL) {
1494		response_error = NECP_ERROR_INTERNAL;
1495		goto fail;
1496	}
1497
1498	necp_send_policy_id_response(session, NECP_PACKET_TYPE_POLICY_ADD, message_id, policy->id);
1499	return;
1500
1501fail:
1502	if (policy_result != NULL) {
1503		FREE(policy_result, M_NECP);
1504	}
1505	if (conditions_array != NULL) {
1506		FREE(conditions_array, M_NECP);
1507	}
1508
1509	necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_ADD, message_id, response_error);
1510}
1511
1512static void
1513necp_handle_policy_get(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1514{
1515#pragma unused(offset)
1516	int error;
1517	u_int8_t *response = NULL;
1518	u_int8_t *cursor = NULL;
1519	u_int32_t response_error = NECP_ERROR_INTERNAL;
1520	necp_policy_id policy_id = 0;
1521	size_t order_tlv_size = 0;
1522	size_t result_tlv_size = 0;
1523	size_t response_size = 0;
1524
1525	struct necp_session_policy *policy = NULL;
1526
1527	// Read policy id
1528	error = necp_packet_get_tlv(packet, offset, NECP_TLV_POLICY_ID, sizeof(policy_id), &policy_id, NULL);
1529	if (error) {
1530		NECPLOG(LOG_ERR, "Failed to get policy id: %d", error);
1531		response_error = NECP_ERROR_INVALID_TLV;
1532		goto fail;
1533	}
1534
1535	policy = necp_policy_find(session, policy_id);
1536	if (policy == NULL || policy->pending_deletion) {
1537		NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1538		response_error = NECP_ERROR_POLICY_ID_NOT_FOUND;
1539		goto fail;
1540	}
1541
1542	order_tlv_size = sizeof(u_int8_t) + sizeof(size_t) + sizeof(necp_policy_order);
1543	result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(size_t) + policy->result_size) : 0);
1544	response_size = sizeof(struct necp_packet_header) + order_tlv_size + result_tlv_size + policy->conditions_size;
1545	MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
1546	if (response == NULL) {
1547		necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_LIST_ALL, message_id, NECP_ERROR_INTERNAL);
1548		return;
1549	}
1550
1551	cursor = response;
1552	cursor = necp_buffer_write_packet_header(cursor, NECP_PACKET_TYPE_POLICY_GET, NECP_PACKET_FLAGS_RESPONSE, message_id);
1553	cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order);
1554
1555	if (result_tlv_size) {
1556		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, &policy->result);
1557	}
1558	if (policy->conditions_size) {
1559		memcpy(((u_int8_t *)(void *)(cursor)), policy->conditions, policy->conditions_size);
1560	}
1561
1562	if (!necp_send_ctl_data(session, (u_int8_t *)response, response_size)) {
1563		NECPLOG0(LOG_ERR, "Failed to send response");
1564	}
1565
1566	FREE(response, M_NECP);
1567	return;
1568
1569fail:
1570	necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_GET, message_id, response_error);
1571}
1572
1573static void
1574necp_handle_policy_delete(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1575{
1576	int error;
1577	u_int32_t response_error = NECP_ERROR_INTERNAL;
1578	necp_policy_id policy_id = 0;
1579
1580	struct necp_session_policy *policy = NULL;
1581
1582	// Read policy id
1583	error = necp_packet_get_tlv(packet, offset, NECP_TLV_POLICY_ID, sizeof(policy_id), &policy_id, NULL);
1584	if (error) {
1585		NECPLOG(LOG_ERR, "Failed to get policy id: %d", error);
1586		response_error = NECP_ERROR_INVALID_TLV;
1587		goto fail;
1588	}
1589
1590	policy = necp_policy_find(session, policy_id);
1591	if (policy == NULL || policy->pending_deletion) {
1592		NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1593		response_error = NECP_ERROR_POLICY_ID_NOT_FOUND;
1594		goto fail;
1595	}
1596
1597	necp_policy_mark_for_deletion(session, policy);
1598
1599	necp_send_success_response(session, NECP_PACKET_TYPE_POLICY_DELETE, message_id);
1600	return;
1601
1602fail:
1603	necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_DELETE, message_id, response_error);
1604}
1605
1606static void
1607necp_handle_policy_apply_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1608{
1609#pragma unused(packet, offset)
1610	necp_policy_apply_all(session);
1611	necp_send_success_response(session, NECP_PACKET_TYPE_POLICY_APPLY_ALL, message_id);
1612}
1613
1614static void
1615necp_handle_policy_list_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1616{
1617#pragma unused(packet, offset)
1618	size_t tlv_size = (sizeof(u_int8_t) + sizeof(size_t) + sizeof(u_int32_t));
1619	size_t response_size = 0;
1620	u_int8_t *response = NULL;
1621	u_int8_t *cursor = NULL;
1622	int num_policies = 0;
1623	int cur_policy_index = 0;
1624	struct necp_session_policy *policy;
1625
1626	LIST_FOREACH(policy, &session->policies, chain) {
1627		if (!policy->pending_deletion) {
1628			num_policies++;
1629		}
1630	}
1631
1632	// Create a response with one Policy ID TLV for each policy
1633	response_size = sizeof(struct necp_packet_header) + num_policies * tlv_size;
1634	MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
1635	if (response == NULL) {
1636		necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_LIST_ALL, message_id, NECP_ERROR_INTERNAL);
1637		return;
1638	}
1639
1640	cursor = response;
1641	cursor = necp_buffer_write_packet_header(cursor, NECP_PACKET_TYPE_POLICY_LIST_ALL, NECP_PACKET_FLAGS_RESPONSE, message_id);
1642
1643	LIST_FOREACH(policy, &session->policies, chain) {
1644		if (!policy->pending_deletion && cur_policy_index < num_policies) {
1645			cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->id);
1646			cur_policy_index++;
1647		}
1648	}
1649
1650	if (!necp_send_ctl_data(session, (u_int8_t *)response, response_size)) {
1651		NECPLOG0(LOG_ERR, "Failed to send response");
1652	}
1653
1654	FREE(response, M_NECP);
1655}
1656
1657static void
1658necp_handle_policy_delete_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1659{
1660#pragma unused(packet, offset)
1661	necp_policy_mark_all_for_deletion(session);
1662	necp_send_success_response(session, NECP_PACKET_TYPE_POLICY_DELETE_ALL, message_id);
1663}
1664
1665static necp_policy_id
1666necp_policy_get_new_id(void)
1667{
1668	necp_policy_id newid = 0;
1669
1670	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1671
1672	necp_last_policy_id++;
1673	if (necp_last_policy_id < 1) {
1674		necp_last_policy_id = 1;
1675	}
1676
1677	newid = necp_last_policy_id;
1678	lck_rw_done(&necp_kernel_policy_lock);
1679
1680	if (newid == 0) {
1681		NECPLOG0(LOG_DEBUG, "Allocate policy id failed.\n");
1682		return (0);
1683	}
1684
1685	return (newid);
1686}
1687
1688static struct necp_session_policy *
1689necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t *conditions_array, size_t conditions_array_size, u_int8_t *result, size_t result_size)
1690{
1691	struct necp_session_policy *new_policy = NULL;
1692	struct necp_session_policy *tmp_policy = NULL;
1693
1694	if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
1695		goto done;
1696	}
1697
1698	MALLOC_ZONE(new_policy, struct necp_session_policy *, sizeof(*new_policy), M_NECP_SESSION_POLICY, M_WAITOK);
1699	if (new_policy == NULL) {
1700		goto done;
1701	}
1702
1703	memset(new_policy, 0, sizeof(*new_policy));
1704	new_policy->applied = FALSE;
1705	new_policy->pending_deletion = FALSE;
1706	new_policy->pending_update = FALSE;
1707	new_policy->order = order;
1708	new_policy->conditions = conditions_array;
1709	new_policy->conditions_size = conditions_array_size;
1710	new_policy->result = result;
1711	new_policy->result_size = result_size;
1712	new_policy->id = necp_policy_get_new_id();
1713
1714	LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
1715
1716	session->dirty = TRUE;
1717
1718	if (necp_debug) {
1719		NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
1720	}
1721done:
1722	return (new_policy);
1723}
1724
1725static struct necp_session_policy *
1726necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
1727{
1728	struct necp_session_policy *policy = NULL;
1729	if (policy_id == 0) {
1730		return (NULL);
1731	}
1732
1733	LIST_FOREACH(policy, &session->policies, chain) {
1734		if (policy->id == policy_id) {
1735			return (policy);
1736		}
1737	}
1738
1739	return (NULL);
1740}
1741
1742static inline u_int8_t
1743necp_policy_get_result_type(struct necp_session_policy *policy)
1744{
1745	return (policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0);
1746}
1747
1748static inline size_t
1749necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
1750{
1751	return (policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0);
1752}
1753
1754static bool
1755necp_policy_get_result_parameter(struct necp_session_policy *policy, u_int8_t *parameter_buffer, size_t parameter_buffer_length)
1756{
1757	if (policy) {
1758		size_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
1759		if (parameter_buffer_length >= parameter_length) {
1760			u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
1761			if (parameter && parameter_buffer) {
1762				memcpy(parameter_buffer, parameter, parameter_length);
1763				return (TRUE);
1764			}
1765		}
1766	}
1767
1768	return (FALSE);
1769}
1770
1771static bool
1772necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
1773{
1774	if (session == NULL || policy == NULL) {
1775		return (FALSE);
1776	}
1777
1778	policy->pending_deletion = TRUE;
1779	session->dirty = TRUE;
1780
1781	if (necp_debug) {
1782		NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
1783	}
1784	return (TRUE);
1785}
1786
1787static bool
1788necp_policy_mark_all_for_deletion(struct necp_session *session)
1789{
1790	struct necp_session_policy *policy = NULL;
1791	struct necp_session_policy *temp_policy = NULL;
1792
1793	LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1794		necp_policy_mark_for_deletion(session, policy);
1795	}
1796
1797	return (TRUE);
1798}
1799
1800static bool
1801necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
1802{
1803	if (session == NULL || policy == NULL) {
1804		return (FALSE);
1805	}
1806
1807	LIST_REMOVE(policy, chain);
1808
1809	if (policy->result) {
1810		FREE(policy->result, M_NECP);
1811		policy->result = NULL;
1812	}
1813
1814	if (policy->conditions) {
1815		FREE(policy->conditions, M_NECP);
1816		policy->conditions = NULL;
1817	}
1818
1819	FREE_ZONE(policy, sizeof(*policy), M_NECP_SESSION_POLICY);
1820
1821	if (necp_debug) {
1822		NECPLOG0(LOG_DEBUG, "Removed NECP policy");
1823	}
1824	return (TRUE);
1825}
1826
1827static bool
1828necp_policy_unapply(struct necp_session_policy *policy)
1829{
1830	int i = 0;
1831	if (policy == NULL) {
1832		return (FALSE);
1833	}
1834
1835	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
1836
1837	// Release local uuid mappings
1838	if (!uuid_is_null(policy->applied_app_uuid)) {
1839		bool removed_mapping = FALSE;
1840		if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
1841			necp_uuid_app_id_mappings_dirty = TRUE;
1842			necp_num_uuid_app_id_mappings--;
1843		}
1844		uuid_clear(policy->applied_app_uuid);
1845	}
1846	if (!uuid_is_null(policy->applied_real_app_uuid)) {
1847		necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
1848		uuid_clear(policy->applied_real_app_uuid);
1849	}
1850	if (!uuid_is_null(policy->applied_service_uuid)) {
1851		necp_remove_uuid_service_id_mapping(policy->applied_service_uuid);
1852		uuid_clear(policy->applied_service_uuid);
1853	}
1854
1855	// Release string mappings
1856	if (policy->applied_account != NULL) {
1857		necp_remove_string_to_id_mapping(&necp_account_id_list, policy->applied_account);
1858		FREE(policy->applied_account, M_NECP);
1859		policy->applied_account = NULL;
1860	}
1861
1862	// Remove socket policies
1863	for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
1864		if (policy->kernel_socket_policies[i] != 0) {
1865			necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
1866			policy->kernel_socket_policies[i] = 0;
1867		}
1868	}
1869
1870	// Remove IP output policies
1871	for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
1872		if (policy->kernel_ip_output_policies[i] != 0) {
1873			necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
1874			policy->kernel_ip_output_policies[i] = 0;
1875		}
1876	}
1877
1878	policy->applied = FALSE;
1879
1880	return (TRUE);
1881}
1882
1883#define	NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION			0
1884#define	NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION		1
1885#define	NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION				2
1886#define	NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS			3
1887struct necp_policy_result_ip_tunnel {
1888	u_int32_t secondary_result;
1889	char interface_name[IFXNAMSIZ];
1890} __attribute__((__packed__));
1891
1892struct necp_policy_result_service {
1893	uuid_t identifier;
1894	u_int32_t data;
1895} __attribute__((__packed__));
1896
1897static bool
1898necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
1899{
1900	bool socket_only_conditions = FALSE;
1901	bool socket_ip_conditions = FALSE;
1902
1903	bool socket_layer_non_id_conditions = FALSE;
1904	bool ip_output_layer_non_id_conditions = FALSE;
1905	bool ip_output_layer_id_condition = FALSE;
1906	bool ip_output_layer_tunnel_condition_from_id = FALSE;
1907	bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
1908	necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
1909
1910	u_int32_t master_condition_mask = 0;
1911	u_int32_t master_condition_negated_mask = 0;
1912	ifnet_t cond_bound_interface = NULL;
1913	u_int32_t cond_account_id = 0;
1914	char *cond_domain = NULL;
1915	pid_t cond_pid = 0;
1916	uid_t cond_uid = 0;
1917	necp_app_id cond_app_id = 0;
1918	necp_app_id cond_real_app_id = 0;
1919	struct necp_policy_condition_tc_range cond_traffic_class;
1920	cond_traffic_class.start_tc = 0;
1921	cond_traffic_class.end_tc = 0;
1922	u_int16_t cond_protocol = 0;
1923	union necp_sockaddr_union cond_local_start;
1924	union necp_sockaddr_union cond_local_end;
1925	u_int8_t cond_local_prefix = 0;
1926	union necp_sockaddr_union cond_remote_start;
1927	union necp_sockaddr_union cond_remote_end;
1928	u_int8_t cond_remote_prefix = 0;
1929	size_t offset = 0;
1930	u_int8_t ultimate_result = 0;
1931	u_int32_t secondary_result = 0;
1932	necp_kernel_policy_result_parameter secondary_result_parameter;
1933	memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
1934	u_int32_t cond_last_interface_index = 0;
1935	necp_kernel_policy_result_parameter ultimate_result_parameter;
1936	memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
1937
1938	if (policy == NULL) {
1939		return (FALSE);
1940	}
1941
1942	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
1943
1944	// Process conditions
1945	while (offset < policy->conditions_size) {
1946		size_t length = 0;
1947		u_int8_t *value = necp_buffer_get_tlv_value(policy->conditions, offset, &length);
1948
1949		u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
1950		u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
1951		bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
1952		size_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
1953		u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
1954		switch (condition_type) {
1955			case NECP_POLICY_CONDITION_DEFAULT: {
1956				socket_ip_conditions = TRUE;
1957				break;
1958			}
1959			case NECP_POLICY_CONDITION_ALL_INTERFACES: {
1960				master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
1961				socket_ip_conditions = TRUE;
1962				break;
1963			}
1964			case NECP_POLICY_CONDITION_ENTITLEMENT: {
1965				master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
1966				socket_only_conditions = TRUE;
1967				break;
1968			}
1969			case NECP_POLICY_CONDITION_DOMAIN: {
1970				// Make sure there is only one such rule
1971				if (condition_length > 0 && cond_domain == NULL) {
1972					cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
1973					if (cond_domain != NULL) {
1974						master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN;
1975						if (condition_is_negative) {
1976							master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN;
1977						}
1978						socket_only_conditions = TRUE;
1979					}
1980				}
1981				break;
1982			}
1983			case NECP_POLICY_CONDITION_ACCOUNT: {
1984				// Make sure there is only one such rule
1985				if (condition_length > 0 && cond_account_id == 0 && policy->applied_account == NULL) {
1986					char *string = NULL;
1987					MALLOC(string, char *, condition_length + 1, M_NECP, M_WAITOK);
1988					if (string != NULL) {
1989						memcpy(string, condition_value, condition_length);
1990						string[condition_length] = 0;
1991						cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, string);
1992						if (cond_account_id != 0) {
1993							policy->applied_account = string; // Save the string in parent policy
1994							master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
1995							if (condition_is_negative) {
1996								master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
1997							}
1998							socket_only_conditions = TRUE;
1999						} else {
2000							FREE(string, M_NECP);
2001						}
2002					}
2003				}
2004				break;
2005			}
2006			case NECP_POLICY_CONDITION_APPLICATION: {
2007				// Make sure there is only one such rule, because we save the uuid in the policy
2008				if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
2009					bool allocated_mapping = FALSE;
2010					uuid_t application_uuid;
2011					memcpy(application_uuid, condition_value, sizeof(uuid_t));
2012					cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
2013					if (cond_app_id != 0) {
2014						if (allocated_mapping) {
2015							necp_uuid_app_id_mappings_dirty = TRUE;
2016							necp_num_uuid_app_id_mappings++;
2017						}
2018						uuid_copy(policy->applied_app_uuid, application_uuid);
2019						master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
2020						if (condition_is_negative) {
2021							master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
2022						}
2023						socket_only_conditions = TRUE;
2024					}
2025				}
2026				break;
2027			}
2028			case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2029				// Make sure there is only one such rule, because we save the uuid in the policy
2030				if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
2031					uuid_t real_application_uuid;
2032					memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
2033					cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
2034					if (cond_real_app_id != 0) {
2035						uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
2036						master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
2037						if (condition_is_negative) {
2038							master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
2039						}
2040						socket_only_conditions = TRUE;
2041					}
2042				}
2043				break;
2044			}
2045			case NECP_POLICY_CONDITION_PID: {
2046				if (condition_length >= sizeof(pid_t)) {
2047					master_condition_mask |= NECP_KERNEL_CONDITION_PID;
2048					if (condition_is_negative) {
2049						master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
2050					}
2051					memcpy(&cond_pid, condition_value, sizeof(cond_pid));
2052					socket_only_conditions = TRUE;
2053				}
2054				break;
2055			}
2056			case NECP_POLICY_CONDITION_UID: {
2057				if (condition_length >= sizeof(uid_t)) {
2058					master_condition_mask |= NECP_KERNEL_CONDITION_UID;
2059					if (condition_is_negative) {
2060						master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
2061					}
2062					memcpy(&cond_uid, condition_value, sizeof(cond_uid));
2063					socket_only_conditions = TRUE;
2064				}
2065				break;
2066			}
2067			case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2068				if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2069					master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
2070					if (condition_is_negative) {
2071						master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
2072					}
2073					memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
2074					socket_only_conditions = TRUE;
2075				}
2076				break;
2077			}
2078			case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
2079				if (condition_length <= IFXNAMSIZ && condition_length > 0) {
2080					char interface_name[IFXNAMSIZ];
2081					memcpy(interface_name, condition_value, condition_length);
2082					interface_name[condition_length - 1] = 0; // Make sure the string is NULL terminated
2083					if (ifnet_find_by_name(interface_name, &cond_bound_interface) == 0) {
2084						master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
2085						if (condition_is_negative) {
2086							master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
2087						}
2088					}
2089					socket_ip_conditions = TRUE;
2090				}
2091				break;
2092			}
2093			case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2094				if (condition_length >= sizeof(u_int16_t)) {
2095					master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
2096					if (condition_is_negative) {
2097						master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
2098					}
2099					memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
2100					socket_ip_conditions = TRUE;
2101				}
2102				break;
2103			}
2104			case NECP_POLICY_CONDITION_LOCAL_ADDR: {
2105				struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
2106				cond_local_prefix = address_struct->prefix;
2107				memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
2108				master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
2109				master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
2110				if (condition_is_negative) {
2111					master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
2112					master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
2113				}
2114				socket_ip_conditions = TRUE;
2115				break;
2116			}
2117			case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2118				struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
2119				cond_remote_prefix = address_struct->prefix;
2120				memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
2121				master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
2122				master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
2123				if (condition_is_negative) {
2124					master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
2125					master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
2126				}
2127				socket_ip_conditions = TRUE;
2128				break;
2129			}
2130			case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE: {
2131				struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
2132				memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
2133				memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
2134				master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
2135				master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
2136				if (condition_is_negative) {
2137					master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
2138					master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
2139				}
2140				socket_ip_conditions = TRUE;
2141				break;
2142			}
2143			case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2144				struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
2145				memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
2146				memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
2147				master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
2148				master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
2149				if (condition_is_negative) {
2150					master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
2151					master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
2152				}
2153				socket_ip_conditions = TRUE;
2154				break;
2155			}
2156			default: {
2157				break;
2158			}
2159		}
2160
2161		offset += sizeof(u_int8_t) + sizeof(size_t) + length;
2162	}
2163
2164	// Process result
2165	ultimate_result = necp_policy_get_result_type(policy);
2166	switch (ultimate_result) {
2167		case NECP_POLICY_RESULT_PASS: {
2168			if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
2169				socket_layer_non_id_conditions = TRUE;
2170				ip_output_layer_id_condition = TRUE;
2171			} else if (socket_ip_conditions) {
2172				socket_layer_non_id_conditions = TRUE;
2173				ip_output_layer_id_condition = TRUE;
2174				ip_output_layer_non_id_conditions = TRUE;
2175			}
2176			break;
2177		}
2178		case NECP_POLICY_RESULT_DROP: {
2179			if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
2180				socket_layer_non_id_conditions = TRUE;
2181			} else if (socket_ip_conditions) {
2182				socket_layer_non_id_conditions = TRUE;
2183				ip_output_layer_non_id_conditions = TRUE;
2184			}
2185			break;
2186		}
2187		case NECP_POLICY_RESULT_SKIP: {
2188			u_int32_t skip_policy_order = 0;
2189			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
2190				ultimate_result_parameter.skip_policy_order = skip_policy_order;
2191			}
2192
2193			if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
2194				socket_layer_non_id_conditions = TRUE;
2195				ip_output_layer_id_condition = TRUE;
2196			} else if (socket_ip_conditions) {
2197				socket_layer_non_id_conditions = TRUE;
2198				ip_output_layer_non_id_conditions = TRUE;
2199			}
2200			break;
2201		}
2202		case NECP_POLICY_RESULT_SOCKET_DIVERT:
2203		case NECP_POLICY_RESULT_SOCKET_FILTER: {
2204			u_int32_t control_unit = 0;
2205			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
2206				ultimate_result_parameter.flow_divert_control_unit = control_unit;
2207			}
2208			socket_layer_non_id_conditions = TRUE;
2209			break;
2210		}
2211		case NECP_POLICY_RESULT_IP_TUNNEL: {
2212			struct necp_policy_result_ip_tunnel tunnel_parameters;
2213			size_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
2214			if (tunnel_parameters_length > sizeof(u_int32_t) &&
2215				tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
2216				necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
2217				ifnet_t tunnel_interface = NULL;
2218				tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0; // Make sure the string is NULL terminated
2219				if (ifnet_find_by_name(tunnel_parameters.interface_name, &tunnel_interface) == 0) {
2220					ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
2221				}
2222
2223				secondary_result = tunnel_parameters.secondary_result;
2224				if (secondary_result) {
2225					cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
2226				}
2227			}
2228
2229			if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
2230				socket_layer_non_id_conditions = TRUE;
2231				ip_output_layer_id_condition = TRUE;
2232				if (secondary_result) {
2233					ip_output_layer_tunnel_condition_from_id = TRUE;
2234				}
2235			} else if (socket_ip_conditions) {
2236				socket_layer_non_id_conditions = TRUE;
2237				ip_output_layer_id_condition = TRUE;
2238				ip_output_layer_non_id_conditions = TRUE;
2239				if (secondary_result) {
2240					ip_output_layer_tunnel_condition_from_id = TRUE;
2241					ip_output_layer_tunnel_condition_from_non_id = TRUE;
2242				}
2243			}
2244			break;
2245		}
2246		case NECP_POLICY_RESULT_TRIGGER:
2247		case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED:
2248		case NECP_POLICY_RESULT_TRIGGER_SCOPED:
2249		case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED: {
2250			struct necp_policy_result_service service_parameters;
2251			size_t service_result_length = necp_policy_get_result_parameter_length(policy);
2252			bool has_extra_service_data = FALSE;
2253			if (service_result_length >= (sizeof(service_parameters))) {
2254				has_extra_service_data = TRUE;
2255			}
2256			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&service_parameters, sizeof(service_parameters))) {
2257				ultimate_result_parameter.service.identifier = necp_create_uuid_service_id_mapping(service_parameters.identifier);
2258				if (ultimate_result_parameter.service.identifier != 0) {
2259					uuid_copy(policy->applied_service_uuid, service_parameters.identifier);
2260					socket_layer_non_id_conditions = TRUE;
2261					if (has_extra_service_data) {
2262						ultimate_result_parameter.service.data = service_parameters.data;
2263					} else {
2264						ultimate_result_parameter.service.data = 0;
2265					}
2266				}
2267			}
2268			break;
2269		}
2270		case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2271			size_t interface_name_length = necp_policy_get_result_parameter_length(policy);
2272			if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
2273				char interface_name[IFXNAMSIZ];
2274				ifnet_t scope_interface = NULL;
2275				necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
2276				interface_name[interface_name_length - 1] = 0; // Make sure the string is NULL terminated
2277				if (ifnet_find_by_name(interface_name, &scope_interface) == 0) {
2278					ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
2279					socket_layer_non_id_conditions = TRUE;
2280				}
2281			}
2282		}
2283		default: {
2284			break;
2285		}
2286	}
2287
2288	if (socket_layer_non_id_conditions) {
2289		necp_kernel_policy_id policy_id = necp_kernel_socket_policy_add(policy->id, policy->order, session->session_order, master_condition_mask, master_condition_negated_mask, cond_app_id, cond_real_app_id, cond_account_id, cond_domain, cond_pid, cond_uid, cond_bound_interface, cond_traffic_class, cond_protocol, &cond_local_start, &cond_local_end, cond_local_prefix, &cond_remote_start, &cond_remote_end, cond_remote_prefix, ultimate_result, ultimate_result_parameter);
2290
2291		if (policy_id == 0) {
2292			NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
2293			goto fail;
2294		}
2295
2296		cond_ip_output_layer_id = policy_id;
2297		policy->kernel_socket_policies[0] = policy_id;
2298	}
2299
2300	if (ip_output_layer_non_id_conditions) {
2301		necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->id, policy->order, NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS, session->session_order, master_condition_mask, master_condition_negated_mask, NECP_KERNEL_POLICY_ID_NONE, cond_bound_interface, 0, cond_protocol, &cond_local_start, &cond_local_end, cond_local_prefix, &cond_remote_start, &cond_remote_end, cond_remote_prefix, ultimate_result, ultimate_result_parameter);
2302
2303		if (policy_id == 0) {
2304			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
2305			goto fail;
2306		}
2307
2308		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
2309	}
2310
2311	if (ip_output_layer_id_condition) {
2312		necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->id, policy->order, NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION, session->session_order, NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_ALL_INTERFACES, 0, cond_ip_output_layer_id, NULL, 0, 0, NULL, NULL, 0, NULL, NULL, 0, ultimate_result, ultimate_result_parameter);
2313
2314		if (policy_id == 0) {
2315			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
2316			goto fail;
2317		}
2318
2319		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
2320	}
2321
2322	// Extra policies for IP Output tunnels for when packets loop back
2323	if (ip_output_layer_tunnel_condition_from_id) {
2324		necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->id, policy->order, NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION, session->session_order, NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_LAST_INTERFACE | NECP_KERNEL_CONDITION_ALL_INTERFACES, 0, policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS], NULL, cond_last_interface_index, 0, NULL, NULL, 0, NULL, NULL, 0, secondary_result, secondary_result_parameter);
2325
2326		if (policy_id == 0) {
2327			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
2328			goto fail;
2329		}
2330
2331		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
2332	}
2333
2334	if (ip_output_layer_tunnel_condition_from_id) {
2335		necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->id, policy->order, NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION, session->session_order, NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_LAST_INTERFACE | NECP_KERNEL_CONDITION_ALL_INTERFACES, 0, policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION], NULL, cond_last_interface_index, 0, NULL, NULL, 0, NULL, NULL, 0, secondary_result, secondary_result_parameter);
2336
2337		if (policy_id == 0) {
2338			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
2339			goto fail;
2340		}
2341
2342		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
2343	}
2344
2345	policy->applied = TRUE;
2346	policy->pending_update = FALSE;
2347	return (TRUE);
2348
2349fail:
2350	return (FALSE);
2351}
2352
2353static void
2354necp_policy_apply_all(struct necp_session *session)
2355{
2356	struct necp_session_policy *policy = NULL;
2357	struct necp_session_policy *temp_policy = NULL;
2358
2359	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2360
2361	// Remove exisiting applied policies
2362	if (session->dirty) {
2363		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
2364			if (policy->pending_deletion) {
2365				if (policy->applied) {
2366					necp_policy_unapply(policy);
2367				}
2368				// Delete the policy
2369				necp_policy_delete(session, policy);
2370			} else if (!policy->applied) {
2371				necp_policy_apply(session, policy);
2372			} else if (policy->pending_update) {
2373				// Must have been applied, but needs an update. Remove and re-add.
2374				necp_policy_unapply(policy);
2375				necp_policy_apply(session, policy);
2376			}
2377		}
2378
2379		necp_kernel_socket_policies_update_uuid_table();
2380		necp_kernel_socket_policies_reprocess();
2381		necp_kernel_ip_output_policies_reprocess();
2382
2383		// Clear dirty bit flags
2384		session->dirty = FALSE;
2385	}
2386
2387	lck_rw_done(&necp_kernel_policy_lock);
2388
2389	if (necp_debug) {
2390		NECPLOG0(LOG_DEBUG, "Applied NECP policies");
2391	}
2392}
2393
2394// Kernel Policy Management
2395// ---------------------
2396// Kernel policies are derived from session policies
2397static necp_kernel_policy_id
2398necp_kernel_policy_get_new_id(void)
2399{
2400	necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
2401
2402	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
2403
2404	necp_last_kernel_policy_id++;
2405	if (necp_last_kernel_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID) {
2406		necp_last_kernel_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID;
2407	}
2408
2409	newid = necp_last_kernel_policy_id;
2410	if (newid == NECP_KERNEL_POLICY_ID_NONE) {
2411		NECPLOG0(LOG_DEBUG, "Allocate kernel policy id failed.\n");
2412		return (0);
2413	}
2414
2415	return (newid);
2416}
2417
2418#define	NECP_KERNEL_VALID_SOCKET_CONDITIONS (NECP_KERNEL_CONDITION_APP_ID | NECP_KERNEL_CONDITION_REAL_APP_ID | NECP_KERNEL_CONDITION_DOMAIN | NECP_KERNEL_CONDITION_ACCOUNT_ID | NECP_KERNEL_CONDITION_PID | NECP_KERNEL_CONDITION_UID | NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_TRAFFIC_CLASS | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_ENTITLEMENT)
2419static necp_kernel_policy_id
2420necp_kernel_socket_policy_add(necp_policy_id parent_policy_id, necp_policy_order order, u_int32_t session_order, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, u_int32_t cond_account_id, char *cond_domain, pid_t cond_pid, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
2421{
2422	struct necp_kernel_socket_policy *new_kernel_policy = NULL;
2423	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
2424
2425	MALLOC_ZONE(new_kernel_policy, struct necp_kernel_socket_policy *, sizeof(*new_kernel_policy), M_NECP_SOCKET_POLICY, M_WAITOK);
2426	if (new_kernel_policy == NULL) {
2427		goto done;
2428	}
2429
2430	memset(new_kernel_policy, 0, sizeof(*new_kernel_policy));
2431	new_kernel_policy->parent_policy_id = parent_policy_id;
2432	new_kernel_policy->id = necp_kernel_policy_get_new_id();
2433	new_kernel_policy->order = order;
2434	new_kernel_policy->session_order = session_order;
2435
2436	// Sanitize condition mask
2437	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
2438	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
2439		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
2440	}
2441	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
2442		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
2443	}
2444	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
2445		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_ENTITLEMENT;
2446	}
2447	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
2448		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
2449	}
2450	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
2451		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
2452	}
2453	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
2454
2455	// Set condition values
2456	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
2457		new_kernel_policy->cond_app_id = cond_app_id;
2458	}
2459	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
2460		new_kernel_policy->cond_real_app_id = cond_real_app_id;
2461	}
2462	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
2463		new_kernel_policy->cond_account_id = cond_account_id;
2464	}
2465	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
2466		new_kernel_policy->cond_domain = cond_domain;
2467		new_kernel_policy->cond_domain_dot_count = necp_count_dots(cond_domain, strlen(cond_domain));
2468	}
2469	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
2470		new_kernel_policy->cond_pid = cond_pid;
2471	}
2472	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
2473		new_kernel_policy->cond_uid = cond_uid;
2474	}
2475	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
2476		if (cond_bound_interface) {
2477			ifnet_reference(cond_bound_interface);
2478		}
2479		new_kernel_policy->cond_bound_interface = cond_bound_interface;
2480	}
2481	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
2482		new_kernel_policy->cond_traffic_class = cond_traffic_class;
2483	}
2484	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
2485		new_kernel_policy->cond_protocol = cond_protocol;
2486	}
2487	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
2488		memcpy(&new_kernel_policy->cond_local_start, cond_local_start, cond_local_start->sa.sa_len);
2489	}
2490	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
2491		memcpy(&new_kernel_policy->cond_local_end, cond_local_end, cond_local_end->sa.sa_len);
2492	}
2493	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
2494		new_kernel_policy->cond_local_prefix = cond_local_prefix;
2495	}
2496	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
2497		memcpy(&new_kernel_policy->cond_remote_start, cond_remote_start, cond_remote_start->sa.sa_len);
2498	}
2499	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
2500		memcpy(&new_kernel_policy->cond_remote_end, cond_remote_end, cond_remote_end->sa.sa_len);
2501	}
2502	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
2503		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
2504	}
2505
2506	new_kernel_policy->result = result;
2507	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
2508
2509	if (necp_debug) {
2510		NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%x\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
2511	}
2512	LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
2513done:
2514	return (new_kernel_policy ? new_kernel_policy->id : 0);
2515}
2516
2517static struct necp_kernel_socket_policy *
2518necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
2519{
2520	struct necp_kernel_socket_policy *kernel_policy = NULL;
2521	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
2522
2523	if (policy_id == 0) {
2524		return (NULL);
2525	}
2526
2527	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
2528		if (kernel_policy->id == policy_id) {
2529			return (kernel_policy);
2530		}
2531	}
2532
2533	return (NULL);
2534}
2535
2536static bool
2537necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
2538{
2539	struct necp_kernel_socket_policy *policy = NULL;
2540
2541	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
2542
2543	policy = necp_kernel_socket_policy_find(policy_id);
2544	if (policy) {
2545		LIST_REMOVE(policy, chain);
2546
2547		if (policy->cond_bound_interface) {
2548			ifnet_release(policy->cond_bound_interface);
2549			policy->cond_bound_interface = NULL;
2550		}
2551
2552		if (policy->cond_domain) {
2553			FREE(policy->cond_domain, M_NECP);
2554			policy->cond_domain = NULL;
2555		}
2556
2557		FREE_ZONE(policy, sizeof(*policy), M_NECP_SOCKET_POLICY);
2558		return (TRUE);
2559	}
2560
2561	return (FALSE);
2562}
2563
2564static void
2565necp_kernel_socket_policies_dump_all(void)
2566{
2567	struct necp_kernel_socket_policy *policy = NULL;
2568	int policy_i;
2569	int app_i;
2570
2571	if (necp_debug) {
2572		NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
2573		NECPLOG0(LOG_DEBUG, "-----------\n");
2574		for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
2575			policy = necp_kernel_socket_policies_app_layer_map[policy_i];
2576			NECPLOG(LOG_DEBUG, "\t%d. Policy ID: %d, Order: %d.%d, Mask: %x, Result: %d, Parameter: %d\n", policy_i, policy->id, policy->session_order, policy->order, policy->condition_mask, policy->result, policy->result_parameter);
2577		}
2578		if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
2579			NECPLOG0(LOG_DEBUG, "-----------\n");
2580		}
2581
2582		NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
2583		NECPLOG0(LOG_DEBUG, "-----------\n");
2584		for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
2585			NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
2586			for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
2587				policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
2588				NECPLOG(LOG_DEBUG, "\t%d. Policy ID: %d, Order: %d.%d, Mask: %x, Result: %d, Parameter: %d\n", policy_i, policy->id, policy->session_order, policy->order, policy->condition_mask, policy->result, policy->result_parameter);
2589			}
2590			NECPLOG0(LOG_DEBUG, "-----------\n");
2591		}
2592	}
2593}
2594
2595static inline bool
2596necp_kernel_socket_result_is_service_type(struct necp_kernel_socket_policy *kernel_policy)
2597{
2598	return (kernel_policy->result >= NECP_KERNEL_POLICY_RESULT_TRIGGER && kernel_policy->result <= NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED);
2599}
2600
2601static inline bool
2602necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
2603{
2604	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
2605		// Drop always cancels out lower policies
2606		return (TRUE);
2607	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
2608		// Filters never cancel out lower policies
2609		return (FALSE);
2610	} else if (necp_kernel_socket_result_is_service_type(upper_policy)) {
2611		// Trigger/Scoping policies can overlap one another, but not other results
2612		return (necp_kernel_socket_result_is_service_type(lower_policy));
2613	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
2614		if (upper_policy->session_order != lower_policy->session_order) {
2615			// A skip cannot override a policy of a different session
2616			return (FALSE);
2617		} else {
2618			if (upper_policy->result_parameter.skip_policy_order == 0 ||
2619				lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
2620				// This policy is beyond the skip
2621				return (FALSE);
2622			} else {
2623				// This policy is inside the skip
2624				return (TRUE);
2625			}
2626		}
2627	}
2628
2629	// A hard pass, flow divert, or tunnel will currently block out lower policies
2630	return (TRUE);
2631}
2632
2633static bool
2634necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy **policy_array, int valid_indices)
2635{
2636	bool can_skip = FALSE;
2637	u_int32_t highest_skip_session_order = 0;
2638	u_int32_t highest_skip_order = 0;
2639	int i;
2640	for (i = 0; i < valid_indices; i++) {
2641		struct necp_kernel_socket_policy *compared_policy = policy_array[i];
2642
2643		// For policies in a skip window, we can't mark conflicting policies as unnecessary
2644		if (can_skip) {
2645			if (highest_skip_session_order != compared_policy->session_order ||
2646				(highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
2647				// If we've moved on to the next session, or passed the skip window
2648				highest_skip_session_order = 0;
2649				highest_skip_order = 0;
2650				can_skip = FALSE;
2651			} else {
2652				// If this policy is also a skip, in can increase the skip window
2653				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
2654					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
2655						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
2656					}
2657				}
2658				continue;
2659			}
2660		}
2661
2662		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
2663			// This policy is a skip. Set the skip window accordingly
2664			can_skip = TRUE;
2665			highest_skip_session_order = compared_policy->session_order;
2666			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
2667		}
2668
2669		// The result of the compared policy must be able to block out this policy result
2670		if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
2671			continue;
2672		}
2673
2674		// If new policy matches All Interfaces, compared policy must also
2675		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
2676			continue;
2677		}
2678
2679		// Default makes lower policies unecessary always
2680		if (compared_policy->condition_mask == 0) {
2681			return (TRUE);
2682		}
2683
2684		// Compared must be more general than policy, and include only conditions within policy
2685		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
2686			continue;
2687		}
2688
2689		// Negative conditions must match for the overlapping conditions
2690		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
2691			continue;
2692		}
2693
2694		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN &&
2695			strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
2696			continue;
2697		}
2698
2699		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
2700			compared_policy->cond_account_id != policy->cond_account_id) {
2701			continue;
2702		}
2703
2704		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
2705			compared_policy->cond_policy_id != policy->cond_policy_id) {
2706			continue;
2707		}
2708
2709		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
2710			compared_policy->cond_app_id != policy->cond_app_id) {
2711			continue;
2712		}
2713
2714		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
2715			compared_policy->cond_real_app_id != policy->cond_real_app_id) {
2716			continue;
2717		}
2718
2719		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
2720			compared_policy->cond_pid != policy->cond_pid) {
2721			continue;
2722		}
2723
2724		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
2725			compared_policy->cond_uid != policy->cond_uid) {
2726			continue;
2727		}
2728
2729		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
2730			compared_policy->cond_bound_interface != policy->cond_bound_interface) {
2731			continue;
2732		}
2733
2734		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
2735			compared_policy->cond_protocol != policy->cond_protocol) {
2736			continue;
2737		}
2738
2739		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
2740			!(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
2741			  compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
2742			continue;
2743		}
2744
2745		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
2746			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
2747				if (!necp_is_range_in_range((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&policy->cond_local_end, (struct sockaddr *)&compared_policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_end)) {
2748					continue;
2749				}
2750			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
2751				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
2752					!necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_start, compared_policy->cond_local_prefix)) {
2753					continue;
2754				}
2755			}
2756		}
2757
2758		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
2759			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
2760				if (!necp_is_range_in_range((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&policy->cond_remote_end, (struct sockaddr *)&compared_policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_end)) {
2761					continue;
2762				}
2763			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
2764				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
2765					!necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_start, compared_policy->cond_remote_prefix)) {
2766					continue;
2767				}
2768			}
2769		}
2770
2771		return (TRUE);
2772	}
2773
2774	return (FALSE);
2775}
2776
2777static bool
2778necp_kernel_socket_policies_reprocess(void)
2779{
2780	int app_i;
2781	int bucket_allocation_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
2782	int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
2783	int app_layer_allocation_count = 0;
2784	int app_layer_current_free_index = 0;
2785	struct necp_kernel_socket_policy *kernel_policy = NULL;
2786
2787	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
2788
2789	// Reset mask to 0
2790	necp_kernel_application_policies_condition_mask = 0;
2791	necp_kernel_socket_policies_condition_mask = 0;
2792	necp_kernel_application_policies_count = 0;
2793	necp_kernel_socket_policies_count = 0;
2794	necp_kernel_socket_policies_non_app_count = 0;
2795
2796	// Reset all maps to NULL
2797	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
2798		if (necp_kernel_socket_policies_map[app_i] != NULL) {
2799			FREE(necp_kernel_socket_policies_map[app_i], M_NECP);
2800			necp_kernel_socket_policies_map[app_i] = NULL;
2801		}
2802
2803		// Init counts
2804		bucket_allocation_counts[app_i] = 0;
2805	}
2806	if (necp_kernel_socket_policies_app_layer_map != NULL) {
2807		FREE(necp_kernel_socket_policies_app_layer_map, M_NECP);
2808		necp_kernel_socket_policies_app_layer_map = NULL;
2809	}
2810
2811	// Create masks and counts
2812	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
2813		// App layer mask/count
2814		necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
2815		necp_kernel_application_policies_count++;
2816		app_layer_allocation_count++;
2817
2818		// Update socket layer bucket mask/counts
2819		necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
2820		necp_kernel_socket_policies_count++;
2821
2822		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
2823			kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
2824			necp_kernel_socket_policies_non_app_count++;
2825			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
2826				bucket_allocation_counts[app_i]++;
2827			}
2828		} else {
2829			bucket_allocation_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
2830		}
2831	}
2832
2833	// Allocate maps
2834	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
2835		if (bucket_allocation_counts[app_i] > 0) {
2836			// Allocate a NULL-terminated array of policy pointers for each bucket
2837			MALLOC(necp_kernel_socket_policies_map[app_i], struct necp_kernel_socket_policy **, sizeof(struct necp_kernel_socket_policy *) * (bucket_allocation_counts[app_i] + 1), M_NECP, M_WAITOK);
2838			if (necp_kernel_socket_policies_map[app_i] == NULL) {
2839				goto fail;
2840			}
2841
2842			// Initialize the first entry to NULL
2843			(necp_kernel_socket_policies_map[app_i])[0] = NULL;
2844		}
2845		bucket_current_free_index[app_i] = 0;
2846	}
2847	MALLOC(necp_kernel_socket_policies_app_layer_map, struct necp_kernel_socket_policy **, sizeof(struct necp_kernel_socket_policy *) * (app_layer_allocation_count + 1), M_NECP, M_WAITOK);
2848	if (necp_kernel_socket_policies_app_layer_map == NULL) {
2849		goto fail;
2850	}
2851	necp_kernel_socket_policies_app_layer_map[0] = NULL;
2852
2853	// Fill out maps
2854	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
2855		// Insert pointers into map
2856		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
2857			kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
2858			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
2859				if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_map[app_i], bucket_current_free_index[app_i])) {
2860					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
2861					bucket_current_free_index[app_i]++;
2862					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
2863				}
2864			}
2865		} else {
2866			app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
2867			if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_map[app_i], bucket_current_free_index[app_i])) {
2868				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
2869				bucket_current_free_index[app_i]++;
2870				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
2871			}
2872		}
2873
2874		if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
2875			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
2876			app_layer_current_free_index++;
2877			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
2878		}
2879	}
2880	necp_kernel_socket_policies_dump_all();
2881	BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
2882	return (TRUE);
2883
2884fail:
2885	// Free memory, reset masks to 0
2886	necp_kernel_application_policies_condition_mask = 0;
2887	necp_kernel_socket_policies_condition_mask = 0;
2888	necp_kernel_application_policies_count = 0;
2889	necp_kernel_socket_policies_count = 0;
2890	necp_kernel_socket_policies_non_app_count = 0;
2891	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
2892		if (necp_kernel_socket_policies_map[app_i] != NULL) {
2893			FREE(necp_kernel_socket_policies_map[app_i], M_NECP);
2894			necp_kernel_socket_policies_map[app_i] = NULL;
2895		}
2896	}
2897	if (necp_kernel_socket_policies_app_layer_map != NULL) {
2898		FREE(necp_kernel_socket_policies_app_layer_map, M_NECP);
2899		necp_kernel_socket_policies_app_layer_map = NULL;
2900	}
2901	return (FALSE);
2902}
2903
2904static u_int32_t
2905necp_get_new_string_id(void)
2906{
2907	u_int32_t newid = 0;
2908
2909	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
2910
2911	necp_last_string_id++;
2912	if (necp_last_string_id < 1) {
2913		necp_last_string_id = 1;
2914	}
2915
2916	newid = necp_last_string_id;
2917	if (newid == 0) {
2918		NECPLOG0(LOG_DEBUG, "Allocate string id failed.\n");
2919		return (0);
2920	}
2921
2922	return (newid);
2923}
2924
2925static struct necp_string_id_mapping *
2926necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string)
2927{
2928	struct necp_string_id_mapping *searchentry = NULL;
2929	struct necp_string_id_mapping *foundentry = NULL;
2930
2931	LIST_FOREACH(searchentry, list, chain) {
2932		if (strcmp(searchentry->string, string) == 0) {
2933			foundentry = searchentry;
2934			break;
2935		}
2936	}
2937
2938	return (foundentry);
2939}
2940
2941static u_int32_t
2942necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string)
2943{
2944	u_int32_t string_id = 0;
2945	struct necp_string_id_mapping *existing_mapping = NULL;
2946
2947	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
2948
2949	existing_mapping = necp_lookup_string_to_id_locked(list, string);
2950	if (existing_mapping != NULL) {
2951		string_id = existing_mapping->id;
2952		existing_mapping->refcount++;
2953	} else {
2954		struct necp_string_id_mapping *new_mapping = NULL;
2955		MALLOC(new_mapping, struct necp_string_id_mapping *, sizeof(struct necp_string_id_mapping), M_NECP, M_WAITOK);
2956		if (new_mapping != NULL) {
2957			memset(new_mapping, 0, sizeof(struct necp_string_id_mapping));
2958
2959			size_t length = strlen(string) + 1;
2960			MALLOC(new_mapping->string, char *, length, M_NECP, M_WAITOK);
2961			if (new_mapping->string != NULL) {
2962				memcpy(new_mapping->string, string, length);
2963				new_mapping->id = necp_get_new_string_id();
2964				new_mapping->refcount = 1;
2965				LIST_INSERT_HEAD(list, new_mapping, chain);
2966				string_id = new_mapping->id;
2967			} else {
2968				FREE(new_mapping, M_NECP);
2969				new_mapping = NULL;
2970			}
2971		}
2972	}
2973	return (string_id);
2974}
2975
2976static bool
2977necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string)
2978{
2979	struct necp_string_id_mapping *existing_mapping = NULL;
2980
2981	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
2982
2983	existing_mapping = necp_lookup_string_to_id_locked(list, string);
2984	if (existing_mapping != NULL) {
2985		if (--existing_mapping->refcount == 0) {
2986			LIST_REMOVE(existing_mapping, chain);
2987			FREE(existing_mapping->string, M_NECP);
2988			FREE(existing_mapping, M_NECP);
2989		}
2990		return (TRUE);
2991	}
2992
2993	return (FALSE);
2994}
2995
2996#define NECP_NULL_SERVICE_ID 1
2997static u_int32_t
2998necp_get_new_uuid_id(void)
2999{
3000	u_int32_t newid = 0;
3001
3002	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3003
3004	necp_last_uuid_id++;
3005	if (necp_last_uuid_id < (NECP_NULL_SERVICE_ID + 1)) {
3006		necp_last_uuid_id = (NECP_NULL_SERVICE_ID + 1);
3007	}
3008
3009	newid = necp_last_uuid_id;
3010	if (newid == 0) {
3011		NECPLOG0(LOG_DEBUG, "Allocate uuid id failed.\n");
3012		return (0);
3013	}
3014
3015	return (newid);
3016}
3017
3018static struct necp_uuid_id_mapping *
3019necp_uuid_lookup_app_id_locked(uuid_t uuid)
3020{
3021	struct necp_uuid_id_mapping *searchentry = NULL;
3022	struct necp_uuid_id_mapping *foundentry = NULL;
3023
3024	LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
3025		if (uuid_compare(searchentry->uuid, uuid) == 0) {
3026			foundentry = searchentry;
3027			break;
3028		}
3029	}
3030
3031	return (foundentry);
3032}
3033
3034static u_int32_t
3035necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
3036{
3037	u_int32_t local_id = 0;
3038	struct necp_uuid_id_mapping *existing_mapping = NULL;
3039
3040	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3041
3042	if (allocated_mapping) {
3043		*allocated_mapping = FALSE;
3044	}
3045
3046	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
3047	if (existing_mapping != NULL) {
3048		local_id = existing_mapping->id;
3049		existing_mapping->refcount++;
3050		if (uuid_policy_table) {
3051			existing_mapping->table_refcount++;
3052		}
3053	} else {
3054		struct necp_uuid_id_mapping *new_mapping = NULL;
3055		MALLOC(new_mapping, struct necp_uuid_id_mapping *, sizeof(*new_mapping), M_NECP, M_WAITOK);
3056		if (new_mapping != NULL) {
3057			uuid_copy(new_mapping->uuid, uuid);
3058			new_mapping->id = necp_get_new_uuid_id();
3059			new_mapping->refcount = 1;
3060			if (uuid_policy_table) {
3061				new_mapping->table_refcount = 1;
3062			} else {
3063				new_mapping->table_refcount = 0;
3064			}
3065
3066			LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
3067
3068			if (allocated_mapping) {
3069				*allocated_mapping = TRUE;
3070			}
3071
3072			local_id = new_mapping->id;
3073		}
3074	}
3075
3076	return (local_id);
3077}
3078
3079static bool
3080necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
3081{
3082	struct necp_uuid_id_mapping *existing_mapping = NULL;
3083
3084	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3085
3086	if (removed_mapping) {
3087		*removed_mapping = FALSE;
3088	}
3089
3090	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
3091	if (existing_mapping != NULL) {
3092		if (uuid_policy_table) {
3093			existing_mapping->table_refcount--;
3094		}
3095		if (--existing_mapping->refcount == 0) {
3096			LIST_REMOVE(existing_mapping, chain);
3097			FREE(existing_mapping, M_NECP);
3098			if (removed_mapping) {
3099				*removed_mapping = TRUE;
3100			}
3101		}
3102		return (TRUE);
3103	}
3104
3105	return (FALSE);
3106}
3107
3108static struct necp_uuid_id_mapping *
3109necp_uuid_get_null_service_id_mapping(void)
3110{
3111	static struct necp_uuid_id_mapping null_mapping;
3112	uuid_clear(null_mapping.uuid);
3113	null_mapping.id = NECP_NULL_SERVICE_ID;
3114
3115	return (&null_mapping);
3116}
3117
3118static struct necp_uuid_id_mapping *
3119necp_uuid_lookup_service_id_locked(uuid_t uuid)
3120{
3121	struct necp_uuid_id_mapping *searchentry = NULL;
3122	struct necp_uuid_id_mapping *foundentry = NULL;
3123
3124	if (uuid_is_null(uuid)) {
3125		return necp_uuid_get_null_service_id_mapping();
3126	}
3127
3128	LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
3129		if (uuid_compare(searchentry->uuid, uuid) == 0) {
3130			foundentry = searchentry;
3131			break;
3132		}
3133	}
3134
3135	return (foundentry);
3136}
3137
3138static struct necp_uuid_id_mapping *
3139necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)
3140{
3141	struct necp_uuid_id_mapping *searchentry = NULL;
3142	struct necp_uuid_id_mapping *foundentry = NULL;
3143
3144	if (local_id == NECP_NULL_SERVICE_ID) {
3145		return necp_uuid_get_null_service_id_mapping();
3146	}
3147
3148	LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
3149		if (searchentry->id == local_id) {
3150			foundentry = searchentry;
3151			break;
3152		}
3153	}
3154
3155	return (foundentry);
3156}
3157
3158static u_int32_t
3159necp_create_uuid_service_id_mapping(uuid_t uuid)
3160{
3161	u_int32_t local_id = 0;
3162	struct necp_uuid_id_mapping *existing_mapping = NULL;
3163
3164	if (uuid_is_null(uuid)) {
3165		return (NECP_NULL_SERVICE_ID);
3166	}
3167
3168	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3169
3170	existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
3171	if (existing_mapping != NULL) {
3172		local_id = existing_mapping->id;
3173		existing_mapping->refcount++;
3174	} else {
3175		struct necp_uuid_id_mapping *new_mapping = NULL;
3176		MALLOC(new_mapping, struct necp_uuid_id_mapping *, sizeof(*new_mapping), M_NECP, M_WAITOK);
3177		if (new_mapping != NULL) {
3178			uuid_copy(new_mapping->uuid, uuid);
3179			new_mapping->id = necp_get_new_uuid_id();
3180			new_mapping->refcount = 1;
3181
3182			LIST_INSERT_HEAD(&necp_uuid_service_id_list, new_mapping, chain);
3183
3184			local_id = new_mapping->id;
3185		}
3186	}
3187
3188	return (local_id);
3189}
3190
3191static bool
3192necp_remove_uuid_service_id_mapping(uuid_t uuid)
3193{
3194	struct necp_uuid_id_mapping *existing_mapping = NULL;
3195
3196	if (uuid_is_null(uuid)) {
3197		return (TRUE);
3198	}
3199
3200	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3201
3202	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
3203	if (existing_mapping != NULL) {
3204		if (--existing_mapping->refcount == 0) {
3205			LIST_REMOVE(existing_mapping, chain);
3206			FREE(existing_mapping, M_NECP);
3207		}
3208		return (TRUE);
3209	}
3210
3211	return (FALSE);
3212}
3213
3214
3215static bool
3216necp_kernel_socket_policies_update_uuid_table(void)
3217{
3218	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3219
3220	if (necp_uuid_app_id_mappings_dirty) {
3221		if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, NULL, PROC_UUID_NECP_APP_POLICY) < 0) {
3222			NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
3223			return (FALSE);
3224		}
3225
3226		if (necp_num_uuid_app_id_mappings > 0) {
3227			struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
3228			for (uuid_list_head = &necp_uuid_app_id_hashtbl[necp_uuid_app_id_hash_num_buckets - 1]; uuid_list_head >= necp_uuid_app_id_hashtbl; uuid_list_head--) {
3229				struct necp_uuid_id_mapping *mapping = NULL;
3230				LIST_FOREACH(mapping, uuid_list_head, chain) {
3231					if (mapping->table_refcount > 0 &&
3232						proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
3233						NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
3234					}
3235				}
3236			}
3237		}
3238
3239		necp_uuid_app_id_mappings_dirty = FALSE;
3240	}
3241
3242	return (TRUE);
3243}
3244
3245#define	NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS (NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_LAST_INTERFACE)
3246static necp_kernel_policy_id
3247necp_kernel_ip_output_policy_add(necp_policy_id parent_policy_id, necp_policy_order order, necp_policy_order suborder, u_int32_t session_order, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_kernel_policy_id cond_policy_id, ifnet_t cond_bound_interface, u_int32_t cond_last_interface_index, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
3248{
3249	struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
3250	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
3251
3252	MALLOC_ZONE(new_kernel_policy, struct necp_kernel_ip_output_policy *, sizeof(*new_kernel_policy), M_NECP_IP_POLICY, M_WAITOK);
3253	if (new_kernel_policy == NULL) {
3254		goto done;
3255	}
3256
3257	memset(new_kernel_policy, 0, sizeof(*new_kernel_policy));
3258	new_kernel_policy->parent_policy_id = parent_policy_id;
3259	new_kernel_policy->id = necp_kernel_policy_get_new_id();
3260	new_kernel_policy->suborder = suborder;
3261	new_kernel_policy->order = order;
3262	new_kernel_policy->session_order = session_order;
3263
3264	// Sanitize condition mask
3265	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
3266	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
3267		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
3268	}
3269	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
3270		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
3271	}
3272	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
3273		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
3274	}
3275	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
3276
3277	// Set condition values
3278	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
3279		new_kernel_policy->cond_policy_id = cond_policy_id;
3280	}
3281	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3282		if (cond_bound_interface) {
3283			ifnet_reference(cond_bound_interface);
3284		}
3285		new_kernel_policy->cond_bound_interface = cond_bound_interface;
3286	}
3287	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
3288		new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
3289	}
3290	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3291		new_kernel_policy->cond_protocol = cond_protocol;
3292	}
3293	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3294		memcpy(&new_kernel_policy->cond_local_start, cond_local_start, cond_local_start->sa.sa_len);
3295	}
3296	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3297		memcpy(&new_kernel_policy->cond_local_end, cond_local_end, cond_local_end->sa.sa_len);
3298	}
3299	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
3300		new_kernel_policy->cond_local_prefix = cond_local_prefix;
3301	}
3302	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3303		memcpy(&new_kernel_policy->cond_remote_start, cond_remote_start, cond_remote_start->sa.sa_len);
3304	}
3305	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3306		memcpy(&new_kernel_policy->cond_remote_end, cond_remote_end, cond_remote_end->sa.sa_len);
3307	}
3308	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
3309		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
3310	}
3311
3312	new_kernel_policy->result = result;
3313	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
3314
3315	if (necp_debug) {
3316		NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%x\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
3317	}
3318	LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
3319done:
3320	return (new_kernel_policy ? new_kernel_policy->id : 0);
3321}
3322
3323static struct necp_kernel_ip_output_policy *
3324necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
3325{
3326	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
3327	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
3328
3329	if (policy_id == 0) {
3330		return (NULL);
3331	}
3332
3333	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
3334		if (kernel_policy->id == policy_id) {
3335			return (kernel_policy);
3336		}
3337	}
3338
3339	return (NULL);
3340}
3341
3342static bool
3343necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
3344{
3345	struct necp_kernel_ip_output_policy *policy = NULL;
3346
3347	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3348
3349	policy = necp_kernel_ip_output_policy_find(policy_id);
3350	if (policy) {
3351		LIST_REMOVE(policy, chain);
3352
3353		if (policy->cond_bound_interface) {
3354			ifnet_release(policy->cond_bound_interface);
3355			policy->cond_bound_interface = NULL;
3356		}
3357
3358		FREE_ZONE(policy, sizeof(*policy), M_NECP_IP_POLICY);
3359		return (TRUE);
3360	}
3361
3362	return (FALSE);
3363}
3364
3365static void
3366necp_kernel_ip_output_policies_dump_all(void)
3367{
3368	struct necp_kernel_ip_output_policy *policy = NULL;
3369	int policy_i;
3370	int id_i;
3371
3372	if (necp_debug) {
3373		NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
3374		NECPLOG0(LOG_DEBUG, "-----------\n");
3375		for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
3376			NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
3377			for (policy_i = 0; necp_kernel_ip_output_policies_map[id_i] != NULL && (necp_kernel_ip_output_policies_map[id_i])[policy_i] != NULL; policy_i++) {
3378				policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
3379				NECPLOG(LOG_DEBUG, "\t%d. Policy ID: %d, Order: %d.%d.%d, Mask: %x, Result: %d, Parameter: %d\n", policy_i, policy->id, policy->session_order, policy->order, policy->suborder, policy->condition_mask, policy->result, policy->result_parameter);
3380			}
3381			NECPLOG0(LOG_DEBUG, "-----------\n");
3382		}
3383	}
3384}
3385
3386static inline bool
3387necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
3388{
3389	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
3390		if (upper_policy->session_order != lower_policy->session_order) {
3391			// A skip cannot override a policy of a different session
3392			return (FALSE);
3393		} else {
3394			if (upper_policy->result_parameter.skip_policy_order == 0 ||
3395				lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
3396				// This policy is beyond the skip
3397				return (FALSE);
3398			} else {
3399				// This policy is inside the skip
3400				return (TRUE);
3401			}
3402		}
3403	}
3404
3405	// All other IP Output policy results (drop, tunnel, hard pass) currently overlap
3406	return (TRUE);
3407}
3408
3409static bool
3410necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy *policy, struct necp_kernel_ip_output_policy **policy_array, int valid_indices)
3411{
3412	bool can_skip = FALSE;
3413	u_int32_t highest_skip_session_order = 0;
3414	u_int32_t highest_skip_order = 0;
3415	int i;
3416	for (i = 0; i < valid_indices; i++) {
3417		struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
3418
3419		// For policies in a skip window, we can't mark conflicting policies as unnecessary
3420		if (can_skip) {
3421			if (highest_skip_session_order != compared_policy->session_order ||
3422				(highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
3423				// If we've moved on to the next session, or passed the skip window
3424				highest_skip_session_order = 0;
3425				highest_skip_order = 0;
3426				can_skip = FALSE;
3427			} else {
3428				// If this policy is also a skip, in can increase the skip window
3429				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
3430					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
3431						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
3432					}
3433				}
3434				continue;
3435			}
3436		}
3437
3438		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
3439			// This policy is a skip. Set the skip window accordingly
3440			can_skip = TRUE;
3441			highest_skip_session_order = compared_policy->session_order;
3442			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
3443		}
3444
3445		// The result of the compared policy must be able to block out this policy result
3446		if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
3447			continue;
3448		}
3449
3450		// If new policy matches All Interfaces, compared policy must also
3451		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
3452			continue;
3453		}
3454
3455		// Default makes lower policies unecessary always
3456		if (compared_policy->condition_mask == 0) {
3457			return (TRUE);
3458		}
3459
3460		// Compared must be more general than policy, and include only conditions within policy
3461		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
3462			continue;
3463		}
3464
3465		// Negative conditions must match for the overlapping conditions
3466		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
3467			continue;
3468		}
3469
3470		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
3471			compared_policy->cond_policy_id != policy->cond_policy_id) {
3472			continue;
3473		}
3474
3475		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
3476			compared_policy->cond_bound_interface != policy->cond_bound_interface) {
3477			continue;
3478		}
3479
3480		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
3481			compared_policy->cond_protocol != policy->cond_protocol) {
3482			continue;
3483		}
3484
3485		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3486			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3487				if (!necp_is_range_in_range((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&policy->cond_local_end, (struct sockaddr *)&compared_policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_end)) {
3488					continue;
3489				}
3490			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
3491				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
3492					!necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_start, compared_policy->cond_local_prefix)) {
3493					continue;
3494				}
3495			}
3496		}
3497
3498		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3499			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3500				if (!necp_is_range_in_range((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&policy->cond_remote_end, (struct sockaddr *)&compared_policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_end)) {
3501					continue;
3502				}
3503			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
3504				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
3505					!necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_start, compared_policy->cond_remote_prefix)) {
3506					continue;
3507				}
3508			}
3509		}
3510
3511		return (TRUE);
3512	}
3513
3514	return (FALSE);
3515}
3516
3517static bool
3518necp_kernel_ip_output_policies_reprocess(void)
3519{
3520	int i;
3521	int bucket_allocation_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
3522	int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
3523	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
3524
3525	lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3526
3527	// Reset mask to 0
3528	necp_kernel_ip_output_policies_condition_mask = 0;
3529	necp_kernel_ip_output_policies_count = 0;
3530	necp_kernel_ip_output_policies_non_id_count = 0;
3531
3532	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
3533		if (necp_kernel_ip_output_policies_map[i] != NULL) {
3534			FREE(necp_kernel_ip_output_policies_map[i], M_NECP);
3535			necp_kernel_ip_output_policies_map[i] = NULL;
3536		}
3537
3538		// Init counts
3539		bucket_allocation_counts[i] = 0;
3540	}
3541
3542	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
3543		// Update mask
3544		necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
3545		necp_kernel_ip_output_policies_count++;
3546
3547		// Update bucket counts
3548		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
3549			necp_kernel_ip_output_policies_non_id_count++;
3550			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
3551				bucket_allocation_counts[i]++;
3552			}
3553		} else {
3554			bucket_allocation_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
3555		}
3556	}
3557
3558	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
3559		if (bucket_allocation_counts[i] > 0) {
3560			// Allocate a NULL-terminated array of policy pointers for each bucket
3561			MALLOC(necp_kernel_ip_output_policies_map[i], struct necp_kernel_ip_output_policy **, sizeof(struct necp_kernel_ip_output_policy *) * (bucket_allocation_counts[i] + 1), M_NECP, M_WAITOK);
3562			if (necp_kernel_ip_output_policies_map[i] == NULL) {
3563				goto fail;
3564			}
3565
3566			// Initialize the first entry to NULL
3567			(necp_kernel_ip_output_policies_map[i])[0] = NULL;
3568		}
3569		bucket_current_free_index[i] = 0;
3570	}
3571
3572	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
3573		// Insert pointers into map
3574		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
3575			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
3576				if (!necp_kernel_ip_output_policy_is_unnecessary(kernel_policy, necp_kernel_ip_output_policies_map[i], bucket_current_free_index[i])) {
3577					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
3578					bucket_current_free_index[i]++;
3579					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
3580				}
3581			}
3582		} else {
3583			i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
3584			if (!necp_kernel_ip_output_policy_is_unnecessary(kernel_policy, necp_kernel_ip_output_policies_map[i], bucket_current_free_index[i])) {
3585				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
3586				bucket_current_free_index[i]++;
3587				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
3588			}
3589		}
3590	}
3591	necp_kernel_ip_output_policies_dump_all();
3592	return (TRUE);
3593
3594fail:
3595	// Free memory, reset mask to 0
3596	necp_kernel_ip_output_policies_condition_mask = 0;
3597	necp_kernel_ip_output_policies_count = 0;
3598	necp_kernel_ip_output_policies_non_id_count = 0;
3599	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
3600		if (necp_kernel_ip_output_policies_map[i] != NULL) {
3601			FREE(necp_kernel_ip_output_policies_map[i], M_NECP);
3602			necp_kernel_ip_output_policies_map[i] = NULL;
3603		}
3604	}
3605	return (FALSE);
3606}
3607
3608// Outbound Policy Matching
3609// ---------------------
3610struct substring {
3611	char *string;
3612	size_t length;
3613};
3614
3615static struct substring
3616necp_trim_dots_and_stars(char *string, size_t length)
3617{
3618	struct substring sub;
3619	sub.string = string;
3620	sub.length = string ? length : 0;
3621
3622	while (sub.length && (sub.string[0] == '.' || sub.string[0] == '*')) {
3623		sub.string++;
3624		sub.length--;
3625	}
3626
3627	while (sub.length && (sub.string[sub.length - 1] == '.' || sub.string[sub.length - 1] == '*')) {
3628		sub.length--;
3629	}
3630
3631	return (sub);
3632}
3633
3634static char *
3635necp_create_trimmed_domain(char *string, size_t length)
3636{
3637	char *trimmed_domain = NULL;
3638	struct substring sub = necp_trim_dots_and_stars(string, length);
3639
3640	MALLOC(trimmed_domain, char *, sub.length + 1, M_NECP, M_WAITOK);
3641	if (trimmed_domain == NULL) {
3642		return (NULL);
3643	}
3644
3645	memcpy(trimmed_domain, sub.string, sub.length);
3646	trimmed_domain[sub.length] = 0;
3647
3648	return (trimmed_domain);
3649}
3650
3651static inline int
3652necp_count_dots(char *string, size_t length)
3653{
3654	int dot_count = 0;
3655	size_t i = 0;
3656
3657	for (i = 0; i < length; i++) {
3658		if (string[i] == '.') {
3659			dot_count++;
3660		}
3661	}
3662
3663	return (dot_count);
3664}
3665
3666static bool
3667necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
3668{
3669	if (parent.length <= suffix.length) {
3670		return (FALSE);
3671	}
3672
3673	size_t length_difference = (parent.length - suffix.length);
3674
3675	if (require_dot_before_suffix) {
3676		if (((char *)(parent.string + length_difference - 1))[0] != '.') {
3677			return (FALSE);
3678		}
3679	}
3680
3681	return (memcmp(parent.string + length_difference, suffix.string, suffix.length) == 0);
3682}
3683
3684static bool
3685necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain, u_int8_t domain_dot_count)
3686{
3687	if (hostname_substring.string == NULL || domain == NULL) {
3688		return (hostname_substring.string == domain);
3689	}
3690
3691	struct substring domain_substring;
3692	domain_substring.string = domain;
3693	domain_substring.length = strlen(domain);
3694
3695	if (hostname_dot_count == domain_dot_count) {
3696		if (hostname_substring.length == domain_substring.length &&
3697			memcmp(hostname_substring.string, domain_substring.string, hostname_substring.length) == 0) {
3698			return (TRUE);
3699		}
3700	} else if (domain_dot_count > 0 && domain_dot_count < hostname_dot_count) {
3701		if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
3702			return (TRUE);
3703		}
3704	}
3705
3706	return (FALSE);
3707}
3708
3709static void
3710necp_application_fillout_info_locked(uuid_t application_uuid, uuid_t real_application_uuid, char *account, char *domain, pid_t pid, uid_t uid, u_int16_t protocol, u_int32_t bound_interface_index, u_int32_t traffic_class, struct necp_socket_info *info)
3711{
3712	memset(info, 0, sizeof(struct necp_socket_info));
3713
3714	info->pid = pid;
3715	info->uid = uid;
3716	info->protocol = protocol;
3717	info->bound_interface_index = bound_interface_index;
3718	info->traffic_class = traffic_class;
3719	info->cred_result = 0; // Don't check the entitlement here, only in the socket layer
3720
3721	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
3722		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
3723		if (existing_mapping) {
3724			info->application_id = existing_mapping->id;
3725		}
3726	}
3727
3728	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
3729		if (uuid_compare(application_uuid, real_application_uuid) == 0) {
3730			info->real_application_id = info->application_id;
3731		} else {
3732			struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
3733			if (existing_mapping) {
3734				info->real_application_id = existing_mapping->id;
3735			}
3736		}
3737	}
3738
3739	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
3740		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
3741		if (existing_mapping) {
3742			info->account_id = existing_mapping->id;
3743		}
3744	}
3745
3746	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
3747		info->domain = domain;
3748	}
3749}
3750
3751static int
3752necp_application_find_policy_match_internal(u_int8_t *parameters, size_t parameters_size, struct necp_aggregate_result *returned_result)
3753{
3754	int error = 0;
3755	size_t offset = 0;
3756
3757	struct necp_kernel_socket_policy *matched_policy = NULL;
3758	struct necp_socket_info info;
3759	necp_kernel_policy_filter filter_control_unit = 0;
3760	necp_kernel_policy_result service_action = 0;
3761	necp_kernel_policy_service service = { 0, 0 };
3762
3763	pid_t pid = 0;
3764	uid_t uid = 0;
3765	u_int16_t protocol = 0;
3766	u_int32_t bound_interface_index = 0;
3767	u_int32_t traffic_class = 0;
3768
3769	uuid_t application_uuid;
3770	uuid_clear(application_uuid);
3771	uuid_t real_application_uuid;
3772	uuid_clear(real_application_uuid);
3773	char *domain = NULL;
3774	char *account = NULL;
3775
3776	if (returned_result == NULL) {
3777		return (EINVAL);
3778	}
3779
3780	memset(returned_result, 0, sizeof(struct necp_aggregate_result));
3781
3782	lck_rw_lock_shared(&necp_kernel_policy_lock);
3783	if (necp_kernel_application_policies_count == 0) {
3784		if (necp_drop_all_order > 0) {
3785			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
3786			lck_rw_done(&necp_kernel_policy_lock);
3787			return (0);
3788		}
3789	}
3790	lck_rw_done(&necp_kernel_policy_lock);
3791
3792	while (offset < parameters_size) {
3793		u_int8_t type = necp_buffer_get_tlv_type(parameters, offset);
3794		size_t length = necp_buffer_get_tlv_length(parameters, offset);
3795
3796		if (length > 0 && (offset + sizeof(u_int8_t) + sizeof(size_t) + length) <= parameters_size) {
3797			u_int8_t *value = necp_buffer_get_tlv_value(parameters, offset, NULL);
3798			if (value != NULL) {
3799				switch (type) {
3800					case NECP_POLICY_CONDITION_APPLICATION: {
3801						if (length >= sizeof(uuid_t)) {
3802							uuid_copy(application_uuid, value);
3803						}
3804						break;
3805					}
3806					case NECP_POLICY_CONDITION_REAL_APPLICATION: {
3807						if (length >= sizeof(uuid_t)) {
3808							uuid_copy(real_application_uuid, value);
3809						}
3810						break;
3811					}
3812					case NECP_POLICY_CONDITION_DOMAIN: {
3813						domain = (char *)value;
3814						domain[length - 1] = 0;
3815						break;
3816					}
3817					case NECP_POLICY_CONDITION_ACCOUNT: {
3818						account = (char *)value;
3819						account[length - 1] = 0;
3820						break;
3821					}
3822					case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
3823						if (length >= sizeof(u_int32_t)) {
3824							memcpy(&traffic_class, value, sizeof(u_int32_t));
3825						}
3826						break;
3827					}
3828					case NECP_POLICY_CONDITION_PID: {
3829						if (length >= sizeof(pid_t)) {
3830							memcpy(&pid, value, sizeof(pid_t));
3831						}
3832						break;
3833					}
3834					case NECP_POLICY_CONDITION_UID: {
3835						if (length >= sizeof(uid_t)) {
3836							memcpy(&uid, value, sizeof(uid_t));
3837						}
3838						break;
3839					}
3840					case NECP_POLICY_CONDITION_IP_PROTOCOL: {
3841						if (length >= sizeof(u_int16_t)) {
3842							memcpy(&protocol, value, sizeof(u_int16_t));
3843						}
3844						break;
3845					}
3846					case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
3847						if (length <= IFXNAMSIZ && length > 0) {
3848							ifnet_t bound_interface = NULL;
3849							char interface_name[IFXNAMSIZ];
3850							memcpy(interface_name, value, length);
3851							interface_name[length - 1] = 0; // Make sure the string is NULL terminated
3852							if (ifnet_find_by_name(interface_name, &bound_interface) == 0) {
3853								bound_interface_index = bound_interface->if_index;
3854							}
3855						}
3856						break;
3857					}
3858					default: {
3859						break;
3860					}
3861				}
3862			}
3863		}
3864
3865		offset += sizeof(u_int8_t) + sizeof(size_t) + length;
3866	}
3867
3868	// Lock
3869	lck_rw_lock_shared(&necp_kernel_policy_lock);
3870
3871	necp_application_fillout_info_locked(application_uuid, real_application_uuid, account, domain, pid, uid, protocol, bound_interface_index, traffic_class, &info);
3872	matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map, &info, &filter_control_unit, &service_action, &service);
3873	if (matched_policy) {
3874		returned_result->routing_result = matched_policy->result;
3875		memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
3876	} else {
3877		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
3878	}
3879	returned_result->filter_control_unit = filter_control_unit;
3880	returned_result->service_action = service_action;
3881
3882	if (service.identifier != 0) {
3883		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(service.identifier);
3884		if (mapping != NULL) {
3885			struct necp_service_registration *service_registration = NULL;
3886			uuid_copy(returned_result->service_uuid, mapping->uuid);
3887			returned_result->service_data = service.data;
3888			if (service.identifier == NECP_NULL_SERVICE_ID) {
3889				// NULL service is always 'registered'
3890				returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
3891			} else {
3892				LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
3893					if (service.identifier == service_registration->service_id) {
3894						returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
3895						break;
3896					}
3897				}
3898			}
3899		}
3900	}
3901
3902	// Unlock
3903	lck_rw_done(&necp_kernel_policy_lock);
3904
3905	return (error);
3906}
3907
3908#define NECP_MAX_MATCH_POLICY_PARAMETER_SIZE 1024
3909
3910int
3911necp_match_policy(struct proc *p, struct necp_match_policy_args *uap, int32_t *retval)
3912{
3913#pragma unused(p, retval)
3914	u_int8_t *parameters = NULL;
3915	struct necp_aggregate_result returned_result;
3916	int error = 0;
3917
3918	if (uap == NULL) {
3919		error = EINVAL;
3920		goto done;
3921	}
3922
3923	if (uap->parameters == 0 || uap->parameters_size == 0 || uap->parameters_size > NECP_MAX_MATCH_POLICY_PARAMETER_SIZE || uap->returned_result == 0) {
3924		error = EINVAL;
3925		goto done;
3926	}
3927
3928	MALLOC(parameters, u_int8_t *, uap->parameters_size, M_NECP, M_WAITOK);
3929	if (parameters == NULL) {
3930		error = ENOMEM;
3931		goto done;
3932	}
3933	// Copy parameters in
3934	copyin(uap->parameters, parameters, uap->parameters_size);
3935
3936	error = necp_application_find_policy_match_internal(parameters, uap->parameters_size, &returned_result);
3937	if (error) {
3938		goto done;
3939	}
3940
3941	// Copy return value back
3942	copyout(&returned_result, uap->returned_result, sizeof(struct necp_aggregate_result));
3943done:
3944	if (parameters != NULL) {
3945		FREE(parameters, M_NECP);
3946	}
3947	return (error);
3948}
3949
3950static bool
3951necp_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)
3952{
3953	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
3954		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3955			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
3956			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3957				if (bound_interface_index == cond_bound_interface_index) {
3958					// No match, matches forbidden interface
3959					return (FALSE);
3960				}
3961			} else {
3962				if (bound_interface_index != cond_bound_interface_index) {
3963					// No match, does not match required interface
3964					return (FALSE);
3965				}
3966			}
3967		} else {
3968			if (bound_interface_index != 0) {
3969				// No match, requires a non-bound packet
3970				return (FALSE);
3971			}
3972		}
3973	}
3974
3975	if (kernel_policy->condition_mask == 0) {
3976		return (TRUE);
3977	}
3978
3979	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3980		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
3981			if (app_id == kernel_policy->cond_app_id) {
3982				// No match, matches forbidden application
3983				return (FALSE);
3984			}
3985		} else {
3986			if (app_id != kernel_policy->cond_app_id) {
3987				// No match, does not match required application
3988				return (FALSE);
3989			}
3990		}
3991	}
3992
3993	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3994		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3995			if (real_app_id == kernel_policy->cond_real_app_id) {
3996				// No match, matches forbidden application
3997				return (FALSE);
3998			}
3999		} else {
4000			if (real_app_id != kernel_policy->cond_real_app_id) {
4001				// No match, does not match required application
4002				return (FALSE);
4003			}
4004		}
4005	}
4006
4007	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
4008		if (cred_result != 0) {
4009			// Process is missing entitlement
4010			return (FALSE);
4011		}
4012	}
4013
4014	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
4015		bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
4016		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
4017			if (domain_matches) {
4018				// No match, matches forbidden domain
4019				return (FALSE);
4020			}
4021		} else {
4022			if (!domain_matches) {
4023				// No match, does not match required domain
4024				return (FALSE);
4025			}
4026		}
4027	}
4028
4029	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
4030		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
4031			if (account_id == kernel_policy->cond_account_id) {
4032				// No match, matches forbidden account
4033				return (FALSE);
4034			}
4035		} else {
4036			if (account_id != kernel_policy->cond_account_id) {
4037				// No match, does not match required account
4038				return (FALSE);
4039			}
4040		}
4041	}
4042
4043	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
4044		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
4045			if (pid == kernel_policy->cond_pid) {
4046				// No match, matches forbidden pid
4047				return (FALSE);
4048			}
4049		} else {
4050			if (pid != kernel_policy->cond_pid) {
4051				// No match, does not match required pid
4052				return (FALSE);
4053			}
4054		}
4055	}
4056
4057	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
4058		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
4059			if (uid == kernel_policy->cond_uid) {
4060				// No match, matches forbidden uid
4061				return (FALSE);
4062			}
4063		} else {
4064			if (uid != kernel_policy->cond_uid) {
4065				// No match, does not match required uid
4066				return (FALSE);
4067			}
4068		}
4069	}
4070
4071	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
4072		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
4073			if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
4074				traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
4075				// No match, matches forbidden traffic class
4076				return (FALSE);
4077			}
4078		} else {
4079			if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
4080				traffic_class > kernel_policy->cond_traffic_class.end_tc) {
4081				// No match, does not match required traffic class
4082				return (FALSE);
4083			}
4084		}
4085	}
4086
4087	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4088		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4089			if (protocol == kernel_policy->cond_protocol) {
4090				// No match, matches forbidden protocol
4091				return (FALSE);
4092			}
4093		} else {
4094			if (protocol != kernel_policy->cond_protocol) {
4095				// No match, does not match required protocol
4096				return (FALSE);
4097			}
4098		}
4099	}
4100
4101	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
4102		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4103			bool inRange = necp_is_addr_in_range((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, (struct sockaddr *)&kernel_policy->cond_local_end);
4104			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4105				if (inRange) {
4106					return (FALSE);
4107				}
4108			} else {
4109				if (!inRange) {
4110					return (FALSE);
4111				}
4112			}
4113		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4114			bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, kernel_policy->cond_local_prefix);
4115			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4116				if (inSubnet) {
4117					return (FALSE);
4118				}
4119			} else {
4120				if (!inSubnet) {
4121					return (FALSE);
4122				}
4123			}
4124		}
4125	}
4126
4127	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
4128		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4129			bool inRange = necp_is_addr_in_range((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, (struct sockaddr *)&kernel_policy->cond_remote_end);
4130			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4131				if (inRange) {
4132					return (FALSE);
4133				}
4134			} else {
4135				if (!inRange) {
4136					return (FALSE);
4137				}
4138			}
4139		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4140			bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, kernel_policy->cond_remote_prefix);
4141			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4142				if (inSubnet) {
4143					return (FALSE);
4144				}
4145			} else {
4146				if (!inSubnet) {
4147					return (FALSE);
4148				}
4149			}
4150		}
4151	}
4152
4153	return (TRUE);
4154}
4155
4156static inline u_int32_t
4157necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
4158{
4159	return (net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount));
4160}
4161
4162#define	NECP_KERNEL_ADDRESS_TYPE_CONDITIONS (NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX)
4163static void
4164necp_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)
4165{
4166	struct socket *so = NULL;
4167
4168	memset(info, 0, sizeof(struct necp_socket_info));
4169
4170	so = inp->inp_socket;
4171
4172	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
4173		info->pid = ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
4174	}
4175
4176	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID) {
4177		info->uid = kauth_cred_getuid(so->so_cred);
4178	}
4179
4180	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
4181		info->traffic_class = so->so_traffic_class;
4182	}
4183
4184	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4185		if (inp->inp_ip_p) {
4186			info->protocol = inp->inp_ip_p;
4187		} else {
4188			info->protocol = SOCK_PROTO(so);
4189		}
4190	}
4191
4192	if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
4193		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
4194		if (existing_mapping) {
4195			info->application_id = existing_mapping->id;
4196		}
4197
4198		if (!(so->so_flags & SOF_DELEGATED)) {
4199			info->real_application_id = info->application_id;
4200		} else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
4201			struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
4202			if (real_existing_mapping) {
4203				info->real_application_id = real_existing_mapping->id;
4204			}
4205		}
4206
4207		if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
4208			info->cred_result = priv_check_cred(so->so_cred, PRIV_NET_PRIVILEGED_NECP_MATCH, 0);
4209		}
4210	}
4211
4212	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
4213		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
4214		if (existing_mapping) {
4215			info->account_id = existing_mapping->id;
4216		}
4217	}
4218
4219	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
4220		info->domain = inp->inp_necp_attributes.inp_domain;
4221	}
4222
4223	if (override_bound_interface) {
4224		info->bound_interface_index = override_bound_interface;
4225	} else {
4226		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
4227			info->bound_interface_index = inp->inp_boundifp->if_index;
4228		}
4229	}
4230
4231	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS) {
4232		if (inp->inp_vflag & INP_IPV4) {
4233			if (override_local_addr) {
4234				memcpy(&info->local_addr, override_local_addr, override_local_addr->sa_len);
4235			} else {
4236				((struct sockaddr_in *)&info->local_addr)->sin_family = AF_INET;
4237				((struct sockaddr_in *)&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
4238				((struct sockaddr_in *)&info->local_addr)->sin_port = inp->inp_lport;
4239				memcpy(&((struct sockaddr_in *)&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
4240			}
4241
4242			if (override_remote_addr) {
4243				memcpy(&info->remote_addr, override_remote_addr, override_remote_addr->sa_len);
4244			} else {
4245				((struct sockaddr_in *)&info->remote_addr)->sin_family = AF_INET;
4246				((struct sockaddr_in *)&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
4247				((struct sockaddr_in *)&info->remote_addr)->sin_port = inp->inp_fport;
4248				memcpy(&((struct sockaddr_in *)&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
4249			}
4250		} else if (inp->inp_vflag & INP_IPV6) {
4251			if (override_local_addr) {
4252				memcpy(&info->local_addr, override_local_addr, override_local_addr->sa_len);
4253			} else {
4254				((struct sockaddr_in6 *)&info->local_addr)->sin6_family = AF_INET6;
4255				((struct sockaddr_in6 *)&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
4256				((struct sockaddr_in6 *)&info->local_addr)->sin6_port = inp->inp_lport;
4257				memcpy(&((struct sockaddr_in6 *)&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
4258			}
4259
4260			if (override_remote_addr) {
4261				memcpy(&info->remote_addr, override_remote_addr, override_remote_addr->sa_len);
4262			} else {
4263				((struct sockaddr_in6 *)&info->remote_addr)->sin6_family = AF_INET6;
4264				((struct sockaddr_in6 *)&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
4265				((struct sockaddr_in6 *)&info->remote_addr)->sin6_port = inp->inp_fport;
4266				memcpy(&((struct sockaddr_in6 *)&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
4267			}
4268		}
4269	}
4270}
4271
4272static inline struct necp_kernel_socket_policy *
4273necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy **policy_search_array, struct necp_socket_info *info, necp_kernel_policy_filter *return_filter, necp_kernel_policy_result *return_service_action, necp_kernel_policy_service *return_service)
4274{
4275	struct necp_kernel_socket_policy *matched_policy = NULL;
4276	u_int32_t skip_order = 0;
4277	u_int32_t skip_session_order = 0;
4278	int i;
4279
4280	// Pre-process domain for quick matching
4281	struct substring domain_substring = necp_trim_dots_and_stars(info->domain, info->domain ? strlen(info->domain) : 0);
4282	u_int8_t domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
4283
4284	if (return_filter) {
4285		*return_filter = 0;
4286	}
4287
4288	if (return_service_action) {
4289		*return_service_action = 0;
4290	}
4291
4292	if (return_service) {
4293		return_service->identifier = 0;
4294		return_service->data = 0;
4295	}
4296
4297	if (policy_search_array != NULL) {
4298		for (i = 0; policy_search_array[i] != NULL; i++) {
4299			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
4300				// We've hit a drop all rule
4301				break;
4302			}
4303			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
4304				// Done skipping
4305				skip_order = 0;
4306				skip_session_order = 0;
4307			}
4308			if (skip_order) {
4309				if (policy_search_array[i]->order < skip_order) {
4310					// Skip this policy
4311					continue;
4312				} else {
4313					// Done skipping
4314					skip_order = 0;
4315					skip_session_order = 0;
4316				}
4317			} else if (skip_session_order) {
4318				// Skip this policy
4319				continue;
4320			}
4321			if (necp_socket_check_policy(policy_search_array[i], info->application_id, info->real_application_id, info->cred_result, info->account_id, domain_substring, domain_dot_count, info->pid, info->uid, info->bound_interface_index, info->traffic_class, info->protocol, &info->local_addr, &info->remote_addr)) {
4322				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
4323					if (return_filter && *return_filter == 0) {
4324						*return_filter = policy_search_array[i]->result_parameter.filter_control_unit;
4325						if (necp_debug > 1) {
4326							NECPLOG(LOG_DEBUG, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Filter %d", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, policy_search_array[i]->result_parameter.filter_control_unit);
4327						}
4328					}
4329					continue;
4330				} else if (necp_kernel_socket_result_is_service_type(policy_search_array[i])) {
4331					if (return_service_action && *return_service_action == 0) {
4332						*return_service_action = policy_search_array[i]->result;
4333						if (necp_debug > 1) {
4334							NECPLOG(LOG_DEBUG, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Service Action %d", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, policy_search_array[i]->result);
4335						}
4336					}
4337					if (return_service && return_service->identifier == 0) {
4338						return_service->identifier = policy_search_array[i]->result_parameter.service.identifier;
4339						return_service->data = policy_search_array[i]->result_parameter.service.data;
4340						if (necp_debug > 1) {
4341							NECPLOG(LOG_DEBUG, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Service ID %d Data %d", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, policy_search_array[i]->result_parameter.service.identifier, policy_search_array[i]->result_parameter.service.data);
4342						}
4343					}
4344					continue;
4345				}
4346
4347				// Passed all tests, found a match
4348				matched_policy = policy_search_array[i];
4349				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
4350					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
4351					skip_session_order = policy_search_array[i]->session_order + 1;
4352					continue;
4353				}
4354				break;
4355			}
4356		}
4357	}
4358
4359	return (matched_policy);
4360}
4361
4362static bool
4363necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
4364{
4365	bool found_match = FALSE;
4366	errno_t result = 0;
4367	ifaddr_t *addresses = NULL;
4368	union necp_sockaddr_union address_storage;
4369	int i;
4370	int family = AF_INET;
4371	ifnet_t interface = ifindex2ifnet[interface_index];
4372
4373	if (inp == NULL || interface == NULL) {
4374		return (FALSE);
4375	}
4376
4377	if (inp->inp_vflag & INP_IPV4) {
4378		family = AF_INET;
4379	} else if (inp->inp_vflag & INP_IPV6) {
4380		family = AF_INET6;
4381	}
4382
4383	result = ifnet_get_address_list_family(interface, &addresses, family);
4384	if (result != 0) {
4385		NECPLOG(LOG_ERR, "Failed to get address list for %s%d", ifnet_name(interface), ifnet_unit(interface));
4386		return (FALSE);
4387	}
4388
4389	for (i = 0; addresses[i] != NULL; i++) {
4390		if (ifaddr_address(addresses[i], &address_storage.sa, sizeof(address_storage)) == 0) {
4391			if (family == AF_INET) {
4392				if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
4393					found_match = TRUE;
4394					goto done;
4395				}
4396			} else if (family == AF_INET6) {
4397				if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
4398					found_match = TRUE;
4399					goto done;
4400				}
4401			}
4402		}
4403	}
4404
4405done:
4406	ifnet_free_address_list(addresses);
4407	addresses = NULL;
4408	return (found_match);
4409}
4410
4411static inline bool
4412necp_socket_is_connected(struct inpcb *inp)
4413{
4414	return (inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING));
4415}
4416
4417necp_kernel_policy_id
4418necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
4419{
4420	struct socket *so = NULL;
4421	necp_kernel_policy_filter filter_control_unit = 0;
4422	struct necp_kernel_socket_policy *matched_policy = NULL;
4423	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
4424	necp_kernel_policy_result service_action = 0;
4425	necp_kernel_policy_service service = { 0, 0 };
4426
4427	struct necp_socket_info info;
4428
4429	if (inp == NULL) {
4430		return (NECP_KERNEL_POLICY_ID_NONE);
4431	}
4432
4433	so = inp->inp_socket;
4434
4435	// Don't lock. Possible race condition, but we don't want the performance hit.
4436	if (necp_kernel_socket_policies_count == 0 ||
4437		(!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0)) {
4438		if (necp_drop_all_order > 0) {
4439			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4440			inp->inp_policyresult.policy_gencount = 0;
4441			inp->inp_policyresult.flowhash = 0;
4442			inp->inp_policyresult.results.filter_control_unit = 0;
4443			if (necp_pass_loopback > 0 &&
4444				necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL)) {
4445				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
4446			} else {
4447				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
4448			}
4449		}
4450		return (NECP_KERNEL_POLICY_ID_NONE);
4451	}
4452
4453	// Check for loopback exception
4454	if (necp_pass_loopback > 0 &&
4455		necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL)) {
4456		// Mark socket as a pass
4457		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4458		inp->inp_policyresult.policy_gencount = 0;
4459		inp->inp_policyresult.flowhash = 0;
4460		inp->inp_policyresult.results.filter_control_unit = 0;
4461		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
4462		return (NECP_KERNEL_POLICY_ID_NONE);
4463	}
4464
4465	// Lock
4466	lck_rw_lock_shared(&necp_kernel_policy_lock);
4467
4468	necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, override_bound_interface, &info);
4469
4470	// Check info
4471	u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
4472	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
4473		inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
4474		inp->inp_policyresult.flowhash == flowhash) {
4475		// If already matched this socket on this generation of table, skip
4476
4477		// Unlock
4478		lck_rw_done(&necp_kernel_policy_lock);
4479
4480		return (inp->inp_policyresult.policy_id);
4481	}
4482
4483	// Match socket to policy
4484	matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)], &info, &filter_control_unit, &service_action, &service);
4485	// If the socket matched a scoped service policy, mark as Drop if not registered.
4486	// This covers the cases in which a service is required (on demand) but hasn't started yet.
4487	if ((service_action == NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED ||
4488		 service_action == NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED) &&
4489		service.identifier != 0 &&
4490		service.identifier != NECP_NULL_SERVICE_ID) {
4491		bool service_is_registered = FALSE;
4492		struct necp_service_registration *service_registration = NULL;
4493		LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
4494			if (service.identifier == service_registration->service_id) {
4495				service_is_registered = TRUE;
4496				break;
4497			}
4498		}
4499		if (!service_is_registered) {
4500			// Mark socket as a drop if service is not registered
4501			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4502			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
4503			inp->inp_policyresult.flowhash = flowhash;
4504			inp->inp_policyresult.results.filter_control_unit = 0;
4505			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
4506
4507			if (necp_debug > 1) {
4508				NECPLOG(LOG_DEBUG, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because service is not registered", info.bound_interface_index, info.protocol);
4509			}
4510
4511			// Unlock
4512			lck_rw_done(&necp_kernel_policy_lock);
4513			return (NECP_KERNEL_POLICY_ID_NONE);
4514		}
4515	}
4516	if (matched_policy) {
4517		matched_policy_id = matched_policy->id;
4518		inp->inp_policyresult.policy_id = matched_policy->id;
4519		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
4520		inp->inp_policyresult.flowhash = flowhash;
4521		inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
4522		inp->inp_policyresult.results.result = matched_policy->result;
4523		memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
4524
4525		if (necp_socket_is_connected(inp) &&
4526			(matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
4527			(matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
4528			if (necp_debug) {
4529				NECPLOG(LOG_DEBUG, "Marking socket in state %d as defunct", so->so_state);
4530			}
4531			sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
4532		}
4533
4534		if (necp_debug > 1) {
4535			NECPLOG(LOG_DEBUG, "Socket Policy: (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d", info.bound_interface_index, info.protocol, matched_policy->id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index);
4536		}
4537	} else if (necp_drop_all_order > 0) {
4538		// Mark socket as a drop if set
4539		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4540		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
4541		inp->inp_policyresult.flowhash = flowhash;
4542		inp->inp_policyresult.results.filter_control_unit = 0;
4543		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
4544	} else {
4545		// Mark non-matching socket so we don't re-check it
4546		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4547		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
4548		inp->inp_policyresult.flowhash = flowhash;
4549		inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
4550		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
4551	}
4552
4553	// Unlock
4554	lck_rw_done(&necp_kernel_policy_lock);
4555
4556	return (matched_policy_id);
4557}
4558
4559static bool
4560necp_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)
4561{
4562	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
4563		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
4564			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
4565			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
4566				if (bound_interface_index == cond_bound_interface_index) {
4567					// No match, matches forbidden interface
4568					return (FALSE);
4569				}
4570			} else {
4571				if (bound_interface_index != cond_bound_interface_index) {
4572					// No match, does not match required interface
4573					return (FALSE);
4574				}
4575			}
4576		} else {
4577			if (bound_interface_index != 0) {
4578				// No match, requires a non-bound packet
4579				return (FALSE);
4580			}
4581		}
4582	}
4583
4584	if (kernel_policy->condition_mask == 0) {
4585		return (TRUE);
4586	}
4587
4588	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
4589		if (socket_policy_id != kernel_policy->cond_policy_id) {
4590			// No match, does not match required id
4591			return (FALSE);
4592		}
4593	}
4594
4595	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
4596		if (last_interface_index != kernel_policy->cond_last_interface_index) {
4597			return (FALSE);
4598		}
4599	}
4600
4601	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4602		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4603			if (protocol == kernel_policy->cond_protocol) {
4604				// No match, matches forbidden protocol
4605				return (FALSE);
4606			}
4607		} else {
4608			if (protocol != kernel_policy->cond_protocol) {
4609				// No match, does not match required protocol
4610				return (FALSE);
4611			}
4612		}
4613	}
4614
4615	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
4616		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4617			bool inRange = necp_is_addr_in_range((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, (struct sockaddr *)&kernel_policy->cond_local_end);
4618			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4619				if (inRange) {
4620					return (FALSE);
4621				}
4622			} else {
4623				if (!inRange) {
4624					return (FALSE);
4625				}
4626			}
4627		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4628			bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, kernel_policy->cond_local_prefix);
4629			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4630				if (inSubnet) {
4631					return (FALSE);
4632				}
4633			} else {
4634				if (!inSubnet) {
4635					return (FALSE);
4636				}
4637			}
4638		}
4639	}
4640
4641	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
4642		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4643			bool inRange = necp_is_addr_in_range((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, (struct sockaddr *)&kernel_policy->cond_remote_end);
4644			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4645				if (inRange) {
4646					return (FALSE);
4647				}
4648			} else {
4649				if (!inRange) {
4650					return (FALSE);
4651				}
4652			}
4653		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4654			bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, kernel_policy->cond_remote_prefix);
4655			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4656				if (inSubnet) {
4657					return (FALSE);
4658				}
4659			} else {
4660				if (!inSubnet) {
4661					return (FALSE);
4662				}
4663			}
4664		}
4665	}
4666
4667	return (TRUE);
4668}
4669
4670static inline struct necp_kernel_ip_output_policy *
4671necp_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)
4672{
4673	u_int32_t skip_order = 0;
4674	u_int32_t skip_session_order = 0;
4675	int i;
4676	struct necp_kernel_ip_output_policy *matched_policy = NULL;
4677	struct necp_kernel_ip_output_policy **policy_search_array = necp_kernel_ip_output_policies_map[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(socket_policy_id)];
4678	if (policy_search_array != NULL) {
4679		for (i = 0; policy_search_array[i] != NULL; i++) {
4680			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
4681				// We've hit a drop all rule
4682				break;
4683			}
4684			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
4685				// Done skipping
4686				skip_order = 0;
4687				skip_session_order = 0;
4688			}
4689			if (skip_order) {
4690				if (policy_search_array[i]->order < skip_order) {
4691					// Skip this policy
4692					continue;
4693				} else {
4694					// Done skipping
4695					skip_order = 0;
4696					skip_session_order = 0;
4697				}
4698			} else if (skip_session_order) {
4699				// Skip this policy
4700				continue;
4701			}
4702			if (necp_ip_output_check_policy(policy_search_array[i], socket_policy_id, bound_interface_index, last_interface_index, protocol, local_addr, remote_addr)) {
4703				// Passed all tests, found a match
4704				matched_policy = policy_search_array[i];
4705
4706				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
4707					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
4708					skip_session_order = policy_search_array[i]->session_order + 1;
4709					continue;
4710				}
4711
4712				break;
4713			}
4714		}
4715	}
4716
4717	return (matched_policy);
4718}
4719
4720necp_kernel_policy_id
4721necp_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)
4722{
4723	struct ip *ip = NULL;
4724	int hlen = sizeof(struct ip);
4725	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
4726	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
4727	struct necp_kernel_ip_output_policy *matched_policy = NULL;
4728	u_int16_t protocol = 0;
4729	u_int32_t bound_interface_index = 0;
4730	u_int32_t last_interface_index = 0;
4731	union necp_sockaddr_union local_addr;
4732	union necp_sockaddr_union remote_addr;
4733
4734	if (result) {
4735		*result = 0;
4736	}
4737
4738	if (result_parameter) {
4739		memset(result_parameter, 0, sizeof(*result_parameter));
4740	}
4741
4742	if (packet == NULL) {
4743		return (NECP_KERNEL_POLICY_ID_NONE);
4744	}
4745
4746	socket_policy_id = necp_get_policy_id_from_packet(packet);
4747
4748	// Exit early for an empty list
4749	// Don't lock. Possible race condition, but we don't want the performance hit.
4750	if (necp_kernel_ip_output_policies_count == 0 ||
4751		((socket_policy_id == NECP_KERNEL_POLICY_ID_NONE) && necp_kernel_ip_output_policies_non_id_count == 0)) {
4752		if (necp_drop_all_order > 0) {
4753			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4754			if (result) {
4755				if ((necp_pass_loopback > 0 &&
4756					 necp_is_loopback(NULL, NULL, NULL, packet)) ||
4757					(necp_pass_keepalives > 0 &&
4758					 necp_get_is_keepalive_from_packet(packet))) {
4759					*result = NECP_KERNEL_POLICY_RESULT_PASS;
4760				} else {
4761					*result = NECP_KERNEL_POLICY_RESULT_DROP;
4762				}
4763			}
4764		}
4765
4766		return (matched_policy_id);
4767	}
4768
4769	// Check for loopback exception
4770	if ((necp_pass_loopback > 0 &&
4771		 necp_is_loopback(NULL, NULL, NULL, packet)) ||
4772		(necp_pass_keepalives > 0 &&
4773		 necp_get_is_keepalive_from_packet(packet))) {
4774		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4775		if (result) {
4776			*result = NECP_KERNEL_POLICY_RESULT_PASS;
4777		}
4778		return (matched_policy_id);
4779	}
4780
4781	last_interface_index = necp_get_last_interface_index_from_packet(packet);
4782
4783	// Process packet to get relevant fields
4784	ip = mtod(packet, struct ip *);
4785#ifdef _IP_VHL
4786	hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
4787#else
4788	hlen = ip->ip_hl << 2;
4789#endif
4790
4791	protocol = ip->ip_p;
4792
4793	if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
4794		(ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
4795		ipoa->ipoa_boundif != IFSCOPE_NONE) {
4796		bound_interface_index = ipoa->ipoa_boundif;
4797	}
4798
4799	local_addr.sin.sin_family = AF_INET;
4800	local_addr.sin.sin_len = sizeof(struct sockaddr_in);
4801	memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
4802
4803	remote_addr.sin.sin_family = AF_INET;
4804	remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
4805	memcpy(&((struct sockaddr_in *)&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
4806
4807	switch (protocol) {
4808		case IPPROTO_TCP: {
4809			struct tcphdr th;
4810			if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
4811				m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
4812				((struct sockaddr_in *)&local_addr)->sin_port = th.th_sport;
4813				((struct sockaddr_in *)&remote_addr)->sin_port = th.th_dport;
4814			}
4815			break;
4816		}
4817		case IPPROTO_UDP: {
4818			struct udphdr uh;
4819			if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
4820				m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
4821				((struct sockaddr_in *)&local_addr)->sin_port = uh.uh_sport;
4822				((struct sockaddr_in *)&remote_addr)->sin_port = uh.uh_dport;
4823			}
4824			break;
4825		}
4826		default: {
4827			((struct sockaddr_in *)&local_addr)->sin_port = 0;
4828			((struct sockaddr_in *)&remote_addr)->sin_port = 0;
4829			break;
4830		}
4831	}
4832
4833	// Match packet to policy
4834	lck_rw_lock_shared(&necp_kernel_policy_lock);
4835	matched_policy = necp_ip_output_find_policy_match_locked(socket_policy_id, bound_interface_index, last_interface_index, protocol, &local_addr, &remote_addr);
4836	if (matched_policy) {
4837		matched_policy_id = matched_policy->id;
4838		if (result) {
4839			*result = matched_policy->result;
4840		}
4841
4842		if (result_parameter) {
4843			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
4844		}
4845
4846		if (necp_debug > 1) {
4847			NECPLOG(LOG_DEBUG, "IP Output: (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d", socket_policy_id, bound_interface_index, last_interface_index, protocol, matched_policy->id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index);
4848		}
4849	} else if (necp_drop_all_order > 0) {
4850		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4851		if (result) {
4852			*result = NECP_KERNEL_POLICY_RESULT_DROP;
4853		}
4854	}
4855
4856	lck_rw_done(&necp_kernel_policy_lock);
4857
4858	return (matched_policy_id);
4859}
4860
4861necp_kernel_policy_id
4862necp_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)
4863{
4864	struct ip6_hdr *ip6 = NULL;
4865	int next = -1;
4866	int offset = 0;
4867	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
4868	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
4869	struct necp_kernel_ip_output_policy *matched_policy = NULL;
4870	u_int16_t protocol = 0;
4871	u_int32_t bound_interface_index = 0;
4872	u_int32_t last_interface_index = 0;
4873	union necp_sockaddr_union local_addr;
4874	union necp_sockaddr_union remote_addr;
4875
4876	if (result) {
4877		*result = 0;
4878	}
4879
4880	if (result_parameter) {
4881		memset(result_parameter, 0, sizeof(*result_parameter));
4882	}
4883
4884	if (packet == NULL) {
4885		return (NECP_KERNEL_POLICY_ID_NONE);
4886	}
4887
4888	socket_policy_id = necp_get_policy_id_from_packet(packet);
4889
4890	// Exit early for an empty list
4891	// Don't lock. Possible race condition, but we don't want the performance hit.
4892	if (necp_kernel_ip_output_policies_count == 0 ||
4893		((socket_policy_id == NECP_KERNEL_POLICY_ID_NONE) && necp_kernel_ip_output_policies_non_id_count == 0)) {
4894		if (necp_drop_all_order > 0) {
4895			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4896			if (result) {
4897				if ((necp_pass_loopback > 0 &&
4898					 necp_is_loopback(NULL, NULL, NULL, packet)) ||
4899					(necp_pass_keepalives > 0 &&
4900					 necp_get_is_keepalive_from_packet(packet))) {
4901					*result = NECP_KERNEL_POLICY_RESULT_PASS;
4902				} else {
4903					*result = NECP_KERNEL_POLICY_RESULT_DROP;
4904				}
4905			}
4906		}
4907
4908		return (matched_policy_id);
4909	}
4910
4911	// Check for loopback exception
4912	if ((necp_pass_loopback > 0 &&
4913		 necp_is_loopback(NULL, NULL, NULL, packet)) ||
4914		(necp_pass_keepalives > 0 &&
4915		 necp_get_is_keepalive_from_packet(packet))) {
4916		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4917		if (result) {
4918			*result = NECP_KERNEL_POLICY_RESULT_PASS;
4919		}
4920		return (matched_policy_id);
4921	}
4922
4923	last_interface_index = necp_get_last_interface_index_from_packet(packet);
4924
4925	// Process packet to get relevant fields
4926	ip6 = mtod(packet, struct ip6_hdr *);
4927
4928	if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
4929		(ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
4930		ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
4931		bound_interface_index = ip6oa->ip6oa_boundif;
4932	}
4933
4934	((struct sockaddr_in6 *)&local_addr)->sin6_family = AF_INET6;
4935	((struct sockaddr_in6 *)&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
4936	memcpy(&((struct sockaddr_in6 *)&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
4937
4938	((struct sockaddr_in6 *)&remote_addr)->sin6_family = AF_INET6;
4939	((struct sockaddr_in6 *)&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
4940	memcpy(&((struct sockaddr_in6 *)&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
4941
4942	offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
4943	if (offset >= 0 && packet->m_pkthdr.len >= offset) {
4944		protocol = next;
4945		switch (protocol) {
4946			case IPPROTO_TCP: {
4947				struct tcphdr th;
4948				if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
4949					m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
4950					((struct sockaddr_in6 *)&local_addr)->sin6_port = th.th_sport;
4951					((struct sockaddr_in6 *)&remote_addr)->sin6_port = th.th_dport;
4952				}
4953				break;
4954			}
4955			case IPPROTO_UDP: {
4956				struct udphdr uh;
4957				if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
4958					m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
4959					((struct sockaddr_in6 *)&local_addr)->sin6_port = uh.uh_sport;
4960					((struct sockaddr_in6 *)&remote_addr)->sin6_port = uh.uh_dport;
4961				}
4962				break;
4963			}
4964			default: {
4965				((struct sockaddr_in6 *)&local_addr)->sin6_port = 0;
4966				((struct sockaddr_in6 *)&remote_addr)->sin6_port = 0;
4967				break;
4968			}
4969		}
4970	}
4971
4972	// Match packet to policy
4973	lck_rw_lock_shared(&necp_kernel_policy_lock);
4974	matched_policy = necp_ip_output_find_policy_match_locked(socket_policy_id, bound_interface_index, last_interface_index, protocol, &local_addr, &remote_addr);
4975	if (matched_policy) {
4976		matched_policy_id = matched_policy->id;
4977		if (result) {
4978			*result = matched_policy->result;
4979		}
4980
4981		if (result_parameter) {
4982			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
4983		}
4984
4985		if (necp_debug > 1) {
4986			NECPLOG(LOG_DEBUG, "IP6 Output: (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d", socket_policy_id, bound_interface_index, last_interface_index, protocol, matched_policy->id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index);
4987		}
4988	} else if (necp_drop_all_order > 0) {
4989		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4990		if (result) {
4991			*result = NECP_KERNEL_POLICY_RESULT_DROP;
4992		}
4993	}
4994
4995	lck_rw_done(&necp_kernel_policy_lock);
4996
4997	return (matched_policy_id);
4998}
4999
5000// Utilities
5001static bool
5002necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
5003{
5004	int cmp = 0;
5005
5006	if (addr == NULL || range_start == NULL || range_end == NULL) {
5007		return (FALSE);
5008	}
5009
5010	/* Must be greater than or equal to start */
5011	cmp = necp_addr_compare(addr, range_start, 1);
5012	if (cmp != 0 && cmp != 1) {
5013		return (FALSE);
5014	}
5015
5016	/* Must be less than or equal to end */
5017	cmp = necp_addr_compare(addr, range_end, 1);
5018	if (cmp != 0 && cmp != -1) {
5019		return (FALSE);
5020	}
5021
5022	return (TRUE);
5023}
5024
5025static bool
5026necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
5027{
5028	int cmp = 0;
5029
5030	if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
5031		return (FALSE);
5032	}
5033
5034	/* Must be greater than or equal to start */
5035	cmp = necp_addr_compare(inner_range_start, range_start, 1);
5036	if (cmp != 0 && cmp != 1) {
5037		return (FALSE);
5038	}
5039
5040	/* Must be less than or equal to end */
5041	cmp = necp_addr_compare(inner_range_end, range_end, 1);
5042	if (cmp != 0 && cmp != -1) {
5043		return (FALSE);
5044	}
5045
5046	return (TRUE);
5047}
5048
5049static bool
5050necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
5051{
5052	if (addr == NULL || subnet_addr == NULL) {
5053		return (FALSE);
5054	}
5055
5056	if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
5057		return (FALSE);
5058	}
5059
5060	switch (addr->sa_family) {
5061		case AF_INET: {
5062			if (satosin(subnet_addr)->sin_port != 0 &&
5063				satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
5064				return (FALSE);
5065			}
5066			return (necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix));
5067		}
5068		case AF_INET6: {
5069			if (satosin6(subnet_addr)->sin6_port != 0 &&
5070				satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
5071				return (FALSE);
5072			}
5073			if (satosin6(addr)->sin6_scope_id &&
5074				satosin6(subnet_addr)->sin6_scope_id &&
5075				satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
5076				return (FALSE);
5077			}
5078			return (necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix));
5079		}
5080		default: {
5081			return (FALSE);
5082		}
5083	}
5084
5085	return (FALSE);
5086}
5087
5088/*
5089 * Return values:
5090 * -1: sa1 < sa2
5091 * 0: sa1 == sa2
5092 * 1: sa1 > sa2
5093 * 2: Not comparable or error
5094 */
5095static int
5096necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
5097{
5098	int result = 0;
5099	int port_result = 0;
5100
5101	if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
5102		return (2);
5103	}
5104
5105	if (sa1->sa_len == 0) {
5106		return (0);
5107	}
5108
5109	switch (sa1->sa_family) {
5110		case AF_INET: {
5111			if (sa1->sa_len != sizeof(struct sockaddr_in)) {
5112				return (2);
5113			}
5114
5115			result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
5116
5117			if (check_port) {
5118				if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
5119					port_result = -1;
5120				} else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
5121					port_result = 1;
5122				}
5123
5124				if (result == 0) {
5125					result = port_result;
5126				} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
5127					return (2);
5128				}
5129			}
5130
5131			break;
5132		}
5133		case AF_INET6: {
5134			if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
5135				return (2);
5136			}
5137
5138			if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
5139				return (2);
5140			}
5141
5142			result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
5143
5144			if (check_port) {
5145				if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
5146					port_result = -1;
5147				} else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
5148					port_result = 1;
5149				}
5150
5151				if (result == 0) {
5152					result = port_result;
5153				} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
5154					return (2);
5155				}
5156			}
5157
5158			break;
5159		}
5160		default: {
5161			result = memcmp(sa1, sa2, sa1->sa_len);
5162			break;
5163		}
5164	}
5165
5166	if (result < 0) {
5167		result = (-1);
5168	} else if (result > 0) {
5169		result = (1);
5170	}
5171
5172	return (result);
5173}
5174
5175static bool
5176necp_buffer_compare_with_bit_prefix(u_int8_t *p1, u_int8_t *p2, u_int32_t bits)
5177{
5178	u_int8_t mask;
5179
5180	/* Handle null pointers */
5181	if (p1 == NULL || p2 == NULL) {
5182		return (p1 == p2);
5183	}
5184
5185	while (bits >= 8) {
5186		if (*p1++ != *p2++) {
5187			return (FALSE);
5188		}
5189		bits -= 8;
5190	}
5191
5192	if (bits > 0) {
5193		mask = ~((1<<(8-bits))-1);
5194		if ((*p1 & mask) != (*p2 & mask)) {
5195			return (FALSE);
5196		}
5197	}
5198	return (TRUE);
5199}
5200
5201// Socket operations
5202#define NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH 253
5203
5204static bool
5205necp_set_socket_attribute(u_int8_t *buffer, size_t buffer_length, u_int8_t type, char **buffer_p)
5206{
5207	int error = 0;
5208	int cursor = 0;
5209	size_t string_size = 0;
5210	char *local_string = NULL;
5211	u_int8_t *value = NULL;
5212
5213	cursor = necp_buffer_find_tlv(buffer, buffer_length, 0, type, 0);
5214	if (cursor < 0) {
5215		// This will clear out the parameter
5216		goto done;
5217	}
5218
5219	string_size = necp_buffer_get_tlv_length(buffer, cursor);
5220	if (string_size == 0 || string_size > NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH) {
5221		// This will clear out the parameter
5222		goto done;
5223	}
5224
5225	MALLOC(local_string, char *, string_size + 1, M_NECP, M_WAITOK);
5226	if (local_string == NULL) {
5227		NECPLOG(LOG_ERR, "Failed to allocate a socket attribute buffer (size %d)", string_size);
5228		goto fail;
5229	}
5230
5231	value = necp_buffer_get_tlv_value(buffer, cursor, NULL);
5232	if (value == NULL) {
5233		NECPLOG0(LOG_ERR, "Failed to get socket attribute");
5234		goto fail;
5235	}
5236
5237	memcpy(local_string, value, string_size);
5238	local_string[string_size] = 0;
5239
5240done:
5241	if (*buffer_p != NULL) {
5242		FREE(*buffer_p, M_NECP);
5243		*buffer_p = NULL;
5244	}
5245
5246	*buffer_p = local_string;
5247	return (0);
5248fail:
5249	if (local_string != NULL) {
5250		FREE(local_string, M_NECP);
5251	}
5252	return (error);
5253}
5254
5255errno_t
5256necp_set_socket_attributes(struct socket *so, struct sockopt *sopt)
5257{
5258	int error = 0;
5259	u_int8_t *buffer = NULL;
5260	struct inpcb *inp = sotoinpcb(so);
5261
5262	size_t valsize = sopt->sopt_valsize;
5263	if (valsize == 0 ||
5264		valsize > ((sizeof(u_int8_t) + sizeof(size_t) + NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH) * 2)) {
5265		goto done;
5266	}
5267
5268	MALLOC(buffer, u_int8_t *, valsize, M_NECP, M_WAITOK);
5269	if (buffer == NULL) {
5270		goto done;
5271	}
5272
5273	error = sooptcopyin(sopt, buffer, valsize, 0);
5274	if (error) {
5275		goto done;
5276	}
5277
5278	error = necp_set_socket_attribute(buffer, valsize, NECP_TLV_ATTRIBUTE_DOMAIN, &inp->inp_necp_attributes.inp_domain);
5279	if (error) {
5280		NECPLOG0(LOG_ERR, "Could not set domain TLV for socket attributes");
5281		goto done;
5282	}
5283
5284	error = necp_set_socket_attribute(buffer, valsize, NECP_TLV_ATTRIBUTE_ACCOUNT, &inp->inp_necp_attributes.inp_account);
5285	if (error) {
5286		NECPLOG0(LOG_ERR, "Could not set account TLV for socket attributes");
5287		goto done;
5288	}
5289
5290	if (necp_debug) {
5291		NECPLOG(LOG_DEBUG, "Set on socket: Domain %s, Account %s", inp->inp_necp_attributes.inp_domain, inp->inp_necp_attributes.inp_account);
5292	}
5293done:
5294	if (buffer != NULL) {
5295		FREE(buffer, M_NECP);
5296	}
5297
5298	return (error);
5299}
5300
5301errno_t
5302necp_get_socket_attributes(struct socket *so, struct sockopt *sopt)
5303{
5304	int error = 0;
5305	u_int8_t *buffer = NULL;
5306	u_int8_t *cursor = NULL;
5307	size_t valsize = 0;
5308	struct inpcb *inp = sotoinpcb(so);
5309
5310	if (inp->inp_necp_attributes.inp_domain != NULL) {
5311		valsize += sizeof(u_int8_t) + sizeof(size_t) + strlen(inp->inp_necp_attributes.inp_domain);
5312	}
5313	if (inp->inp_necp_attributes.inp_account != NULL) {
5314		valsize += sizeof(u_int8_t) + sizeof(size_t) + strlen(inp->inp_necp_attributes.inp_account);
5315	}
5316	if (valsize == 0) {
5317		goto done;
5318	}
5319
5320	MALLOC(buffer, u_int8_t *, valsize, M_NECP, M_WAITOK);
5321	if (buffer == NULL) {
5322		goto done;
5323	}
5324
5325	cursor = buffer;
5326	if (inp->inp_necp_attributes.inp_domain != NULL) {
5327		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ATTRIBUTE_DOMAIN, strlen(inp->inp_necp_attributes.inp_domain), inp->inp_necp_attributes.inp_domain);
5328	}
5329
5330	if (inp->inp_necp_attributes.inp_account != NULL) {
5331		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ATTRIBUTE_ACCOUNT, strlen(inp->inp_necp_attributes.inp_account), inp->inp_necp_attributes.inp_account);
5332	}
5333
5334	error = sooptcopyout(sopt, buffer, valsize);
5335	if (error) {
5336		goto done;
5337	}
5338done:
5339	if (buffer != NULL) {
5340		FREE(buffer, M_NECP);
5341	}
5342
5343	return (error);
5344}
5345
5346static bool
5347necp_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)
5348{
5349	u_int32_t verifyifindex = interface ? interface->if_index : 0;
5350	bool allowed_to_receive = TRUE;
5351	struct necp_socket_info info;
5352	u_int32_t flowhash = 0;
5353	necp_kernel_policy_result service_action = 0;
5354	necp_kernel_policy_service service = { 0, 0 };
5355
5356	if (return_policy_id) {
5357		*return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
5358	}
5359
5360	if (inp == NULL) {
5361		goto done;
5362	}
5363
5364	// Don't lock. Possible race condition, but we don't want the performance hit.
5365	if (necp_kernel_socket_policies_count == 0 ||
5366		(!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0)) {
5367		if (necp_drop_all_order > 0) {
5368			if (necp_pass_loopback > 0 &&
5369				necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL)) {
5370				allowed_to_receive = TRUE;
5371			} else {
5372				allowed_to_receive = FALSE;
5373			}
5374		}
5375		goto done;
5376	}
5377
5378	// If this socket is connected, or we are not taking addresses into account, try to reuse last result
5379	if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
5380		bool policies_have_changed = FALSE;
5381		lck_rw_lock_shared(&necp_kernel_policy_lock);
5382		if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
5383			policies_have_changed = TRUE;
5384		}
5385		lck_rw_done(&necp_kernel_policy_lock);
5386
5387		if (!policies_have_changed) {
5388			if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
5389				inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
5390				(inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && interface &&
5391				inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
5392				allowed_to_receive = FALSE;
5393			} else if (return_policy_id) {
5394				*return_policy_id = inp->inp_policyresult.policy_id;
5395			}
5396			goto done;
5397		}
5398	}
5399
5400	// Check for loopback exception
5401	if (necp_pass_loopback > 0 &&
5402		necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL)) {
5403		allowed_to_receive = TRUE;
5404		goto done;
5405	}
5406
5407	// Actually calculate policy result
5408	lck_rw_lock_shared(&necp_kernel_policy_lock);
5409	necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, &info);
5410
5411	flowhash = necp_socket_calc_flowhash_locked(&info);
5412	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
5413		inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
5414		inp->inp_policyresult.flowhash == flowhash) {
5415		if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
5416			inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
5417			(inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && interface &&
5418			inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
5419			allowed_to_receive = FALSE;
5420		} else if (return_policy_id) {
5421			*return_policy_id = inp->inp_policyresult.policy_id;
5422		}
5423		lck_rw_done(&necp_kernel_policy_lock);
5424		goto done;
5425	}
5426
5427	struct necp_kernel_socket_policy *matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)], &info, NULL, &service_action, &service);
5428	if (matched_policy != NULL) {
5429		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
5430			matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
5431			(matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && interface &&
5432			matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
5433			((service_action == NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED ||
5434			  service_action == NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED) &&
5435			 service.identifier != 0 && service.identifier != NECP_NULL_SERVICE_ID)) {
5436			allowed_to_receive = FALSE;
5437		} else if (return_policy_id) {
5438			*return_policy_id = matched_policy->id;
5439		}
5440		lck_rw_done(&necp_kernel_policy_lock);
5441
5442		if (necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) {
5443			NECPLOG(LOG_DEBUG, "Socket Send/Recv Policy: Policy %d Allowed %d", return_policy_id ? *return_policy_id : 0, allowed_to_receive);
5444		}
5445		goto done;
5446	} else if (necp_drop_all_order > 0) {
5447		allowed_to_receive = FALSE;
5448	}
5449
5450	lck_rw_done(&necp_kernel_policy_lock);
5451
5452done:
5453	return (allowed_to_receive);
5454}
5455
5456bool
5457necp_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)
5458{
5459	struct sockaddr_in local;
5460	struct sockaddr_in remote;
5461	local.sin_family = remote.sin_family = AF_INET;
5462	local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
5463	local.sin_port = local_port;
5464	remote.sin_port = remote_port;
5465	memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
5466	memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
5467
5468	return (necp_socket_is_allowed_to_send_recv_internal(inp, (struct sockaddr *)&local, (struct sockaddr *)&remote, interface, return_policy_id));
5469}
5470
5471bool
5472necp_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)
5473{
5474	struct sockaddr_in6 local;
5475	struct sockaddr_in6 remote;
5476	local.sin6_family = remote.sin6_family = AF_INET6;
5477	local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
5478	local.sin6_port = local_port;
5479	remote.sin6_port = remote_port;
5480	memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
5481	memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
5482
5483	return (necp_socket_is_allowed_to_send_recv_internal(inp, (struct sockaddr *)&local, (struct sockaddr *)&remote, interface, return_policy_id));
5484}
5485
5486bool
5487necp_socket_is_allowed_to_send_recv(struct inpcb *inp, necp_kernel_policy_id *return_policy_id)
5488{
5489	return (necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, NULL, return_policy_id));
5490}
5491
5492int
5493necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id)
5494{
5495	if (packet == NULL || inp == NULL) {
5496		return (EINVAL);
5497	}
5498
5499	// Mark ID for Pass and IP Tunnel
5500	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
5501		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
5502	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
5503		inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
5504		packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
5505	} else {
5506		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
5507	}
5508	packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
5509
5510	return (0);
5511}
5512
5513int
5514necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
5515{
5516	if (packet == NULL) {
5517		return (EINVAL);
5518	}
5519
5520	// Mark ID for Pass and IP Tunnel
5521	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
5522		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
5523	} else {
5524		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
5525	}
5526
5527	return (0);
5528}
5529
5530int
5531necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
5532{
5533	if (packet == NULL) {
5534		return (EINVAL);
5535	}
5536
5537	// Mark ID for Pass and IP Tunnel
5538	if (interface != NULL) {
5539		packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
5540	}
5541
5542	return (0);
5543}
5544
5545int
5546necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
5547{
5548	if (packet == NULL) {
5549		return (EINVAL);
5550	}
5551
5552	if (is_keepalive) {
5553		packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
5554	} else {
5555		packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
5556	}
5557
5558	return (0);
5559}
5560
5561necp_kernel_policy_id
5562necp_get_policy_id_from_packet(struct mbuf *packet)
5563{
5564	if (packet == NULL) {
5565		return (NECP_KERNEL_POLICY_ID_NONE);
5566	}
5567
5568	return (packet->m_pkthdr.necp_mtag.necp_policy_id);
5569}
5570
5571u_int32_t
5572necp_get_last_interface_index_from_packet(struct mbuf *packet)
5573{
5574	if (packet == NULL) {
5575		return (0);
5576	}
5577
5578	return (packet->m_pkthdr.necp_mtag.necp_last_interface_index);
5579}
5580
5581bool
5582necp_get_is_keepalive_from_packet(struct mbuf *packet)
5583{
5584	if (packet == NULL) {
5585		return (FALSE);
5586	}
5587
5588	return (packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE);
5589}
5590
5591u_int32_t
5592necp_socket_get_content_filter_control_unit(struct socket *so)
5593{
5594	struct inpcb *inp = sotoinpcb(so);
5595
5596	if (inp == NULL) {
5597		return (0);
5598	}
5599	return (inp->inp_policyresult.results.filter_control_unit);
5600}
5601
5602bool
5603necp_socket_should_use_flow_divert(struct inpcb *inp)
5604{
5605	if (inp == NULL) {
5606		return (FALSE);
5607	}
5608
5609	return (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT);
5610}
5611
5612u_int32_t
5613necp_socket_get_flow_divert_control_unit(struct inpcb *inp)
5614{
5615	if (inp == NULL) {
5616		return (0);
5617	}
5618
5619	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
5620		return (inp->inp_policyresult.results.result_parameter.flow_divert_control_unit);
5621	}
5622
5623	return (0);
5624}
5625
5626bool
5627necp_socket_should_rescope(struct inpcb *inp)
5628{
5629	if (inp == NULL) {
5630		return (FALSE);
5631	}
5632
5633	return (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED);
5634}
5635
5636u_int
5637necp_socket_get_rescope_if_index(struct inpcb *inp)
5638{
5639	if (inp == NULL) {
5640		return (0);
5641	}
5642
5643	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
5644		return (inp->inp_policyresult.results.result_parameter.scoped_interface_index);
5645	}
5646
5647	return (0);
5648}
5649
5650ifnet_t
5651necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
5652{
5653	if (result_parameter == NULL) {
5654		return (NULL);
5655	}
5656
5657	return (ifindex2ifnet[result_parameter->tunnel_interface_index]);
5658}
5659
5660bool
5661necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
5662{
5663	bool found_match = FALSE;
5664	errno_t result = 0;
5665	ifaddr_t *addresses = NULL;
5666	union necp_sockaddr_union address_storage;
5667	int i;
5668
5669	if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
5670		return (FALSE);
5671	}
5672
5673	result = ifnet_get_address_list_family(interface, &addresses, family);
5674	if (result != 0) {
5675		NECPLOG(LOG_ERR, "Failed to get address list for %s%d", ifnet_name(interface), ifnet_unit(interface));
5676		return (FALSE);
5677	}
5678
5679	for (i = 0; addresses[i] != NULL; i++) {
5680		ROUTE_RELEASE(new_route);
5681		if (ifaddr_address(addresses[i], &address_storage.sa, sizeof(address_storage)) == 0) {
5682			if (family == AF_INET) {
5683				struct ip *ip = mtod(packet, struct ip *);
5684				if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
5685					struct sockaddr_in *dst4 = (struct sockaddr_in *)(void *)&new_route->ro_dst;
5686					dst4->sin_family = AF_INET;
5687					dst4->sin_len = sizeof(struct sockaddr_in);
5688					dst4->sin_addr = ip->ip_dst;
5689					rtalloc_scoped(new_route, interface->if_index);
5690					if (!ROUTE_UNUSABLE(new_route)) {
5691						found_match = TRUE;
5692						goto done;
5693					}
5694				}
5695			} else if (family == AF_INET6) {
5696				struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
5697				if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
5698					struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)(void *)&new_route->ro_dst;
5699					dst6->sin6_family = AF_INET6;
5700					dst6->sin6_len = sizeof(struct sockaddr_in6);
5701					dst6->sin6_addr = ip6->ip6_dst;
5702					rtalloc_scoped(new_route, interface->if_index);
5703					if (!ROUTE_UNUSABLE(new_route)) {
5704						found_match = TRUE;
5705						goto done;
5706					}
5707				}
5708			}
5709		}
5710	}
5711
5712done:
5713	ifnet_free_address_list(addresses);
5714	addresses = NULL;
5715	return (found_match);
5716}
5717
5718static bool
5719necp_addr_is_loopback(struct sockaddr *address)
5720{
5721	if (address == NULL) {
5722		return (FALSE);
5723	}
5724
5725	if (address->sa_family == AF_INET) {
5726		return (ntohl(((struct sockaddr_in *)(void *)address)->sin_addr.s_addr) == INADDR_LOOPBACK);
5727	} else if (address->sa_family == AF_INET6) {
5728		return IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)(void *)address)->sin6_addr);
5729	}
5730
5731	return (FALSE);
5732}
5733
5734static bool
5735necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet)
5736{
5737	// Note: This function only checks for the loopback addresses.
5738	// In the future, we may want to expand to also allow any traffic
5739	// going through the loopback interface, but until then, this
5740	// check is cheaper.
5741
5742	if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
5743		return (TRUE);
5744	}
5745
5746	if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
5747		return (TRUE);
5748	}
5749
5750	if (inp != NULL) {
5751		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
5752			return (TRUE);
5753		}
5754		if (inp->inp_vflag & INP_IPV4) {
5755			if (ntohl(inp->inp_laddr.s_addr) == INADDR_LOOPBACK ||
5756				ntohl(inp->inp_faddr.s_addr) == INADDR_LOOPBACK) {
5757				return (TRUE);
5758			}
5759		} else if (inp->inp_vflag & INP_IPV6) {
5760			if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
5761				IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
5762				return (TRUE);
5763			}
5764		}
5765	}
5766
5767	if (packet != NULL) {
5768		struct ip *ip = mtod(packet, struct ip *);
5769		if (ip->ip_v == 4) {
5770			if (ntohl(ip->ip_src.s_addr) == INADDR_LOOPBACK) {
5771				return (TRUE);
5772			}
5773			if (ntohl(ip->ip_dst.s_addr) == INADDR_LOOPBACK) {
5774				return (TRUE);
5775			}
5776		} else if (ip->ip_v == 6) {
5777			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
5778			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
5779				return (TRUE);
5780			}
5781			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
5782				return (TRUE);
5783			}
5784		}
5785	}
5786
5787	return (FALSE);
5788}
5789