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