2 * Copyright (c) 2015-2017 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
31 #include <kern/thread_call.h>
32 #include <kern/zalloc.h>
34 #include <libkern/OSMalloc.h>
37 #include <net/if_var.h>
38 #include <net/net_api_stats.h>
40 #include <net/network_agent.h>
41 #include <net/ntstat.h>
43 #include <netinet/in_pcb.h>
44 #include <netinet/ip.h>
45 #include <netinet/ip6.h>
46 #include <netinet/mp_pcb.h>
47 #include <netinet/tcp_cc.h>
48 #include <netinet/tcp_fsm.h>
49 #include <netinet/tcp_cache.h>
50 #include <netinet6/in6_var.h>
52 #include <sys/domain.h>
53 #include <sys/file_internal.h>
54 #include <sys/kauth.h>
55 #include <sys/kernel.h>
56 #include <sys/malloc.h>
59 #include <sys/protosw.h>
60 #include <sys/queue.h>
61 #include <sys/socket.h>
62 #include <sys/socketvar.h>
63 #include <sys/sysproto.h>
64 #include <sys/systm.h>
65 #include <sys/types.h>
66 #include <sys/codesign.h>
67 #include <libkern/section_keywords.h>
71 * NECP Client Architecture
72 * ------------------------------------------------
73 * See <net/necp.c> for a discussion on NECP database architecture.
75 * Each client of NECP provides a set of parameters for a connection or network state
76 * evaluation, on which NECP policy evaluation is run. This produces a policy result
77 * which can be accessed by the originating process, along with events for when policies
78 * results have changed.
80 * ------------------------------------------------
82 * ------------------------------------------------
83 * A process opens an NECP file descriptor using necp_open(). This is a very simple
84 * file descriptor, upon which the process may do the following operations:
85 * - necp_client_action(...), to add/remove/query clients
86 * - kqueue, to watch for readable events
87 * - close(), to close the client session and release all clients
89 * Client objects are allocated structures that hang off of the file descriptor. Each
91 * - Client ID, a UUID that references the client across the system
92 * - Parameters, a buffer of TLVs that describe the client's connection parameters,
93 * such as the remote and local endpoints, interface requirements, etc.
94 * - Result, a buffer of TLVs containing the current policy evaluation for the client.
95 * This result will be updated whenever a network change occurs that impacts the
96 * policy result for that client.
102 * ==================================
104 * +--------------+ +--------------+ +--------------+
105 * | Client ID | | Client ID | | Client ID |
106 * | ---- | | ---- | | ---- |
107 * | Parameters | | Parameters | | Parameters |
108 * | ---- | | ---- | | ---- |
109 * | Result | | Result | | Result |
110 * +--------------+ +--------------+ +--------------+
112 * ------------------------------------------------
114 * ------------------------------------------------
115 * - Add. Input parameters as a buffer of TLVs, and output a client ID. Allocates a
116 * new client structure on the file descriptor.
117 * - Remove. Input a client ID. Removes a client structure from the file descriptor.
118 * - Copy Parameters. Input a client ID, and output parameter TLVs.
119 * - Copy Result. Input a client ID, and output result TLVs. Alternatively, input empty
120 * client ID and get next unread client result.
121 * - Copy List. List all client IDs.
123 * ------------------------------------------------
124 * Client Policy Evaluation
125 * ------------------------------------------------
126 * Policies are evaluated for clients upon client creation, and upon update events,
127 * which are network/agent/policy changes coalesced by a timer.
129 * The policy evaluation goes through the following steps:
130 * 1. Parse client parameters.
131 * 2. Select a scoped interface if applicable. This involves using require/prohibit
132 * parameters, along with the local address, to select the most appropriate interface
133 * if not explicitly set by the client parameters.
134 * 3. Run NECP application-level policy evalution
135 * 4. Set policy result into client result buffer.
137 * ------------------------------------------------
139 * ------------------------------------------------
140 * If necp_open() is called with the NECP_OPEN_FLAG_OBSERVER flag, and the process
141 * passes the necessary privilege check, the fd is allowed to use necp_client_action()
142 * to copy client state attached to the file descriptors of other processes, and to
143 * list all client IDs on the system.
146 extern u_int32_t necp_debug
;
148 // proc_best_name() is declared here in advance of it landing in a header file.
149 // See comment in kern_proc.c
150 extern char *proc_best_name(proc_t p
);
152 static int noop_read(struct fileproc
*, struct uio
*, int, vfs_context_t
);
153 static int noop_write(struct fileproc
*, struct uio
*, int, vfs_context_t
);
154 static int noop_ioctl(struct fileproc
*, unsigned long, caddr_t
,
156 static int necpop_select(struct fileproc
*, int, void *, vfs_context_t
);
157 static int necpop_close(struct fileglob
*, vfs_context_t
);
158 static int necpop_kqfilter(struct fileproc
*, struct knote
*,
159 struct kevent_internal_s
*kev
, vfs_context_t
);
162 static int necp_timeout_microseconds
= 1000 * 100; // 100ms
163 static int necp_timeout_leeway_microseconds
= 1000 * 500; // 500ms
165 static int necp_client_fd_count
= 0;
166 static int necp_observer_fd_count
= 0;
167 static int necp_client_count
= 0;
168 static int necp_socket_flow_count
= 0;
169 static int necp_if_flow_count
= 0;
170 static int necp_observer_message_limit
= 256;
172 SYSCTL_INT(_net_necp
, NECPCTL_CLIENT_FD_COUNT
, client_fd_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_client_fd_count
, 0, "");
173 SYSCTL_INT(_net_necp
, NECPCTL_OBSERVER_FD_COUNT
, observer_fd_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_observer_fd_count
, 0, "");
174 SYSCTL_INT(_net_necp
, NECPCTL_CLIENT_COUNT
, client_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_client_count
, 0, "");
175 SYSCTL_INT(_net_necp
, NECPCTL_SOCKET_FLOW_COUNT
, socket_flow_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_socket_flow_count
, 0, "");
176 SYSCTL_INT(_net_necp
, NECPCTL_IF_FLOW_COUNT
, if_flow_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_if_flow_count
, 0, "");
177 SYSCTL_INT(_net_necp
, NECPCTL_OBSERVER_MESSAGE_LIMIT
, observer_message_limit
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_observer_message_limit
, 256, "");
179 #define NECP_MAX_CLIENT_LIST_SIZE 1024 * 1024 // 1MB
181 extern int tvtohz(struct timeval
*);
182 extern unsigned int get_maxmtu(struct rtentry
*);
185 #define NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR 0x00001
186 #define NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR 0x00002
187 #define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF 0x00004
188 #define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF 0x00008
189 #define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE 0x00010
190 #define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE 0x00020
191 #define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT 0x00040
192 #define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT 0x00080
193 #define NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT 0x00100
194 #define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE 0x00200
195 #define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE 0x00400
196 #define NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE 0x00800
197 #define NECP_PARSED_PARAMETERS_FIELD_FLAGS 0x01000
198 #define NECP_PARSED_PARAMETERS_FIELD_IP_PROTOCOL 0x02000
199 #define NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_PID 0x04000
200 #define NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_UUID 0x08000
201 #define NECP_PARSED_PARAMETERS_FIELD_TRAFFIC_CLASS 0x10000
202 #define NECP_PARSED_PARAMETERS_FIELD_LOCAL_PORT 0x20000
204 #define NECP_MAX_PARSED_PARAMETERS 16
205 struct necp_client_parsed_parameters
{
206 u_int32_t valid_fields
;
208 union necp_sockaddr_union local_addr
;
209 union necp_sockaddr_union remote_addr
;
210 u_int32_t required_interface_index
;
211 char prohibited_interfaces
[IFXNAMSIZ
][NECP_MAX_PARSED_PARAMETERS
];
212 u_int8_t required_interface_type
;
213 u_int8_t prohibited_interface_types
[NECP_MAX_PARSED_PARAMETERS
];
214 struct necp_client_parameter_netagent_type required_netagent_types
[NECP_MAX_PARSED_PARAMETERS
];
215 struct necp_client_parameter_netagent_type prohibited_netagent_types
[NECP_MAX_PARSED_PARAMETERS
];
216 struct necp_client_parameter_netagent_type preferred_netagent_types
[NECP_MAX_PARSED_PARAMETERS
];
217 uuid_t required_netagents
[NECP_MAX_PARSED_PARAMETERS
];
218 uuid_t prohibited_netagents
[NECP_MAX_PARSED_PARAMETERS
];
219 uuid_t preferred_netagents
[NECP_MAX_PARSED_PARAMETERS
];
220 u_int16_t ip_protocol
;
222 uuid_t effective_uuid
;
223 u_int32_t traffic_class
;
227 necp_find_matching_interface_index(struct necp_client_parsed_parameters
*parsed_parameters
,
228 u_int
*return_ifindex
);
231 necp_ifnet_matches_local_address(struct ifnet
*ifp
, struct sockaddr
*sa
);
234 necp_ifnet_matches_parameters(struct ifnet
*ifp
,
235 struct necp_client_parsed_parameters
*parsed_parameters
,
236 u_int32_t
*preferred_count
, bool ignore_require_if
);
238 static const struct fileops necp_fd_ops
= {
239 .fo_type
= DTYPE_NETPOLICY
,
240 .fo_read
= noop_read
,
241 .fo_write
= noop_write
,
242 .fo_ioctl
= noop_ioctl
,
243 .fo_select
= necpop_select
,
244 .fo_close
= necpop_close
,
245 .fo_kqfilter
= necpop_kqfilter
,
249 struct necp_client_assertion
{
250 LIST_ENTRY(necp_client_assertion
) assertion_chain
;
251 uuid_t asserted_netagent
;
254 struct necp_client_flow_header
{
255 struct necp_tlv_header outer_header
;
256 struct necp_tlv_header flags_tlv_header
;
257 u_int32_t flags_value
;
258 struct necp_tlv_header interface_tlv_header
;
259 struct necp_client_result_interface interface_value
;
260 } __attribute__((__packed__
));
262 struct necp_client_flow_protoctl_event_header
{
263 struct necp_tlv_header protoctl_tlv_header
;
264 struct necp_client_flow_protoctl_event protoctl_event
;
265 } __attribute__((__packed__
));
267 struct necp_client_nexus_flow_header
{
268 struct necp_client_flow_header flow_header
;
269 struct necp_tlv_header agent_tlv_header
;
270 struct necp_client_result_netagent agent_value
;
271 struct necp_tlv_header tfo_cookie_tlv_header
;
272 u_int8_t tfo_cookie_value
[NECP_TFO_COOKIE_LEN_MAX
];
273 } __attribute__((__packed__
));
276 RB_ENTRY(necp_client
) link
;
277 RB_ENTRY(necp_client
) global_link
;
278 LIST_ENTRY(necp_client
) collect_stats_chain
;
280 decl_lck_mtx_data(, lock
);
281 decl_lck_mtx_data(, route_lock
);
282 uint32_t reference_count
;
285 unsigned result_read
: 1;
286 unsigned flow_result_read
: 1;
287 unsigned allow_multiple_flows
: 1;
289 unsigned defunct
: 1;
290 unsigned background
: 1;
291 unsigned background_update
: 1;
292 unsigned platform_binary
: 1;
294 size_t result_length
;
295 u_int8_t result
[NECP_MAX_CLIENT_RESULT_SIZE
];
297 necp_policy_id policy_id
;
299 u_int16_t ip_protocol
;
302 LIST_HEAD(_necp_client_flow_list
, necp_client_flow
) flow_list
;
303 LIST_HEAD(_necp_client_assertion_list
, necp_client_assertion
) assertion_list
;
305 struct rtentry
*current_route
;
307 void *interface_handle
;
308 void (*interface_cb
)(void *handle
, int action
, struct necp_client_flow
*flow
);
310 size_t parameters_length
;
311 u_int8_t parameters
[0];
314 #define NECP_CLIENT_LOCK(_c) lck_mtx_lock(&_c->lock)
315 #define NECP_CLIENT_UNLOCK(_c) lck_mtx_unlock(&_c->lock)
316 #define NECP_CLIENT_ASSERT_LOCKED(_c) LCK_MTX_ASSERT(&_c->lock, LCK_MTX_ASSERT_OWNED)
317 #define NECP_CLIENT_ASSERT_UNLOCKED(_c) LCK_MTX_ASSERT(&_c->lock, LCK_MTX_ASSERT_NOTOWNED)
319 #define NECP_CLIENT_ROUTE_LOCK(_c) lck_mtx_lock(&_c->route_lock)
320 #define NECP_CLIENT_ROUTE_UNLOCK(_c) lck_mtx_unlock(&_c->route_lock)
322 static void necp_client_retain_locked(struct necp_client
*client
);
323 static void necp_client_retain(struct necp_client
*client
);
324 static bool necp_client_release_locked(struct necp_client
*client
);
327 necp_client_add_assertion(struct necp_client
*client
, uuid_t netagent_uuid
);
330 necp_client_remove_assertion(struct necp_client
*client
, uuid_t netagent_uuid
);
332 LIST_HEAD(_necp_client_list
, necp_client
);
333 static struct _necp_client_list necp_collect_stats_client_list
;
335 struct necp_client_defunct
{
336 LIST_ENTRY(necp_client_defunct
) chain
;
343 LIST_HEAD(_necp_client_defunct_list
, necp_client_defunct
);
345 static int necp_client_id_cmp(struct necp_client
*client0
, struct necp_client
*client1
);
347 RB_HEAD(_necp_client_tree
, necp_client
);
348 RB_PROTOTYPE_PREV(_necp_client_tree
, necp_client
, link
, necp_client_id_cmp
);
349 RB_GENERATE_PREV(_necp_client_tree
, necp_client
, link
, necp_client_id_cmp
);
351 RB_HEAD(_necp_client_global_tree
, necp_client
);
352 RB_PROTOTYPE_PREV(_necp_client_global_tree
, necp_client
, global_link
, necp_client_id_cmp
);
353 RB_GENERATE_PREV(_necp_client_global_tree
, necp_client
, global_link
, necp_client_id_cmp
);
355 static struct _necp_client_global_tree necp_client_global_tree
;
357 struct necp_client_update
{
358 TAILQ_ENTRY(necp_client_update
) chain
;
362 size_t update_length
;
363 struct necp_client_observer_update update
;
366 struct necp_fd_data
{
367 u_int8_t necp_fd_type
;
368 LIST_ENTRY(necp_fd_data
) chain
;
369 struct _necp_client_tree clients
;
370 TAILQ_HEAD(_necp_client_update_list
, necp_client_update
) update_list
;
374 decl_lck_mtx_data(, fd_lock
);
378 #define NECP_FD_LOCK(_f) lck_mtx_lock(&_f->fd_lock)
379 #define NECP_FD_UNLOCK(_f) lck_mtx_unlock(&_f->fd_lock)
380 #define NECP_FD_ASSERT_LOCKED(_f) LCK_MTX_ASSERT(&_f->fd_lock, LCK_MTX_ASSERT_OWNED)
381 #define NECP_FD_ASSERT_UNLOCKED(_f) LCK_MTX_ASSERT(&_f->fd_lock, LCK_MTX_ASSERT_NOTOWNED)
383 static LIST_HEAD(_necp_fd_list
, necp_fd_data
) necp_fd_list
;
384 static LIST_HEAD(_necp_fd_observer_list
, necp_fd_data
) necp_fd_observer_list
;
386 #define NECP_CLIENT_FD_ZONE_MAX 128
387 #define NECP_CLIENT_FD_ZONE_NAME "necp.clientfd"
389 static unsigned int necp_client_fd_size
; /* size of zone element */
390 static struct zone
*necp_client_fd_zone
; /* zone for necp_fd_data */
392 #define NECP_FLOW_ZONE_MAX 512
393 #define NECP_FLOW_ZONE_NAME "necp.flow"
395 static unsigned int necp_flow_size
; /* size of zone element */
396 static struct zone
*necp_flow_zone
; /* zone for necp_client_flow */
398 static lck_grp_attr_t
*necp_fd_grp_attr
= NULL
;
399 static lck_attr_t
*necp_fd_mtx_attr
= NULL
;
400 static lck_grp_t
*necp_fd_mtx_grp
= NULL
;
402 decl_lck_rw_data(static, necp_fd_lock
);
403 decl_lck_rw_data(static, necp_observer_lock
);
404 decl_lck_rw_data(static, necp_client_tree_lock
);
405 decl_lck_rw_data(static, necp_collect_stats_list_lock
);
407 #define NECP_STATS_LIST_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_collect_stats_list_lock)
408 #define NECP_STATS_LIST_LOCK_SHARED() lck_rw_lock_shared(&necp_collect_stats_list_lock)
409 #define NECP_STATS_LIST_UNLOCK() lck_rw_done(&necp_collect_stats_list_lock)
411 #define NECP_CLIENT_TREE_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_client_tree_lock)
412 #define NECP_CLIENT_TREE_LOCK_SHARED() lck_rw_lock_shared(&necp_client_tree_lock)
413 #define NECP_CLIENT_TREE_UNLOCK() lck_rw_done(&necp_client_tree_lock)
415 #define NECP_FD_LIST_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_fd_lock)
416 #define NECP_FD_LIST_LOCK_SHARED() lck_rw_lock_shared(&necp_fd_lock)
417 #define NECP_FD_LIST_UNLOCK() lck_rw_done(&necp_fd_lock)
419 #define NECP_OBSERVER_LIST_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_observer_lock)
420 #define NECP_OBSERVER_LIST_LOCK_SHARED() lck_rw_lock_shared(&necp_observer_lock)
421 #define NECP_OBSERVER_LIST_UNLOCK() lck_rw_done(&necp_observer_lock)
425 // Take NECP_FD_LIST_LOCK when accessing or modifying the necp_fd_list
426 // Take NECP_CLIENT_TREE_LOCK when accessing or modifying the necp_client_global_tree
427 // Take NECP_STATS_LIST_LOCK when accessing or modifying the necp_collect_stats_client_list
428 // Take NECP_FD_LOCK when accessing or modifying an necp_fd_data entry
429 // Take NECP_CLIENT_LOCK when accessing or modifying a single necp_client
430 // Take NECP_CLIENT_ROUTE_LOCK when accessing or modifying a client's route
432 // Precedence, where 1 is the first lock that must be taken
433 // 1. NECP_FD_LIST_LOCK
434 // 2. NECP_FD_LOCK (any)
435 // 3. NECP_CLIENT_TREE_LOCK
436 // 4. NECP_CLIENT_LOCK (any)
437 // 5. NECP_STATS_LIST_LOCK
438 // 6. NECP_CLIENT_ROUTE_LOCK (any)
440 static thread_call_t necp_client_update_tcall
;
443 /// NECP file descriptor functions
446 noop_read(struct fileproc
*fp
, struct uio
*uio
, int flags
, vfs_context_t ctx
)
448 #pragma unused(fp, uio, flags, ctx)
453 noop_write(struct fileproc
*fp
, struct uio
*uio
, int flags
,
456 #pragma unused(fp, uio, flags, ctx)
461 noop_ioctl(struct fileproc
*fp
, unsigned long com
, caddr_t data
,
464 #pragma unused(fp, com, data, ctx)
469 necp_fd_notify(struct necp_fd_data
*fd_data
, bool locked
)
471 struct selinfo
*si
= &fd_data
->si
;
474 NECP_FD_LOCK(fd_data
);
479 // use a non-zero hint to tell the notification from the
480 // call done in kqueue_scan() which uses 0
481 KNOTE(&si
->si_note
, 1); // notification
484 NECP_FD_UNLOCK(fd_data
);
489 necp_fd_poll(struct necp_fd_data
*fd_data
, int events
, void *wql
, struct proc
*p
, int is_kevent
)
491 #pragma unused(wql, p, is_kevent)
494 u_int want_rx
= events
& (POLLIN
| POLLRDNORM
);
496 if (fd_data
->flags
& NECP_OPEN_FLAG_PUSH_OBSERVER
) {
497 // Push-mode observers are readable when they have a new update
498 if (!TAILQ_EMPTY(&fd_data
->update_list
)) {
502 // Standard fds are readable when some client is unread
503 struct necp_client
*client
= NULL
;
504 bool has_unread_clients
= FALSE
;
505 RB_FOREACH(client
, _necp_client_tree
, &fd_data
->clients
) {
506 NECP_CLIENT_LOCK(client
);
507 if (!client
->result_read
|| !client
->flow_result_read
) {
508 has_unread_clients
= TRUE
;
510 NECP_CLIENT_UNLOCK(client
);
511 if (has_unread_clients
) {
516 if (has_unread_clients
) {
525 static struct necp_client
*
526 necp_client_fd_find_client_and_lock(struct necp_fd_data
*client_fd
, uuid_t client_id
)
528 struct necp_client find
;
529 NECP_FD_ASSERT_LOCKED(client_fd
);
530 uuid_copy(find
.client_id
, client_id
);
531 struct necp_client
*client
= RB_FIND(_necp_client_tree
, &client_fd
->clients
, &find
);
533 if (client
!= NULL
) {
534 NECP_CLIENT_LOCK(client
);
541 necp_client_id_cmp(struct necp_client
*client0
, struct necp_client
*client1
)
543 return (uuid_compare(client0
->client_id
, client1
->client_id
));
547 necpop_select(struct fileproc
*fp
, int which
, void *wql
, vfs_context_t ctx
)
549 #pragma unused(fp, which, wql, ctx)
551 struct necp_fd_data
*fd_data
= NULL
;
556 fd_data
= (struct necp_fd_data
*)fp
->f_fglob
->fg_data
;
557 if (fd_data
== NULL
) {
561 procp
= vfs_context_proc(ctx
);
574 NECP_FD_LOCK(fd_data
);
575 revents
= necp_fd_poll(fd_data
, events
, wql
, procp
, 0);
576 NECP_FD_UNLOCK(fd_data
);
578 return ((events
& revents
) ? 1 : 0);
582 necp_fd_knrdetach(struct knote
*kn
)
584 struct necp_fd_data
*fd_data
= (struct necp_fd_data
*)kn
->kn_hook
;
585 struct selinfo
*si
= &fd_data
->si
;
587 NECP_FD_LOCK(fd_data
);
588 KNOTE_DETACH(&si
->si_note
, kn
);
589 NECP_FD_UNLOCK(fd_data
);
593 necp_fd_knread(struct knote
*kn
, long hint
)
595 #pragma unused(kn, hint)
596 return 1; /* assume we are ready */
600 necp_fd_knrprocess(struct knote
*kn
, struct filt_process_s
*data
, struct kevent_internal_s
*kev
)
603 struct necp_fd_data
*fd_data
;
607 fd_data
= (struct necp_fd_data
*)kn
->kn_hook
;
609 NECP_FD_LOCK(fd_data
);
610 revents
= necp_fd_poll(fd_data
, POLLIN
, NULL
, current_proc(), 1);
611 res
= ((revents
& POLLIN
) != 0);
613 *kev
= kn
->kn_kevent
;
615 NECP_FD_UNLOCK(fd_data
);
620 necp_fd_knrtouch(struct knote
*kn
, struct kevent_internal_s
*kev
)
623 struct necp_fd_data
*fd_data
;
626 fd_data
= (struct necp_fd_data
*)kn
->kn_hook
;
628 NECP_FD_LOCK(fd_data
);
629 if ((kn
->kn_status
& KN_UDATA_SPECIFIC
) == 0)
630 kn
->kn_udata
= kev
->udata
;
631 revents
= necp_fd_poll(fd_data
, POLLIN
, NULL
, current_proc(), 1);
632 NECP_FD_UNLOCK(fd_data
);
634 return ((revents
& POLLIN
) != 0);
637 SECURITY_READ_ONLY_EARLY(struct filterops
) necp_fd_rfiltops
= {
639 .f_detach
= necp_fd_knrdetach
,
640 .f_event
= necp_fd_knread
,
641 .f_touch
= necp_fd_knrtouch
,
642 .f_process
= necp_fd_knrprocess
,
646 necpop_kqfilter(struct fileproc
*fp
, struct knote
*kn
,
647 __unused
struct kevent_internal_s
*kev
, vfs_context_t ctx
)
649 #pragma unused(fp, ctx)
650 struct necp_fd_data
*fd_data
= NULL
;
653 if (kn
->kn_filter
!= EVFILT_READ
) {
654 NECPLOG(LOG_ERR
, "bad filter request %d", kn
->kn_filter
);
655 kn
->kn_flags
= EV_ERROR
;
656 kn
->kn_data
= EINVAL
;
660 fd_data
= (struct necp_fd_data
*)kn
->kn_fp
->f_fglob
->fg_data
;
661 if (fd_data
== NULL
) {
662 NECPLOG0(LOG_ERR
, "No channel for kqfilter");
663 kn
->kn_flags
= EV_ERROR
;
664 kn
->kn_data
= ENOENT
;
668 NECP_FD_LOCK(fd_data
);
669 kn
->kn_filtid
= EVFILTID_NECP_FD
;
670 kn
->kn_hook
= fd_data
;
671 KNOTE_ATTACH(&fd_data
->si
.si_note
, kn
);
673 revents
= necp_fd_poll(fd_data
, POLLIN
, NULL
, current_proc(), 1);
675 NECP_FD_UNLOCK(fd_data
);
677 return ((revents
& POLLIN
) != 0);
682 necp_set_client_defunct(struct necp_client
*client
)
684 bool updated
= FALSE
;
686 u_int32_t value_size
= 0;
688 client
->defunct
= TRUE
;
690 u_int8_t
*flags_pointer
= necp_buffer_get_tlv_value(client
->result
, 0, &value_size
);
691 if (flags_pointer
&& value_size
== sizeof(flags
)) {
692 memcpy(&flags
, flags_pointer
, value_size
);
694 flags
|= NECP_CLIENT_RESULT_FLAG_DEFUNCT
;
696 (void)necp_buffer_write_tlv_if_different(client
->result
, NECP_CLIENT_RESULT_FLAGS
,
697 sizeof(flags
), &flags
, &updated
, client
->result
, sizeof(client
->result
));
704 necp_defunct_client_for_policy(struct necp_client
*client
,
705 struct _necp_client_defunct_list
*defunct_list
)
707 if (!client
->defunct
) {
708 bool needs_defunct
= false;
709 struct necp_client_flow
*search_flow
= NULL
;
710 LIST_FOREACH(search_flow
, &client
->flow_list
, flow_chain
) {
711 if (search_flow
->nexus
&&
712 !uuid_is_null(search_flow
->u
.nexus_agent
) &&
713 search_flow
->requested_nexus
) {
715 // Save defunct values for the nexus
716 if (defunct_list
!= NULL
) {
717 // Sleeping alloc won't fail; copy only what's necessary
718 struct necp_client_defunct
*client_defunct
= _MALLOC(sizeof (struct necp_client_defunct
),
719 M_NECP
, M_WAITOK
| M_ZERO
);
720 uuid_copy(client_defunct
->nexus_agent
, search_flow
->u
.nexus_agent
);
721 uuid_copy(client_defunct
->client_id
, client
->client_id
);
722 client_defunct
->proc_pid
= client
->proc_pid
;
724 // Add to the list provided by caller
725 LIST_INSERT_HEAD(defunct_list
, client_defunct
, chain
);
728 needs_defunct
= true;
733 // Only set defunct if there was some assigned flow
734 client
->defunct
= true;
740 necp_client_free(struct necp_client
*client
)
742 NECP_CLIENT_ASSERT_LOCKED(client
);
744 NECP_CLIENT_UNLOCK(client
);
746 lck_mtx_destroy(&client
->route_lock
, necp_fd_mtx_grp
);
747 lck_mtx_destroy(&client
->lock
, necp_fd_mtx_grp
);
749 FREE(client
, M_NECP
);
753 necp_client_retain_locked(struct necp_client
*client
)
755 NECP_CLIENT_ASSERT_LOCKED(client
);
757 client
->reference_count
++;
758 ASSERT(client
->reference_count
!= 0);
762 necp_client_retain(struct necp_client
*client
)
764 NECP_CLIENT_LOCK(client
);
765 necp_client_retain_locked(client
);
766 NECP_CLIENT_UNLOCK(client
);
770 necp_client_release_locked(struct necp_client
*client
)
772 NECP_CLIENT_ASSERT_LOCKED(client
);
774 uint32_t old_ref
= client
->reference_count
;
776 ASSERT(client
->reference_count
!= 0);
777 if (--client
->reference_count
== 0) {
778 necp_client_free(client
);
781 return (old_ref
== 1);
786 necp_client_update_observer_add_internal(struct necp_fd_data
*observer_fd
, struct necp_client
*client
)
788 NECP_FD_LOCK(observer_fd
);
790 if (observer_fd
->update_count
>= necp_observer_message_limit
) {
791 NECP_FD_UNLOCK(observer_fd
);
795 struct necp_client_update
*client_update
= _MALLOC(sizeof(struct necp_client_update
) + client
->parameters_length
,
796 M_NECP
, M_WAITOK
| M_ZERO
);
797 if (client_update
!= NULL
) {
798 client_update
->update_length
= sizeof(struct necp_client_observer_update
) + client
->parameters_length
;
799 uuid_copy(client_update
->client_id
, client
->client_id
);
800 client_update
->update
.update_type
= NECP_CLIENT_UPDATE_TYPE_PARAMETERS
;
801 memcpy(client_update
->update
.tlv_buffer
, client
->parameters
, client
->parameters_length
);
802 TAILQ_INSERT_TAIL(&observer_fd
->update_list
, client_update
, chain
);
803 observer_fd
->update_count
++;
805 necp_fd_notify(observer_fd
, true);
808 NECP_FD_UNLOCK(observer_fd
);
812 necp_client_update_observer_update_internal(struct necp_fd_data
*observer_fd
, struct necp_client
*client
)
814 NECP_FD_LOCK(observer_fd
);
816 if (observer_fd
->update_count
>= necp_observer_message_limit
) {
817 NECP_FD_UNLOCK(observer_fd
);
821 struct necp_client_update
*client_update
= _MALLOC(sizeof(struct necp_client_update
) + client
->result_length
,
822 M_NECP
, M_WAITOK
| M_ZERO
);
823 if (client_update
!= NULL
) {
824 client_update
->update_length
= sizeof(struct necp_client_observer_update
) + client
->result_length
;
825 uuid_copy(client_update
->client_id
, client
->client_id
);
826 client_update
->update
.update_type
= NECP_CLIENT_UPDATE_TYPE_RESULT
;
827 memcpy(client_update
->update
.tlv_buffer
, client
->result
, client
->result_length
);
828 TAILQ_INSERT_TAIL(&observer_fd
->update_list
, client_update
, chain
);
829 observer_fd
->update_count
++;
831 necp_fd_notify(observer_fd
, true);
834 NECP_FD_UNLOCK(observer_fd
);
838 necp_client_update_observer_remove_internal(struct necp_fd_data
*observer_fd
, struct necp_client
*client
)
840 NECP_FD_LOCK(observer_fd
);
842 if (observer_fd
->update_count
>= necp_observer_message_limit
) {
843 NECP_FD_UNLOCK(observer_fd
);
847 struct necp_client_update
*client_update
= _MALLOC(sizeof(struct necp_client_update
),
848 M_NECP
, M_WAITOK
| M_ZERO
);
849 if (client_update
!= NULL
) {
850 client_update
->update_length
= sizeof(struct necp_client_observer_update
);
851 uuid_copy(client_update
->client_id
, client
->client_id
);
852 client_update
->update
.update_type
= NECP_CLIENT_UPDATE_TYPE_REMOVE
;
853 TAILQ_INSERT_TAIL(&observer_fd
->update_list
, client_update
, chain
);
854 observer_fd
->update_count
++;
856 necp_fd_notify(observer_fd
, true);
859 NECP_FD_UNLOCK(observer_fd
);
863 necp_client_update_observer_add(struct necp_client
*client
)
865 NECP_OBSERVER_LIST_LOCK_SHARED();
867 if (LIST_EMPTY(&necp_fd_observer_list
)) {
868 // No observers, bail
869 NECP_OBSERVER_LIST_UNLOCK();
873 struct necp_fd_data
*observer_fd
= NULL
;
874 LIST_FOREACH(observer_fd
, &necp_fd_observer_list
, chain
) {
875 necp_client_update_observer_add_internal(observer_fd
, client
);
878 NECP_OBSERVER_LIST_UNLOCK();
882 necp_client_update_observer_update(struct necp_client
*client
)
884 NECP_OBSERVER_LIST_LOCK_SHARED();
886 if (LIST_EMPTY(&necp_fd_observer_list
)) {
887 // No observers, bail
888 NECP_OBSERVER_LIST_UNLOCK();
892 struct necp_fd_data
*observer_fd
= NULL
;
893 LIST_FOREACH(observer_fd
, &necp_fd_observer_list
, chain
) {
894 necp_client_update_observer_update_internal(observer_fd
, client
);
897 NECP_OBSERVER_LIST_UNLOCK();
901 necp_client_update_observer_remove(struct necp_client
*client
)
903 NECP_OBSERVER_LIST_LOCK_SHARED();
905 if (LIST_EMPTY(&necp_fd_observer_list
)) {
906 // No observers, bail
907 NECP_OBSERVER_LIST_UNLOCK();
911 struct necp_fd_data
*observer_fd
= NULL
;
912 LIST_FOREACH(observer_fd
, &necp_fd_observer_list
, chain
) {
913 necp_client_update_observer_remove_internal(observer_fd
, client
);
916 NECP_OBSERVER_LIST_UNLOCK();
920 necp_destroy_client(struct necp_client
*client
, pid_t pid
, bool abort
)
922 NECP_CLIENT_ASSERT_UNLOCKED(client
);
924 necp_client_update_observer_remove(client
);
926 NECP_CLIENT_LOCK(client
);
929 NECP_CLIENT_ROUTE_LOCK(client
);
930 if (client
->current_route
!= NULL
) {
931 rtfree(client
->current_route
);
932 client
->current_route
= NULL
;
934 NECP_CLIENT_ROUTE_UNLOCK(client
);
936 // Remove flow assignments
937 struct necp_client_flow
*search_flow
= NULL
;
938 struct necp_client_flow
*temp_flow
= NULL
;
939 LIST_FOREACH_SAFE(search_flow
, &client
->flow_list
, flow_chain
, temp_flow
) {
940 if (search_flow
->nexus
&&
941 !uuid_is_null(search_flow
->u
.nexus_agent
) &&
942 search_flow
->requested_nexus
) {
943 // Note that if we had defuncted the client earlier, this would result in a harmless ENOENT
944 int netagent_error
= netagent_client_message(search_flow
->u
.nexus_agent
, client
->client_id
, pid
,
945 abort
? NETAGENT_MESSAGE_TYPE_ABORT_NEXUS
: NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS
);
946 if (netagent_error
!= 0 && netagent_error
!= ENOENT
) {
947 NECPLOG(LOG_ERR
, "necp_client_remove close nexus error (%d)", netagent_error
);
949 uuid_clear(search_flow
->u
.nexus_agent
);
951 if (search_flow
->assigned_results
!= NULL
) {
952 FREE(search_flow
->assigned_results
, M_NETAGENT
);
953 search_flow
->assigned_results
= NULL
;
955 LIST_REMOVE(search_flow
, flow_chain
);
956 if (search_flow
->socket
) {
957 OSDecrementAtomic(&necp_socket_flow_count
);
959 OSDecrementAtomic(&necp_if_flow_count
);
961 zfree(necp_flow_zone
, search_flow
);
964 // Remove agent assertions
965 struct necp_client_assertion
*search_assertion
= NULL
;
966 struct necp_client_assertion
*temp_assertion
= NULL
;
967 LIST_FOREACH_SAFE(search_assertion
, &client
->assertion_list
, assertion_chain
, temp_assertion
) {
968 int netagent_error
= netagent_client_message(search_assertion
->asserted_netagent
, client
->client_id
, pid
, NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT
);
969 if (netagent_error
!= 0) {
970 NECPLOG((netagent_error
== ENOENT
? LOG_DEBUG
: LOG_ERR
),
971 "necp_client_remove unassert agent error (%d)", netagent_error
);
973 LIST_REMOVE(search_assertion
, assertion_chain
);
974 FREE(search_assertion
, M_NECP
);
977 if (!necp_client_release_locked(client
)) {
978 NECP_CLIENT_UNLOCK(client
);
981 OSDecrementAtomic(&necp_client_count
);
985 necpop_close(struct fileglob
*fg
, vfs_context_t ctx
)
988 struct necp_fd_data
*fd_data
= NULL
;
991 fd_data
= (struct necp_fd_data
*)fg
->fg_data
;
994 if (fd_data
!= NULL
) {
995 struct _necp_client_tree clients_to_close
;
996 RB_INIT(&clients_to_close
);
998 // Remove from list quickly
999 if (fd_data
->flags
& NECP_OPEN_FLAG_PUSH_OBSERVER
) {
1000 NECP_OBSERVER_LIST_LOCK_EXCLUSIVE();
1001 LIST_REMOVE(fd_data
, chain
);
1002 NECP_OBSERVER_LIST_UNLOCK();
1004 NECP_FD_LIST_LOCK_EXCLUSIVE();
1005 LIST_REMOVE(fd_data
, chain
);
1006 NECP_FD_LIST_UNLOCK();
1009 NECP_FD_LOCK(fd_data
);
1010 pid_t pid
= fd_data
->proc_pid
;
1011 struct necp_client
*client
= NULL
;
1012 struct necp_client
*temp_client
= NULL
;
1013 RB_FOREACH_SAFE(client
, _necp_client_tree
, &fd_data
->clients
, temp_client
) {
1014 NECP_CLIENT_TREE_LOCK_EXCLUSIVE();
1015 RB_REMOVE(_necp_client_global_tree
, &necp_client_global_tree
, client
);
1016 NECP_CLIENT_TREE_UNLOCK();
1017 RB_REMOVE(_necp_client_tree
, &fd_data
->clients
, client
);
1018 RB_INSERT(_necp_client_tree
, &clients_to_close
, client
);
1021 struct necp_client_update
*client_update
= NULL
;
1022 struct necp_client_update
*temp_update
= NULL
;
1023 TAILQ_FOREACH_SAFE(client_update
, &fd_data
->update_list
, chain
, temp_update
) {
1024 // Flush pending updates
1025 TAILQ_REMOVE(&fd_data
->update_list
, client_update
, chain
);
1026 FREE(client_update
, M_NECP
);
1028 fd_data
->update_count
= 0;
1031 NECP_FD_UNLOCK(fd_data
);
1033 selthreadclear(&fd_data
->si
);
1035 lck_mtx_destroy(&fd_data
->fd_lock
, necp_fd_mtx_grp
);
1037 if (fd_data
->flags
& NECP_OPEN_FLAG_PUSH_OBSERVER
) {
1038 OSDecrementAtomic(&necp_observer_fd_count
);
1040 OSDecrementAtomic(&necp_client_fd_count
);
1043 zfree(necp_client_fd_zone
, fd_data
);
1046 RB_FOREACH_SAFE(client
, _necp_client_tree
, &clients_to_close
, temp_client
) {
1047 RB_REMOVE(_necp_client_tree
, &clients_to_close
, client
);
1048 necp_destroy_client(client
, pid
, true);
1055 /// NECP client utilities
1058 necp_address_is_wildcard(const union necp_sockaddr_union
* const addr
)
1060 return ((addr
->sa
.sa_family
== AF_INET
&& addr
->sin
.sin_addr
.s_addr
== INADDR_ANY
) ||
1061 (addr
->sa
.sa_family
== AF_INET6
&& IN6_IS_ADDR_UNSPECIFIED(&addr
->sin6
.sin6_addr
)));
1065 necp_find_fd_data(int fd
, struct necp_fd_data
**fd_data
)
1067 proc_t p
= current_proc();
1068 struct fileproc
*fp
= NULL
;
1071 proc_fdlock_spin(p
);
1072 if ((error
= fp_lookup(p
, fd
, &fp
, 1)) != 0) {
1075 if (fp
->f_fglob
->fg_ops
->fo_type
!= DTYPE_NETPOLICY
) {
1076 fp_drop(p
, fd
, fp
, 1);
1080 *fd_data
= (struct necp_fd_data
*)fp
->f_fglob
->fg_data
;
1089 necp_client_add_socket_flow(struct necp_client
*client
, struct inpcb
*inp
)
1091 struct necp_client_flow
*new_flow
= zalloc(necp_flow_zone
);
1092 if (new_flow
== NULL
) {
1093 NECPLOG0(LOG_ERR
, "Failed to allocate socket flow");
1097 memset(new_flow
, 0, sizeof(*new_flow
));
1099 new_flow
->socket
= TRUE
;
1100 new_flow
->u
.socket_handle
= inp
;
1101 new_flow
->u
.cb
= inp
->necp_cb
;
1103 OSIncrementAtomic(&necp_socket_flow_count
);
1105 LIST_INSERT_HEAD(&client
->flow_list
, new_flow
, flow_chain
);
1109 necp_client_add_interface_flow(struct necp_client
*client
, uint32_t interface_index
)
1111 struct necp_client_flow
*new_flow
= zalloc(necp_flow_zone
);
1112 if (new_flow
== NULL
) {
1113 NECPLOG0(LOG_ERR
, "Failed to allocate interface flow");
1117 memset(new_flow
, 0, sizeof(*new_flow
));
1119 // Neither nexus nor socket
1120 new_flow
->interface_index
= interface_index
;
1121 new_flow
->u
.socket_handle
= client
->interface_handle
;
1122 new_flow
->u
.cb
= client
->interface_cb
;
1124 OSIncrementAtomic(&necp_if_flow_count
);
1126 LIST_INSERT_HEAD(&client
->flow_list
, new_flow
, flow_chain
);
1130 necp_client_add_interface_flow_if_needed(struct necp_client
*client
, uint32_t interface_index
)
1132 if (!client
->allow_multiple_flows
||
1133 interface_index
== IFSCOPE_NONE
) {
1134 // Interface not set, or client not allowed to use this mode
1138 struct necp_client_flow
*flow
= NULL
;
1139 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
1140 if (!flow
->nexus
&& !flow
->socket
&& flow
->interface_index
== interface_index
) {
1141 // Already have the flow
1142 flow
->invalid
= FALSE
;
1144 flow
->u
.socket_handle
= client
->interface_handle
;
1145 flow
->u
.cb
= client
->interface_cb
;
1150 necp_client_add_interface_flow(client
, interface_index
);
1154 necp_client_flow_is_viable(proc_t proc
, struct necp_client
*client
,
1155 struct necp_client_flow
*flow
)
1157 struct necp_aggregate_result result
;
1158 bool ignore_address
= (client
->allow_multiple_flows
&& !flow
->nexus
&& !flow
->socket
);
1160 flow
->necp_flow_flags
= 0;
1161 int error
= necp_application_find_policy_match_internal(proc
, client
->parameters
,
1162 (u_int32_t
)client
->parameters_length
,
1163 &result
, &flow
->necp_flow_flags
,
1164 flow
->interface_index
,
1165 &flow
->local_addr
, &flow
->remote_addr
, NULL
, ignore_address
);
1167 return (error
== 0 &&
1168 result
.routed_interface_index
!= IFSCOPE_NONE
&&
1169 result
.routing_result
!= NECP_KERNEL_POLICY_RESULT_DROP
);
1173 necp_client_update_flows(proc_t proc
, struct necp_client
*client
)
1175 bool client_updated
= FALSE
;
1176 struct necp_client_flow
*flow
= NULL
;
1177 struct necp_client_flow
*temp_flow
= NULL
;
1178 LIST_FOREACH_SAFE(flow
, &client
->flow_list
, flow_chain
, temp_flow
) {
1179 // Check policy result for flow
1180 int old_flags
= flow
->necp_flow_flags
;
1181 bool viable
= necp_client_flow_is_viable(proc
, client
, flow
);
1183 // TODO: Defunct nexus flows that are blocked by policy
1185 if (flow
->viable
!= viable
) {
1186 flow
->viable
= viable
;
1187 client_updated
= TRUE
;
1190 if ((old_flags
& (NECP_CLIENT_RESULT_FLAG_HAS_IPV4
| NECP_CLIENT_RESULT_FLAG_HAS_IPV6
)) !=
1191 (flow
->necp_flow_flags
& (NECP_CLIENT_RESULT_FLAG_HAS_IPV4
| NECP_CLIENT_RESULT_FLAG_HAS_IPV6
))) {
1192 client_updated
= TRUE
;
1195 if (flow
->viable
&& client_updated
&& (flow
->socket
|| (!flow
->socket
&& !flow
->nexus
)) && flow
->u
.cb
) {
1196 flow
->u
.cb(flow
->u
.socket_handle
, NECP_CLIENT_CBACTION_VIABLE
, flow
);
1199 if (!flow
->viable
|| flow
->invalid
) {
1200 if (client_updated
&& (flow
->socket
|| (!flow
->socket
&& !flow
->nexus
)) && flow
->u
.cb
) {
1201 flow
->u
.cb(flow
->u
.socket_handle
, NECP_CLIENT_CBACTION_NONVIABLE
, flow
);
1203 // The callback might change the viable-flag of the
1204 // flow depending on its policy. Thus, we need to
1205 // check again the flags after the callback.
1209 // Handle flows that no longer match
1210 if (!flow
->viable
|| flow
->invalid
) {
1211 // Drop them as long as they aren't assigned data
1212 if (!flow
->requested_nexus
&& !flow
->assigned
) {
1213 if (flow
->assigned_results
!= NULL
) {
1214 FREE(flow
->assigned_results
, M_NETAGENT
);
1215 flow
->assigned_results
= NULL
;
1216 client_updated
= TRUE
;
1218 LIST_REMOVE(flow
, flow_chain
);
1220 OSDecrementAtomic(&necp_socket_flow_count
);
1222 OSDecrementAtomic(&necp_if_flow_count
);
1224 zfree(necp_flow_zone
, flow
);
1229 return (client_updated
);
1233 necp_client_mark_all_nonsocket_flows_as_invalid(struct necp_client
*client
)
1235 struct necp_client_flow
*flow
= NULL
;
1236 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
1237 if (!flow
->socket
) { // Socket flows are not marked as invalid
1238 flow
->invalid
= TRUE
;
1244 necp_netagent_applies_to_client(__unused
struct necp_client
*client
,
1245 const struct necp_client_parsed_parameters
*parameters
,
1246 uuid_t netagent_uuid
, bool allow_nexus
,
1247 uint32_t interface_index
, u_int16_t interface_flags
)
1249 #pragma unused(interface_index, interface_flags)
1250 bool applies
= FALSE
;
1251 u_int32_t flags
= netagent_get_flags(netagent_uuid
);
1252 if (!(flags
& NETAGENT_FLAG_REGISTERED
)) {
1253 // Unregistered agents never apply
1258 (flags
& NETAGENT_FLAG_NEXUS_PROVIDER
)) {
1259 // Hide nexus providers unless allowed
1260 // Direct interfaces and direct policies are allowed to use a nexus
1261 // Delegate interfaces or re-scoped interfaces are not allowed
1265 if (flags
& NETAGENT_FLAG_SPECIFIC_USE_ONLY
) {
1266 // Specific use agents only apply when required
1267 bool required
= FALSE
;
1268 if (parameters
!= NULL
) {
1269 // Check required agent UUIDs
1270 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1271 if (uuid_is_null(parameters
->required_netagents
[i
])) {
1274 if (uuid_compare(parameters
->required_netagents
[i
], netagent_uuid
) == 0) {
1281 // Check required agent types
1282 bool fetched_type
= FALSE
;
1283 char netagent_domain
[NETAGENT_DOMAINSIZE
];
1284 char netagent_type
[NETAGENT_TYPESIZE
];
1285 memset(&netagent_domain
, 0, NETAGENT_DOMAINSIZE
);
1286 memset(&netagent_type
, 0, NETAGENT_TYPESIZE
);
1288 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1289 if (strlen(parameters
->required_netagent_types
[i
].netagent_domain
) == 0 ||
1290 strlen(parameters
->required_netagent_types
[i
].netagent_type
) == 0) {
1294 if (!fetched_type
) {
1295 if (netagent_get_agent_domain_and_type(netagent_uuid
, netagent_domain
, netagent_type
)) {
1296 fetched_type
= TRUE
;
1302 if ((strlen(parameters
->required_netagent_types
[i
].netagent_domain
) == 0 ||
1303 strncmp(netagent_domain
, parameters
->required_netagent_types
[i
].netagent_domain
, NETAGENT_DOMAINSIZE
) == 0) &&
1304 (strlen(parameters
->required_netagent_types
[i
].netagent_type
) == 0 ||
1305 strncmp(netagent_type
, parameters
->required_netagent_types
[i
].netagent_type
, NETAGENT_TYPESIZE
) == 0)) {
1323 necp_client_add_agent_flows_for_interface(struct necp_client
*client
,
1324 const struct necp_client_parsed_parameters
*parsed_parameters
,
1327 if (ifp
!= NULL
&& ifp
->if_agentids
!= NULL
) {
1328 for (u_int32_t i
= 0; i
< ifp
->if_agentcount
; i
++) {
1329 if (uuid_is_null(ifp
->if_agentids
[i
])) {
1332 u_int16_t if_flags
= nstat_ifnet_to_flags(ifp
);
1333 // Relies on the side effect that nexus agents that apply will create flows
1334 (void)necp_netagent_applies_to_client(client
, parsed_parameters
, ifp
->if_agentids
[i
], TRUE
, ifp
->if_index
, if_flags
);
1340 necp_client_address_is_valid(struct sockaddr
*address
)
1342 if (address
->sa_family
== AF_INET
) {
1343 return (address
->sa_len
== sizeof(struct sockaddr_in
));
1344 } else if (address
->sa_family
== AF_INET6
) {
1345 return (address
->sa_len
== sizeof(struct sockaddr_in6
));
1352 necp_client_parse_parameters(u_int8_t
*parameters
,
1353 u_int32_t parameters_size
,
1354 struct necp_client_parsed_parameters
*parsed_parameters
)
1359 u_int32_t num_prohibited_interfaces
= 0;
1360 u_int32_t num_prohibited_interface_types
= 0;
1361 u_int32_t num_required_agents
= 0;
1362 u_int32_t num_prohibited_agents
= 0;
1363 u_int32_t num_preferred_agents
= 0;
1364 u_int32_t num_required_agent_types
= 0;
1365 u_int32_t num_prohibited_agent_types
= 0;
1366 u_int32_t num_preferred_agent_types
= 0;
1368 if (parsed_parameters
== NULL
) {
1372 memset(parsed_parameters
, 0, sizeof(struct necp_client_parsed_parameters
));
1374 while ((offset
+ sizeof(struct necp_tlv_header
)) <= parameters_size
) {
1375 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
1376 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
1378 if (length
> (parameters_size
- (offset
+ sizeof(struct necp_tlv_header
)))) {
1379 // If the length is larger than what can fit in the remaining parameters size, bail
1380 NECPLOG(LOG_ERR
, "Invalid TLV length (%u)", length
);
1385 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
1386 if (value
!= NULL
) {
1388 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE
: {
1389 if (length
<= IFXNAMSIZ
&& length
> 0) {
1390 ifnet_t bound_interface
= NULL
;
1391 char interface_name
[IFXNAMSIZ
];
1392 memcpy(interface_name
, value
, length
);
1393 interface_name
[length
- 1] = 0; // Make sure the string is NULL terminated
1394 if (ifnet_find_by_name(interface_name
, &bound_interface
) == 0) {
1395 parsed_parameters
->required_interface_index
= bound_interface
->if_index
;
1396 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF
;
1397 ifnet_release(bound_interface
);
1402 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS
: {
1403 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
1404 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
1405 if (necp_client_address_is_valid(&address_struct
->address
.sa
)) {
1406 memcpy(&parsed_parameters
->local_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
1407 if (!necp_address_is_wildcard(&parsed_parameters
->local_addr
)) {
1408 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR
;
1410 if ((parsed_parameters
->local_addr
.sa
.sa_family
== AF_INET
&& parsed_parameters
->local_addr
.sin
.sin_port
) ||
1411 (parsed_parameters
->local_addr
.sa
.sa_family
== AF_INET6
&& parsed_parameters
->local_addr
.sin6
.sin6_port
)) {
1412 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_LOCAL_PORT
;
1418 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT
: {
1419 if (length
>= sizeof(struct necp_client_endpoint
)) {
1420 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
1421 if (necp_client_address_is_valid(&endpoint
->u
.sa
)) {
1422 memcpy(&parsed_parameters
->local_addr
, &endpoint
->u
.sa
, sizeof(union necp_sockaddr_union
));
1423 if (!necp_address_is_wildcard(&parsed_parameters
->local_addr
)) {
1424 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR
;
1426 if ((parsed_parameters
->local_addr
.sa
.sa_family
== AF_INET
&& parsed_parameters
->local_addr
.sin
.sin_port
) ||
1427 (parsed_parameters
->local_addr
.sa
.sa_family
== AF_INET6
&& parsed_parameters
->local_addr
.sin6
.sin6_port
)) {
1428 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_LOCAL_PORT
;
1434 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS
: {
1435 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
1436 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
1437 if (necp_client_address_is_valid(&address_struct
->address
.sa
)) {
1438 memcpy(&parsed_parameters
->remote_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
1439 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR
;
1444 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT
: {
1445 if (length
>= sizeof(struct necp_client_endpoint
)) {
1446 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
1447 if (necp_client_address_is_valid(&endpoint
->u
.sa
)) {
1448 memcpy(&parsed_parameters
->remote_addr
, &endpoint
->u
.sa
, sizeof(union necp_sockaddr_union
));
1449 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR
;
1454 case NECP_CLIENT_PARAMETER_PROHIBIT_INTERFACE
: {
1455 if (num_prohibited_interfaces
>= NECP_MAX_PARSED_PARAMETERS
) {
1458 if (length
<= IFXNAMSIZ
&& length
> 0) {
1459 memcpy(parsed_parameters
->prohibited_interfaces
[num_prohibited_interfaces
], value
, length
);
1460 parsed_parameters
->prohibited_interfaces
[num_prohibited_interfaces
][length
- 1] = 0; // Make sure the string is NULL terminated
1461 num_prohibited_interfaces
++;
1462 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF
;
1466 case NECP_CLIENT_PARAMETER_REQUIRE_IF_TYPE
: {
1467 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
) {
1470 if (length
>= sizeof(u_int8_t
)) {
1471 memcpy(&parsed_parameters
->required_interface_type
, value
, sizeof(u_int8_t
));
1472 if (parsed_parameters
->required_interface_type
) {
1473 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
;
1478 case NECP_CLIENT_PARAMETER_PROHIBIT_IF_TYPE
: {
1479 if (num_prohibited_interface_types
>= NECP_MAX_PARSED_PARAMETERS
) {
1482 if (length
>= sizeof(u_int8_t
)) {
1483 memcpy(&parsed_parameters
->prohibited_interface_types
[num_prohibited_interface_types
], value
, sizeof(u_int8_t
));
1484 num_prohibited_interface_types
++;
1485 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE
;
1489 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT
: {
1490 if (num_required_agents
>= NECP_MAX_PARSED_PARAMETERS
) {
1493 if (length
>= sizeof(uuid_t
)) {
1494 memcpy(&parsed_parameters
->required_netagents
[num_required_agents
], value
, sizeof(uuid_t
));
1495 num_required_agents
++;
1496 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT
;
1500 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT
: {
1501 if (num_prohibited_agents
>= NECP_MAX_PARSED_PARAMETERS
) {
1504 if (length
>= sizeof(uuid_t
)) {
1505 memcpy(&parsed_parameters
->prohibited_netagents
[num_prohibited_agents
], value
, sizeof(uuid_t
));
1506 num_prohibited_agents
++;
1507 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT
;
1511 case NECP_CLIENT_PARAMETER_PREFER_AGENT
: {
1512 if (num_preferred_agents
>= NECP_MAX_PARSED_PARAMETERS
) {
1515 if (length
>= sizeof(uuid_t
)) {
1516 memcpy(&parsed_parameters
->preferred_netagents
[num_preferred_agents
], value
, sizeof(uuid_t
));
1517 num_preferred_agents
++;
1518 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT
;
1522 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE
: {
1523 if (num_required_agent_types
>= NECP_MAX_PARSED_PARAMETERS
) {
1526 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
1527 memcpy(&parsed_parameters
->required_netagent_types
[num_required_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
1528 num_required_agent_types
++;
1529 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE
;
1533 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT_TYPE
: {
1534 if (num_prohibited_agent_types
>= NECP_MAX_PARSED_PARAMETERS
) {
1537 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
1538 memcpy(&parsed_parameters
->prohibited_netagent_types
[num_prohibited_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
1539 num_prohibited_agent_types
++;
1540 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE
;
1544 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE
: {
1545 if (num_preferred_agent_types
>= NECP_MAX_PARSED_PARAMETERS
) {
1548 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
1549 memcpy(&parsed_parameters
->preferred_netagent_types
[num_preferred_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
1550 num_preferred_agent_types
++;
1551 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE
;
1555 case NECP_CLIENT_PARAMETER_FLAGS
: {
1556 if (length
>= sizeof(u_int32_t
)) {
1557 memcpy(&parsed_parameters
->flags
, value
, sizeof(parsed_parameters
->flags
));
1558 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_FLAGS
;
1562 case NECP_CLIENT_PARAMETER_IP_PROTOCOL
: {
1563 if (length
>= sizeof(parsed_parameters
->ip_protocol
)) {
1564 memcpy(&parsed_parameters
->ip_protocol
, value
, sizeof(parsed_parameters
->ip_protocol
));
1565 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_IP_PROTOCOL
;
1569 case NECP_CLIENT_PARAMETER_PID
: {
1570 if (length
>= sizeof(parsed_parameters
->effective_pid
)) {
1571 memcpy(&parsed_parameters
->effective_pid
, value
, sizeof(parsed_parameters
->effective_pid
));
1572 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_PID
;
1576 case NECP_CLIENT_PARAMETER_APPLICATION
: {
1577 if (length
>= sizeof(parsed_parameters
->effective_uuid
)) {
1578 memcpy(&parsed_parameters
->effective_uuid
, value
, sizeof(parsed_parameters
->effective_uuid
));
1579 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_UUID
;
1583 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS
: {
1584 if (length
>= sizeof(parsed_parameters
->traffic_class
)) {
1585 memcpy(&parsed_parameters
->traffic_class
, value
, sizeof(parsed_parameters
->traffic_class
));
1586 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_TRAFFIC_CLASS
;
1597 offset
+= sizeof(struct necp_tlv_header
) + length
;
1604 necp_client_parse_result(u_int8_t
*result
,
1605 u_int32_t result_size
,
1606 union necp_sockaddr_union
*local_address
,
1607 union necp_sockaddr_union
*remote_address
)
1612 while ((offset
+ sizeof(struct necp_tlv_header
)) <= result_size
) {
1613 u_int8_t type
= necp_buffer_get_tlv_type(result
, offset
);
1614 u_int32_t length
= necp_buffer_get_tlv_length(result
, offset
);
1616 if (length
> 0 && (offset
+ sizeof(struct necp_tlv_header
) + length
) <= result_size
) {
1617 u_int8_t
*value
= necp_buffer_get_tlv_value(result
, offset
, NULL
);
1618 if (value
!= NULL
) {
1620 case NECP_CLIENT_RESULT_LOCAL_ENDPOINT
: {
1621 if (length
>= sizeof(struct necp_client_endpoint
)) {
1622 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
1623 if (local_address
!= NULL
&& necp_client_address_is_valid(&endpoint
->u
.sa
)) {
1624 memcpy(local_address
, &endpoint
->u
.sa
, endpoint
->u
.sa
.sa_len
);
1629 case NECP_CLIENT_RESULT_REMOTE_ENDPOINT
: {
1630 if (length
>= sizeof(struct necp_client_endpoint
)) {
1631 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
1632 if (remote_address
!= NULL
&& necp_client_address_is_valid(&endpoint
->u
.sa
)) {
1633 memcpy(remote_address
, &endpoint
->u
.sa
, endpoint
->u
.sa
.sa_len
);
1645 offset
+= sizeof(struct necp_tlv_header
) + length
;
1652 necp_client_register_socket_flow(pid_t pid
, uuid_t client_id
, struct inpcb
*inp
)
1655 bool found_client
= FALSE
;
1657 NECP_CLIENT_TREE_LOCK_SHARED();
1659 struct necp_client find
;
1660 uuid_copy(find
.client_id
, client_id
);
1661 struct necp_client
*client
= RB_FIND(_necp_client_global_tree
, &necp_client_global_tree
, &find
);
1662 if (client
!= NULL
) {
1663 NECP_CLIENT_LOCK(client
);
1665 if (!pid
|| client
->proc_pid
== pid
) {
1666 // Found the right client!
1667 found_client
= TRUE
;
1668 necp_client_add_socket_flow(client
, inp
);
1671 NECP_CLIENT_UNLOCK(client
);
1674 NECP_CLIENT_TREE_UNLOCK();
1676 if (!found_client
) {
1680 * Count the sockets that have the NECP client UUID set
1682 struct socket
*so
= inp
->inp_socket
;
1683 if (!(so
->so_flags1
& SOF1_HAS_NECP_CLIENT_UUID
)) {
1684 so
->so_flags1
|= SOF1_HAS_NECP_CLIENT_UUID
;
1685 INC_ATOMIC_INT64_LIM(net_api_stats
.nas_socket_necp_clientuuid_total
);
1693 necp_client_add_multipath_cb(struct necp_client
*client
, struct mppcb
*mpp
)
1695 struct necp_client_flow
*flow
= NULL
;
1697 client
->interface_handle
= mpp
;
1698 client
->interface_cb
= mpp
->necp_cb
;
1700 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
1701 if (flow
->nexus
|| flow
->socket
) {
1705 flow
->u
.socket_handle
= mpp
;
1706 flow
->u
.cb
= mpp
->necp_cb
;
1708 if (flow
->viable
&& flow
->u
.cb
) {
1709 flow
->u
.cb(mpp
, NECP_CLIENT_CBACTION_INITIAL
, flow
);
1715 necp_client_register_multipath_cb(pid_t pid
, uuid_t client_id
, struct mppcb
*mpp
)
1718 bool found_client
= FALSE
;
1720 NECP_CLIENT_TREE_LOCK_SHARED();
1722 struct necp_client find
;
1723 uuid_copy(find
.client_id
, client_id
);
1724 struct necp_client
*client
= RB_FIND(_necp_client_global_tree
, &necp_client_global_tree
, &find
);
1725 if (client
!= NULL
) {
1726 NECP_CLIENT_LOCK(client
);
1728 if (!pid
|| client
->proc_pid
== pid
) {
1729 // Found the right client!
1730 found_client
= TRUE
;
1731 necp_client_add_multipath_cb(client
, mpp
);
1734 NECP_CLIENT_UNLOCK(client
);
1737 NECP_CLIENT_TREE_UNLOCK();
1739 if (!found_client
) {
1746 #define NETAGENT_DOMAIN_NETEXT "NetworkExtension"
1747 #define NETAGENT_TYPE_PATHCTRL "PathController"
1750 necp_client_unregister_socket_flow(uuid_t client_id
, void *handle
)
1753 struct necp_fd_data
*client_fd
= NULL
;
1754 bool found_client
= FALSE
;
1755 bool client_updated
= FALSE
;
1757 NECP_FD_LIST_LOCK_SHARED();
1758 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
1759 NECP_FD_LOCK(client_fd
);
1761 struct necp_client
*client
= necp_client_fd_find_client_and_lock(client_fd
, client_id
);
1762 if (client
!= NULL
) {
1763 // Found the right client!
1764 found_client
= TRUE
;
1766 // Remove flow assignment
1767 struct necp_client_flow
*search_flow
= NULL
;
1768 struct necp_client_flow
*temp_flow
= NULL
;
1769 LIST_FOREACH_SAFE(search_flow
, &client
->flow_list
, flow_chain
, temp_flow
) {
1770 if (search_flow
->socket
&& search_flow
->u
.socket_handle
== handle
) {
1771 if (search_flow
->assigned_results
!= NULL
) {
1772 FREE(search_flow
->assigned_results
, M_NETAGENT
);
1773 search_flow
->assigned_results
= NULL
;
1775 client_updated
= TRUE
;
1776 LIST_REMOVE(search_flow
, flow_chain
);
1777 OSDecrementAtomic(&necp_socket_flow_count
);
1778 zfree(necp_flow_zone
, search_flow
);
1782 NECP_CLIENT_UNLOCK(client
);
1785 if (client_updated
) {
1786 client
->flow_result_read
= FALSE
;
1787 necp_fd_notify(client_fd
, true);
1789 NECP_FD_UNLOCK(client_fd
);
1795 NECP_FD_LIST_UNLOCK();
1797 if (!found_client
) {
1805 necp_client_unregister_multipath_cb(uuid_t client_id
, void *handle
)
1808 bool found_client
= FALSE
;
1810 NECP_CLIENT_TREE_LOCK_SHARED();
1812 struct necp_client find
;
1813 uuid_copy(find
.client_id
, client_id
);
1814 struct necp_client
*client
= RB_FIND(_necp_client_global_tree
, &necp_client_global_tree
, &find
);
1815 if (client
!= NULL
) {
1816 NECP_CLIENT_LOCK(client
);
1818 // Found the right client!
1819 found_client
= TRUE
;
1821 // Remove flow assignment
1822 struct necp_client_flow
*search_flow
= NULL
;
1823 struct necp_client_flow
*temp_flow
= NULL
;
1824 LIST_FOREACH_SAFE(search_flow
, &client
->flow_list
, flow_chain
, temp_flow
) {
1825 if (!search_flow
->socket
&& !search_flow
->nexus
&&
1826 search_flow
->u
.socket_handle
== handle
) {
1827 search_flow
->u
.socket_handle
= NULL
;
1828 search_flow
->u
.cb
= NULL
;
1832 client
->interface_handle
= NULL
;
1833 client
->interface_cb
= NULL
;
1835 NECP_CLIENT_UNLOCK(client
);
1838 NECP_CLIENT_TREE_UNLOCK();
1840 if (!found_client
) {
1848 necp_client_assign_from_socket(pid_t pid
, uuid_t client_id
, struct inpcb
*inp
)
1851 struct necp_fd_data
*client_fd
= NULL
;
1852 bool found_client
= FALSE
;
1853 bool client_updated
= FALSE
;
1855 NECP_FD_LIST_LOCK_SHARED();
1856 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
1857 if (pid
&& client_fd
->proc_pid
!= pid
) {
1861 proc_t proc
= proc_find(client_fd
->proc_pid
);
1862 if (proc
== PROC_NULL
) {
1866 NECP_FD_LOCK(client_fd
);
1868 struct necp_client
*client
= necp_client_fd_find_client_and_lock(client_fd
, client_id
);
1869 if (client
!= NULL
) {
1870 // Found the right client!
1871 found_client
= TRUE
;
1873 struct necp_client_flow
*flow
= NULL
;
1874 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
1875 if (flow
->socket
&& flow
->u
.socket_handle
== inp
) {
1876 // Release prior results and route
1877 if (flow
->assigned_results
!= NULL
) {
1878 FREE(flow
->assigned_results
, M_NETAGENT
);
1879 flow
->assigned_results
= NULL
;
1883 if ((inp
->inp_flags
& INP_BOUND_IF
) && inp
->inp_boundifp
) {
1884 ifp
= inp
->inp_boundifp
;
1886 ifp
= inp
->inp_last_outifp
;
1890 flow
->interface_index
= ifp
->if_index
;
1892 flow
->interface_index
= IFSCOPE_NONE
;
1895 if (inp
->inp_vflag
& INP_IPV4
) {
1896 flow
->local_addr
.sin
.sin_family
= AF_INET
;
1897 flow
->local_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
1898 flow
->local_addr
.sin
.sin_port
= inp
->inp_lport
;
1899 memcpy(&flow
->local_addr
.sin
.sin_addr
, &inp
->inp_laddr
, sizeof(struct in_addr
));
1901 flow
->remote_addr
.sin
.sin_family
= AF_INET
;
1902 flow
->remote_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
1903 flow
->remote_addr
.sin
.sin_port
= inp
->inp_fport
;
1904 memcpy(&flow
->remote_addr
.sin
.sin_addr
, &inp
->inp_faddr
, sizeof(struct in_addr
));
1905 } else if (inp
->inp_vflag
& INP_IPV6
) {
1906 in6_ip6_to_sockaddr(&inp
->in6p_laddr
, inp
->inp_lport
, &flow
->local_addr
.sin6
, sizeof(flow
->local_addr
));
1907 in6_ip6_to_sockaddr(&inp
->in6p_faddr
, inp
->inp_fport
, &flow
->remote_addr
.sin6
, sizeof(flow
->remote_addr
));
1910 flow
->viable
= necp_client_flow_is_viable(proc
, client
, flow
);
1913 uuid_clear(empty_uuid
);
1914 flow
->assigned
= TRUE
;
1915 flow
->assigned_results
= necp_create_nexus_assign_message(empty_uuid
, 0, NULL
, 0,
1916 (struct necp_client_endpoint
*)&flow
->local_addr
,
1917 (struct necp_client_endpoint
*)&flow
->remote_addr
,
1918 0, &flow
->assigned_results_length
);
1919 client
->flow_result_read
= FALSE
;
1920 client_updated
= TRUE
;
1925 NECP_CLIENT_UNLOCK(client
);
1927 if (client_updated
) {
1928 necp_fd_notify(client_fd
, true);
1930 NECP_FD_UNLOCK(client_fd
);
1939 NECP_FD_LIST_UNLOCK();
1941 if (!found_client
) {
1943 } else if (!client_updated
) {
1951 necp_update_flow_protoctl_event(uuid_t netagent_uuid
, uuid_t client_id
,
1952 uint32_t protoctl_event_code
, uint32_t protoctl_event_val
,
1953 uint32_t protoctl_event_tcp_seq_number
)
1956 struct necp_fd_data
*client_fd
= NULL
;
1957 bool found_client
= FALSE
;
1958 bool client_updated
= FALSE
;
1960 NECP_FD_LIST_LOCK_SHARED();
1961 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
1962 proc_t proc
= proc_find(client_fd
->proc_pid
);
1963 if (proc
== PROC_NULL
) {
1967 NECP_FD_LOCK(client_fd
);
1969 struct necp_client
*client
= necp_client_fd_find_client_and_lock(client_fd
, client_id
);
1970 if (client
!= NULL
) {
1971 /* Found the right client! */
1972 found_client
= TRUE
;
1974 struct necp_client_flow
*flow
= NULL
;
1975 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
1976 // Verify that the client nexus agent matches
1978 uuid_compare(flow
->u
.nexus_agent
,
1979 netagent_uuid
) == 0) {
1980 flow
->has_protoctl_event
= TRUE
;
1981 flow
->protoctl_event
.protoctl_event_code
= protoctl_event_code
;
1982 flow
->protoctl_event
.protoctl_event_val
= protoctl_event_val
;
1983 flow
->protoctl_event
.protoctl_event_tcp_seq_num
= protoctl_event_tcp_seq_number
;
1984 client
->flow_result_read
= FALSE
;
1985 client_updated
= TRUE
;
1990 NECP_CLIENT_UNLOCK(client
);
1993 if (client_updated
) {
1994 necp_fd_notify(client_fd
, true);
1997 NECP_FD_UNLOCK(client_fd
);
2005 NECP_FD_LIST_UNLOCK();
2007 if (!found_client
) {
2009 } else if (!client_updated
) {
2016 necp_assign_client_result_locked(struct proc
*proc
, struct necp_fd_data
*client_fd
, struct necp_client
*client
, uuid_t netagent_uuid
, u_int8_t
*assigned_results
, size_t assigned_results_length
)
2018 bool client_updated
= FALSE
;
2020 NECP_FD_ASSERT_LOCKED(client_fd
);
2021 NECP_CLIENT_ASSERT_LOCKED(client
);
2023 struct necp_client_flow
*flow
= NULL
;
2024 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
2025 // Verify that the client nexus agent matches
2027 uuid_compare(flow
->u
.nexus_agent
, netagent_uuid
) == 0) {
2028 // Release prior results and route
2029 if (flow
->assigned_results
!= NULL
) {
2030 FREE(flow
->assigned_results
, M_NETAGENT
);
2031 flow
->assigned_results
= NULL
;
2034 if (assigned_results
!= NULL
&& assigned_results_length
> 0) {
2035 int error
= necp_client_parse_result(assigned_results
, (u_int32_t
)assigned_results_length
,
2036 &flow
->local_addr
, &flow
->remote_addr
);
2040 flow
->viable
= necp_client_flow_is_viable(proc
, client
, flow
);
2042 flow
->assigned
= TRUE
;
2043 flow
->assigned_results
= assigned_results
;
2044 flow
->assigned_results_length
= assigned_results_length
;
2045 client
->flow_result_read
= FALSE
;
2046 client_updated
= TRUE
;
2051 if (client_updated
) {
2052 necp_fd_notify(client_fd
, true);
2055 // if not updated, client must free assigned_results
2056 return (client_updated
);
2060 necp_assign_client_result(uuid_t netagent_uuid
, uuid_t client_id
,
2061 u_int8_t
*assigned_results
, size_t assigned_results_length
)
2064 struct necp_fd_data
*client_fd
= NULL
;
2065 bool found_client
= FALSE
;
2066 bool client_updated
= FALSE
;
2068 NECP_FD_LIST_LOCK_SHARED();
2070 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
2071 proc_t proc
= proc_find(client_fd
->proc_pid
);
2072 if (proc
== PROC_NULL
) {
2076 NECP_FD_LOCK(client_fd
);
2077 struct necp_client
*client
= necp_client_fd_find_client_and_lock(client_fd
, client_id
);
2078 if (client
!= NULL
) {
2079 // Found the right client!
2080 found_client
= TRUE
;
2082 if (necp_assign_client_result_locked(proc
, client_fd
, client
, netagent_uuid
, assigned_results
, assigned_results_length
)) {
2083 client_updated
= TRUE
;
2086 NECP_CLIENT_UNLOCK(client
);
2088 NECP_FD_UNLOCK(client_fd
);
2098 NECP_FD_LIST_UNLOCK();
2100 // upon error, client must free assigned_results
2101 if (!found_client
) {
2103 } else if (!client_updated
) {
2113 necp_update_client_result(proc_t proc
,
2114 struct necp_fd_data
*client_fd
,
2115 struct necp_client
*client
,
2116 struct _necp_client_defunct_list
*defunct_list
)
2118 struct necp_client_result_netagent netagent
;
2119 struct necp_aggregate_result result
;
2120 struct necp_client_parsed_parameters
*parsed_parameters
= NULL
;
2121 u_int32_t flags
= 0;
2122 struct rtentry
*route
= NULL
;
2124 NECP_CLIENT_ASSERT_LOCKED(client
);
2126 MALLOC(parsed_parameters
, struct necp_client_parsed_parameters
*, sizeof(*parsed_parameters
), M_NECP
, (M_WAITOK
| M_ZERO
));
2127 if (parsed_parameters
== NULL
) {
2128 NECPLOG0(LOG_ERR
, "Failed to allocate parsed parameters");
2132 // Nexus flows will be brought back if they are still valid
2133 necp_client_mark_all_nonsocket_flows_as_invalid(client
);
2135 int error
= necp_client_parse_parameters(client
->parameters
, (u_int32_t
)client
->parameters_length
, parsed_parameters
);
2137 FREE(parsed_parameters
, M_NECP
);
2141 // Update saved IP protocol
2142 client
->ip_protocol
= parsed_parameters
->ip_protocol
;
2144 // Check parameters to find best interface
2145 u_int matching_if_index
= 0;
2146 if (necp_find_matching_interface_index(parsed_parameters
, &matching_if_index
)) {
2147 if (matching_if_index
!= 0) {
2148 parsed_parameters
->required_interface_index
= matching_if_index
;
2150 // Interface found or not needed, match policy.
2151 error
= necp_application_find_policy_match_internal(proc
, client
->parameters
,
2152 (u_int32_t
)client
->parameters_length
,
2153 &result
, &flags
, matching_if_index
,
2154 NULL
, NULL
, &route
, false);
2156 if (route
!= NULL
) {
2159 FREE(parsed_parameters
, M_NECP
);
2163 // Reset current route
2164 NECP_CLIENT_ROUTE_LOCK(client
);
2165 if (client
->current_route
!= NULL
) {
2166 rtfree(client
->current_route
);
2168 client
->current_route
= route
;
2169 NECP_CLIENT_ROUTE_UNLOCK(client
);
2171 // Interface not found. Clear out the whole result, make everything fail.
2172 memset(&result
, 0, sizeof(result
));
2175 // Save the last policy id on the client
2176 client
->policy_id
= result
.policy_id
;
2178 if ((parsed_parameters
->flags
& NECP_CLIENT_PARAMETER_FLAG_MULTIPATH
) ||
2179 ((parsed_parameters
->flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) &&
2180 result
.routing_result
!= NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
)) {
2181 client
->allow_multiple_flows
= TRUE
;
2183 client
->allow_multiple_flows
= FALSE
;
2186 // If the original request was scoped, and the policy result matches, make sure the result is scoped
2187 if ((result
.routing_result
== NECP_KERNEL_POLICY_RESULT_NONE
||
2188 result
.routing_result
== NECP_KERNEL_POLICY_RESULT_PASS
) &&
2189 result
.routed_interface_index
!= IFSCOPE_NONE
&&
2190 parsed_parameters
->required_interface_index
== result
.routed_interface_index
) {
2191 result
.routing_result
= NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
;
2192 result
.routing_result_parameter
.scoped_interface_index
= result
.routed_interface_index
;
2195 if (defunct_list
!= NULL
&&
2196 result
.routing_result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
2197 // If we are forced to drop the client, defunct it if it has flows
2198 necp_defunct_client_for_policy(client
, defunct_list
);
2201 // Recalculate flags
2202 if (client
->defunct
) {
2203 flags
|= NECP_CLIENT_RESULT_FLAG_DEFUNCT
;
2205 if (parsed_parameters
->flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) {
2206 // Listeners are valid as long as they aren't dropped
2207 if (result
.routing_result
!= NECP_KERNEL_POLICY_RESULT_DROP
) {
2208 flags
|= NECP_CLIENT_RESULT_FLAG_SATISFIED
;
2210 } else if (result
.routed_interface_index
!= 0) {
2211 // Clients without flows determine viability based on having some routable interface
2212 flags
|= NECP_CLIENT_RESULT_FLAG_SATISFIED
;
2215 bool updated
= FALSE
;
2216 u_int8_t
*cursor
= client
->result
;
2217 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_FLAGS
, sizeof(flags
), &flags
, &updated
, client
->result
, sizeof(client
->result
));
2218 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_CLIENT_ID
, sizeof(uuid_t
), client
->client_id
, &updated
,
2219 client
->result
, sizeof(client
->result
));
2220 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_POLICY_RESULT
, sizeof(result
.routing_result
), &result
.routing_result
, &updated
,
2221 client
->result
, sizeof(client
->result
));
2222 if (result
.routing_result_parameter
.tunnel_interface_index
!= 0) {
2223 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_POLICY_RESULT_PARAMETER
,
2224 sizeof(result
.routing_result_parameter
), &result
.routing_result_parameter
, &updated
,
2225 client
->result
, sizeof(client
->result
));
2227 if (result
.filter_control_unit
!= 0) {
2228 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_FILTER_CONTROL_UNIT
,
2229 sizeof(result
.filter_control_unit
), &result
.filter_control_unit
, &updated
,
2230 client
->result
, sizeof(client
->result
));
2232 if (result
.routed_interface_index
!= 0) {
2233 u_int routed_interface_index
= result
.routed_interface_index
;
2234 if (result
.routing_result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
2235 parsed_parameters
->required_interface_index
!= IFSCOPE_NONE
&&
2236 parsed_parameters
->required_interface_index
!= result
.routed_interface_index
) {
2237 routed_interface_index
= parsed_parameters
->required_interface_index
;
2240 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_INTERFACE_INDEX
,
2241 sizeof(routed_interface_index
), &routed_interface_index
, &updated
,
2242 client
->result
, sizeof(client
->result
));
2244 if (client_fd
&& client_fd
->flags
& NECP_OPEN_FLAG_BACKGROUND
) {
2245 u_int32_t effective_traffic_class
= SO_TC_BK_SYS
;
2246 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_EFFECTIVE_TRAFFIC_CLASS
,
2247 sizeof(effective_traffic_class
), &effective_traffic_class
, &updated
,
2248 client
->result
, sizeof(client
->result
));
2250 if (client
->background_update
) {
2251 u_int32_t background
= client
->background
;
2252 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_TRAFFIC_MGMT_BG
,
2253 sizeof(background
), &background
, &updated
,
2254 client
->result
, sizeof(client
->result
));
2256 client
->background_update
= 0;
2259 NECP_CLIENT_ROUTE_LOCK(client
);
2260 if (client
->current_route
!= NULL
) {
2261 const u_int32_t route_mtu
= get_maxmtu(client
->current_route
);
2262 if (route_mtu
!= 0) {
2263 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_EFFECTIVE_MTU
,
2264 sizeof(route_mtu
), &route_mtu
, &updated
,
2265 client
->result
, sizeof(client
->result
));
2268 NECP_CLIENT_ROUTE_UNLOCK(client
);
2270 if (result
.mss_recommended
!= 0) {
2271 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_RECOMMENDED_MSS
,
2272 sizeof(result
.mss_recommended
), &result
.mss_recommended
, &updated
,
2273 client
->result
, sizeof(client
->result
));
2276 for (int i
= 0; i
< NECP_MAX_NETAGENTS
; i
++) {
2277 if (uuid_is_null(result
.netagents
[i
])) {
2280 uuid_copy(netagent
.netagent_uuid
, result
.netagents
[i
]);
2281 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
2282 if (necp_netagent_applies_to_client(client
, parsed_parameters
, netagent
.netagent_uuid
, TRUE
, 0, 0)) {
2283 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
,
2284 client
->result
, sizeof(client
->result
));
2288 ifnet_head_lock_shared();
2289 ifnet_t direct_interface
= NULL
;
2290 ifnet_t delegate_interface
= NULL
;
2291 ifnet_t original_scoped_interface
= NULL
;
2293 if (result
.routed_interface_index
!= IFSCOPE_NONE
&& result
.routed_interface_index
<= (u_int32_t
)if_index
) {
2294 direct_interface
= ifindex2ifnet
[result
.routed_interface_index
];
2295 } else if (parsed_parameters
->required_interface_index
!= IFSCOPE_NONE
&&
2296 parsed_parameters
->required_interface_index
<= (u_int32_t
)if_index
) {
2297 // If the request was scoped, but the route didn't match, still grab the agents
2298 direct_interface
= ifindex2ifnet
[parsed_parameters
->required_interface_index
];
2299 } else if (result
.routed_interface_index
== IFSCOPE_NONE
&&
2300 result
.routing_result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
&&
2301 result
.routing_result_parameter
.scoped_interface_index
!= IFSCOPE_NONE
) {
2302 direct_interface
= ifindex2ifnet
[result
.routing_result_parameter
.scoped_interface_index
];
2304 if (direct_interface
!= NULL
) {
2305 delegate_interface
= direct_interface
->if_delegated
.ifp
;
2307 if (result
.routing_result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
2308 parsed_parameters
->required_interface_index
!= IFSCOPE_NONE
&&
2309 parsed_parameters
->required_interface_index
!= result
.routing_result_parameter
.tunnel_interface_index
&&
2310 parsed_parameters
->required_interface_index
<= (u_int32_t
)if_index
) {
2311 original_scoped_interface
= ifindex2ifnet
[parsed_parameters
->required_interface_index
];
2314 if (original_scoped_interface
!= NULL
) {
2315 struct necp_client_result_interface interface_struct
;
2316 interface_struct
.index
= original_scoped_interface
->if_index
;
2317 interface_struct
.generation
= ifnet_get_generation(original_scoped_interface
);
2318 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_INTERFACE
, sizeof(interface_struct
), &interface_struct
, &updated
,
2319 client
->result
, sizeof(client
->result
));
2321 if (direct_interface
!= NULL
) {
2322 struct necp_client_result_interface interface_struct
;
2323 interface_struct
.index
= direct_interface
->if_index
;
2324 interface_struct
.generation
= ifnet_get_generation(direct_interface
);
2325 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_INTERFACE
, sizeof(interface_struct
), &interface_struct
, &updated
,
2326 client
->result
, sizeof(client
->result
));
2328 if (delegate_interface
!= NULL
) {
2329 struct necp_client_result_interface interface_struct
;
2330 interface_struct
.index
= delegate_interface
->if_index
;
2331 interface_struct
.generation
= ifnet_get_generation(delegate_interface
);
2332 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_INTERFACE
, sizeof(interface_struct
), &interface_struct
, &updated
,
2333 client
->result
, sizeof(client
->result
));
2336 // Update multipath/listener interface flows
2337 if (parsed_parameters
->flags
& NECP_CLIENT_PARAMETER_FLAG_MULTIPATH
) {
2338 // Get multipath interface options from ordered list
2339 struct ifnet
*multi_interface
= NULL
;
2340 TAILQ_FOREACH(multi_interface
, &ifnet_ordered_head
, if_ordered_link
) {
2341 if (necp_ifnet_matches_parameters(multi_interface
, parsed_parameters
, NULL
, true)) {
2342 // Add multipath interface flows for kernel MPTCP
2343 necp_client_add_interface_flow_if_needed(client
, multi_interface
->if_index
);
2345 // Add nexus agents for multipath
2346 necp_client_add_agent_flows_for_interface(client
, parsed_parameters
, multi_interface
);
2349 } else if ((parsed_parameters
->flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) &&
2350 result
.routing_result
!= NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
2351 // Get listener interface options from global list
2352 struct ifnet
*listen_interface
= NULL
;
2353 TAILQ_FOREACH(listen_interface
, &ifnet_head
, if_link
) {
2354 if (necp_ifnet_matches_parameters(listen_interface
, parsed_parameters
, NULL
, false)) {
2355 // Add nexus agents for listeners
2356 necp_client_add_agent_flows_for_interface(client
, parsed_parameters
, listen_interface
);
2362 if (original_scoped_interface
!= NULL
) {
2363 ifnet_lock_shared(original_scoped_interface
);
2364 if (original_scoped_interface
->if_agentids
!= NULL
) {
2365 for (u_int32_t i
= 0; i
< original_scoped_interface
->if_agentcount
; i
++) {
2366 if (uuid_is_null(original_scoped_interface
->if_agentids
[i
])) {
2369 u_int16_t if_flags
= nstat_ifnet_to_flags(original_scoped_interface
);
2370 uuid_copy(netagent
.netagent_uuid
, original_scoped_interface
->if_agentids
[i
]);
2371 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
2372 if (necp_netagent_applies_to_client(client
, parsed_parameters
, netagent
.netagent_uuid
, FALSE
, original_scoped_interface
->if_index
, if_flags
)) {
2373 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
,
2374 client
->result
, sizeof(client
->result
));
2378 ifnet_lock_done(original_scoped_interface
);
2380 if (direct_interface
!= NULL
) {
2381 ifnet_lock_shared(direct_interface
);
2382 if (direct_interface
->if_agentids
!= NULL
) {
2383 for (u_int32_t i
= 0; i
< direct_interface
->if_agentcount
; i
++) {
2384 if (uuid_is_null(direct_interface
->if_agentids
[i
])) {
2387 u_int16_t if_flags
= nstat_ifnet_to_flags(direct_interface
);
2388 uuid_copy(netagent
.netagent_uuid
, direct_interface
->if_agentids
[i
]);
2389 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
2390 if (necp_netagent_applies_to_client(client
, parsed_parameters
, netagent
.netagent_uuid
, TRUE
, direct_interface
->if_index
, if_flags
)) {
2391 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
,
2392 client
->result
, sizeof(client
->result
));
2396 ifnet_lock_done(direct_interface
);
2398 if (delegate_interface
!= NULL
) {
2399 ifnet_lock_shared(delegate_interface
);
2400 if (delegate_interface
->if_agentids
!= NULL
) {
2401 for (u_int32_t i
= 0; i
< delegate_interface
->if_agentcount
; i
++) {
2402 if (uuid_is_null(delegate_interface
->if_agentids
[i
])) {
2405 u_int16_t if_flags
= nstat_ifnet_to_flags(delegate_interface
);
2406 uuid_copy(netagent
.netagent_uuid
, delegate_interface
->if_agentids
[i
]);
2407 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
2408 if (necp_netagent_applies_to_client(client
, parsed_parameters
, netagent
.netagent_uuid
, FALSE
, delegate_interface
->if_index
, if_flags
)) {
2409 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
,
2410 client
->result
, sizeof(client
->result
));
2414 ifnet_lock_done(delegate_interface
);
2418 size_t new_result_length
= (cursor
- client
->result
);
2419 if (new_result_length
!= client
->result_length
) {
2420 client
->result_length
= new_result_length
;
2424 // Update flow viability/flags
2425 if (necp_client_update_flows(proc
, client
)) {
2430 client
->result_read
= FALSE
;
2431 necp_client_update_observer_update(client
);
2434 FREE(parsed_parameters
, M_NECP
);
2439 necp_defunct_client_fd_locked(struct necp_fd_data
*client_fd
, struct _necp_client_defunct_list
*defunct_list
)
2441 bool updated_result
= FALSE
;
2442 struct necp_client
*client
= NULL
;
2444 NECP_FD_ASSERT_LOCKED(client_fd
);
2445 RB_FOREACH(client
, _necp_client_tree
, &client_fd
->clients
) {
2446 NECP_CLIENT_LOCK(client
);
2447 if (!client
->defunct
) {
2448 updated_result
= necp_set_client_defunct(client
);
2450 // Prepare close events to be sent to the nexus to effectively remove the flows
2451 struct necp_client_flow
*search_flow
= NULL
;
2452 LIST_FOREACH(search_flow
, &client
->flow_list
, flow_chain
) {
2453 if (search_flow
->nexus
&&
2454 !uuid_is_null(search_flow
->u
.nexus_agent
) &&
2455 search_flow
->requested_nexus
) {
2457 struct necp_client_defunct
*client_defunct
;
2459 // Sleeping alloc won't fail; copy only what's necessary
2460 client_defunct
= _MALLOC(sizeof (struct necp_client_defunct
), M_NECP
, M_WAITOK
| M_ZERO
);
2461 uuid_copy(client_defunct
->nexus_agent
, search_flow
->u
.nexus_agent
);
2462 uuid_copy(client_defunct
->client_id
, client
->client_id
);
2463 client_defunct
->proc_pid
= client
->proc_pid
;
2465 // Add to the list provided by caller
2466 LIST_INSERT_HEAD(defunct_list
, client_defunct
, chain
);
2470 NECP_CLIENT_UNLOCK(client
);
2472 if (updated_result
) {
2473 necp_fd_notify(client_fd
, true);
2478 necp_update_client_fd_locked(struct necp_fd_data
*client_fd
,
2480 struct _necp_client_defunct_list
*defunct_list
)
2482 struct necp_client
*client
= NULL
;
2483 bool updated_result
= FALSE
;
2484 NECP_FD_ASSERT_LOCKED(client_fd
);
2485 RB_FOREACH(client
, _necp_client_tree
, &client_fd
->clients
) {
2486 NECP_CLIENT_LOCK(client
);
2487 if (necp_update_client_result(proc
, client_fd
, client
, defunct_list
)) {
2488 updated_result
= TRUE
;
2490 NECP_CLIENT_UNLOCK(client
);
2492 if (updated_result
) {
2493 necp_fd_notify(client_fd
, true);
2499 necp_update_all_clients_callout(__unused thread_call_param_t dummy
,
2500 __unused thread_call_param_t arg
)
2502 struct necp_fd_data
*client_fd
= NULL
;
2504 struct _necp_client_defunct_list defunct_list
;
2505 LIST_INIT(&defunct_list
);
2507 NECP_FD_LIST_LOCK_SHARED();
2509 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
2510 proc_t proc
= proc_find(client_fd
->proc_pid
);
2511 if (proc
== PROC_NULL
) {
2515 // Update all clients on one fd
2516 NECP_FD_LOCK(client_fd
);
2517 necp_update_client_fd_locked(client_fd
, proc
, &defunct_list
);
2518 NECP_FD_UNLOCK(client_fd
);
2524 NECP_FD_LIST_UNLOCK();
2526 // Handle the case in which some clients became newly defunct
2527 if (!LIST_EMPTY(&defunct_list
)) {
2528 struct necp_client_defunct
*client_defunct
= NULL
;
2529 struct necp_client_defunct
*temp_client_defunct
= NULL
;
2531 // For each newly defunct client, send a message to the nexus to remove the flow
2532 LIST_FOREACH_SAFE(client_defunct
, &defunct_list
, chain
, temp_client_defunct
) {
2533 if (!uuid_is_null(client_defunct
->nexus_agent
)) {
2534 int netagent_error
= netagent_client_message(client_defunct
->nexus_agent
,
2535 client_defunct
->client_id
,
2536 client_defunct
->proc_pid
,
2537 NETAGENT_MESSAGE_TYPE_ABORT_NEXUS
);
2538 if (netagent_error
!= 0) {
2539 NECPLOG((netagent_error
== ENOENT
? LOG_DEBUG
: LOG_ERR
), "necp_update_client abort nexus error (%d)", netagent_error
);
2542 LIST_REMOVE(client_defunct
, chain
);
2543 FREE(client_defunct
, M_NECP
);
2546 ASSERT(LIST_EMPTY(&defunct_list
));
2550 necp_update_all_clients(void)
2552 if (necp_client_update_tcall
== NULL
) {
2553 // Don't try to update clients if the module is not initialized
2557 uint64_t deadline
= 0;
2558 uint64_t leeway
= 0;
2559 clock_interval_to_deadline(necp_timeout_microseconds
, NSEC_PER_USEC
, &deadline
);
2560 clock_interval_to_absolutetime_interval(necp_timeout_leeway_microseconds
, NSEC_PER_USEC
, &leeway
);
2562 thread_call_enter_delayed_with_leeway(necp_client_update_tcall
, NULL
,
2563 deadline
, leeway
, THREAD_CALL_DELAY_LEEWAY
);
2567 necp_set_client_as_background(proc_t proc
,
2568 struct fileproc
*fp
,
2571 bool updated_result
= FALSE
;
2572 struct necp_client
*client
= NULL
;
2574 if (proc
== PROC_NULL
) {
2575 NECPLOG0(LOG_ERR
, "NULL proc");
2580 NECPLOG0(LOG_ERR
, "NULL fp");
2584 struct necp_fd_data
*client_fd
= (struct necp_fd_data
*)fp
->f_fglob
->fg_data
;
2585 if (client_fd
== NULL
) {
2586 NECPLOG0(LOG_ERR
, "Could not find client structure for backgrounded client");
2590 if (client_fd
->necp_fd_type
!= necp_fd_type_client
) {
2591 // Not a client fd, ignore
2592 NECPLOG0(LOG_ERR
, "Not a client fd, ignore");
2596 NECP_FD_LOCK(client_fd
);
2598 RB_FOREACH(client
, _necp_client_tree
, &client_fd
->clients
) {
2599 NECP_CLIENT_LOCK(client
);
2601 bool has_assigned_flow
= FALSE
;
2602 struct necp_client_flow
*search_flow
= NULL
;
2603 LIST_FOREACH(search_flow
, &client
->flow_list
, flow_chain
) {
2604 if (search_flow
->assigned
) {
2605 has_assigned_flow
= TRUE
;
2610 if (has_assigned_flow
) {
2611 client
->background
= background
;
2612 client
->background_update
= TRUE
;
2613 updated_result
= TRUE
;
2616 NECP_CLIENT_UNLOCK(client
);
2618 if (updated_result
) {
2619 necp_update_client_fd_locked(client_fd
, proc
, NULL
);
2621 NECP_FD_UNLOCK(client_fd
);
2625 necp_defunct_client(proc_t proc
,
2626 struct fileproc
*fp
)
2628 struct _necp_client_defunct_list defunct_list
;
2630 if (proc
== PROC_NULL
) {
2631 NECPLOG0(LOG_ERR
, "NULL proc passed to set as background");
2636 NECPLOG0(LOG_ERR
, "NULL fp passed to set as background");
2640 struct necp_fd_data
*client_fd
= (struct necp_fd_data
*)fp
->f_fglob
->fg_data
;
2641 if (client_fd
== NULL
) {
2642 NECPLOG0(LOG_ERR
, "Could not find client structure for backgrounded client");
2646 if (client_fd
->necp_fd_type
!= necp_fd_type_client
) {
2647 // Not a client fd, ignore
2651 // Our local temporary list
2652 LIST_INIT(&defunct_list
);
2654 // Need to hold lock so ntstats defunct the same set of clients
2655 NECP_FD_LOCK(client_fd
);
2656 necp_defunct_client_fd_locked(client_fd
, &defunct_list
);
2657 NECP_FD_UNLOCK(client_fd
);
2659 if (!LIST_EMPTY(&defunct_list
)) {
2660 struct necp_client_defunct
*client_defunct
= NULL
;
2661 struct necp_client_defunct
*temp_client_defunct
= NULL
;
2663 // For each defunct client, remove flow from the nexus
2664 LIST_FOREACH_SAFE(client_defunct
, &defunct_list
, chain
, temp_client_defunct
) {
2665 if (!uuid_is_null(client_defunct
->nexus_agent
)) {
2666 int netagent_error
= netagent_client_message(client_defunct
->nexus_agent
,
2667 client_defunct
->client_id
,
2668 client_defunct
->proc_pid
,
2669 NETAGENT_MESSAGE_TYPE_ABORT_NEXUS
);
2670 if (netagent_error
!= 0) {
2671 NECPLOG((netagent_error
== ENOENT
? LOG_DEBUG
: LOG_ERR
), "necp_defunct_client abort nexus error (%d)", netagent_error
);
2674 LIST_REMOVE(client_defunct
, chain
);
2675 FREE(client_defunct
, M_NECP
);
2678 ASSERT(LIST_EMPTY(&defunct_list
));
2682 necp_client_remove_agent_from_result(struct necp_client
*client
, uuid_t netagent_uuid
)
2686 u_int8_t
*result_buffer
= client
->result
;
2687 while ((offset
+ sizeof(struct necp_tlv_header
)) <= client
->result_length
) {
2688 u_int8_t type
= necp_buffer_get_tlv_type(result_buffer
, offset
);
2689 u_int32_t length
= necp_buffer_get_tlv_length(result_buffer
, offset
);
2691 size_t tlv_total_length
= (sizeof(struct necp_tlv_header
) + length
);
2692 if (type
== NECP_CLIENT_RESULT_NETAGENT
&&
2693 length
== sizeof(struct necp_client_result_netagent
) &&
2694 (offset
+ tlv_total_length
) <= client
->result_length
) {
2695 struct necp_client_result_netagent
*value
= ((struct necp_client_result_netagent
*)(void *)
2696 necp_buffer_get_tlv_value(result_buffer
, offset
, NULL
));
2697 if (uuid_compare(value
->netagent_uuid
, netagent_uuid
) == 0) {
2698 // Found a netagent to remove
2699 // Shift bytes down to remove the tlv, and adjust total length
2700 // Don't adjust the current offset
2701 memmove(result_buffer
+ offset
,
2702 result_buffer
+ offset
+ tlv_total_length
,
2703 client
->result_length
- (offset
+ tlv_total_length
));
2704 client
->result_length
-= tlv_total_length
;
2705 memset(result_buffer
+ client
->result_length
, 0, sizeof(client
->result
) - client
->result_length
);
2710 offset
+= tlv_total_length
;
2715 necp_force_update_client(uuid_t client_id
, uuid_t remove_netagent_uuid
)
2717 struct necp_fd_data
*client_fd
= NULL
;
2719 NECP_FD_LIST_LOCK_SHARED();
2721 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
2722 bool updated_result
= FALSE
;
2723 NECP_FD_LOCK(client_fd
);
2724 struct necp_client
*client
= necp_client_fd_find_client_and_lock(client_fd
, client_id
);
2725 if (client
!= NULL
) {
2726 if (!uuid_is_null(remove_netagent_uuid
)) {
2727 necp_client_remove_agent_from_result(client
, remove_netagent_uuid
);
2729 client
->flow_result_read
= FALSE
;
2730 // Found the client, break
2731 updated_result
= TRUE
;
2732 NECP_CLIENT_UNLOCK(client
);
2734 if (updated_result
) {
2735 necp_fd_notify(client_fd
, true);
2737 NECP_FD_UNLOCK(client_fd
);
2738 if (updated_result
) {
2739 // Found the client, break
2744 NECP_FD_LIST_UNLOCK();
2748 /// Interface matching
2750 #define NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
2751 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF | \
2752 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
2753 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE | \
2754 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
2755 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT | \
2756 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
2757 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
2758 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE | \
2759 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
2761 #define NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
2762 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
2763 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
2764 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
2765 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
2766 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
2768 #define NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
2769 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
2772 necp_ifnet_matches_type(struct ifnet
*ifp
, u_int8_t interface_type
, bool check_delegates
)
2774 struct ifnet
*check_ifp
= ifp
;
2776 if (if_functional_type(check_ifp
, TRUE
) == interface_type
) {
2779 if (!check_delegates
) {
2782 check_ifp
= check_ifp
->if_delegated
.ifp
;
2789 necp_ifnet_matches_name(struct ifnet
*ifp
, const char *interface_name
, bool check_delegates
)
2791 struct ifnet
*check_ifp
= ifp
;
2793 if (strncmp(check_ifp
->if_xname
, interface_name
, IFXNAMSIZ
) == 0) {
2796 if (!check_delegates
) {
2799 check_ifp
= check_ifp
->if_delegated
.ifp
;
2805 necp_ifnet_matches_agent(struct ifnet
*ifp
, uuid_t
*agent_uuid
, bool check_delegates
)
2807 struct ifnet
*check_ifp
= ifp
;
2809 while (check_ifp
!= NULL
) {
2810 ifnet_lock_shared(check_ifp
);
2811 if (check_ifp
->if_agentids
!= NULL
) {
2812 for (u_int32_t index
= 0; index
< check_ifp
->if_agentcount
; index
++) {
2813 if (uuid_compare(check_ifp
->if_agentids
[index
], *agent_uuid
) == 0) {
2814 ifnet_lock_done(check_ifp
);
2819 ifnet_lock_done(check_ifp
);
2821 if (!check_delegates
) {
2824 check_ifp
= check_ifp
->if_delegated
.ifp
;
2830 necp_necp_ifnet_matches_agent_type(struct ifnet
*ifp
, const char *agent_domain
, const char *agent_type
, bool check_delegates
)
2832 struct ifnet
*check_ifp
= ifp
;
2834 while (check_ifp
!= NULL
) {
2835 ifnet_lock_shared(check_ifp
);
2836 if (check_ifp
->if_agentids
!= NULL
) {
2837 for (u_int32_t index
= 0; index
< check_ifp
->if_agentcount
; index
++) {
2838 if (uuid_is_null(check_ifp
->if_agentids
[index
])) {
2842 char if_agent_domain
[NETAGENT_DOMAINSIZE
] = { 0 };
2843 char if_agent_type
[NETAGENT_TYPESIZE
] = { 0 };
2845 if (netagent_get_agent_domain_and_type(check_ifp
->if_agentids
[index
], if_agent_domain
, if_agent_type
)) {
2846 if ((strlen(agent_domain
) == 0 ||
2847 strncmp(if_agent_domain
, agent_domain
, NETAGENT_DOMAINSIZE
) == 0) &&
2848 (strlen(agent_type
) == 0 ||
2849 strncmp(if_agent_type
, agent_type
, NETAGENT_TYPESIZE
) == 0)) {
2850 ifnet_lock_done(check_ifp
);
2856 ifnet_lock_done(check_ifp
);
2858 if (!check_delegates
) {
2861 check_ifp
= check_ifp
->if_delegated
.ifp
;
2867 necp_ifnet_matches_local_address(struct ifnet
*ifp
, struct sockaddr
*sa
)
2869 struct ifaddr
*ifa
= NULL
;
2870 bool matched_local_address
= FALSE
;
2872 // Transform sa into the ifaddr form
2873 // IPv6 Scope IDs are always embedded in the ifaddr list
2874 struct sockaddr_storage address
;
2875 u_int ifscope
= IFSCOPE_NONE
;
2876 (void)sa_copy(sa
, &address
, &ifscope
);
2877 SIN(&address
)->sin_port
= 0;
2878 if (address
.ss_family
== AF_INET6
) {
2879 SIN6(&address
)->sin6_scope_id
= 0;
2882 ifa
= ifa_ifwithaddr_scoped_locked((struct sockaddr
*)&address
, ifp
->if_index
);
2883 matched_local_address
= (ifa
!= NULL
);
2886 ifaddr_release(ifa
);
2889 return (matched_local_address
);
2893 necp_interface_type_is_primary_eligible(u_int8_t interface_type
)
2895 switch (interface_type
) {
2896 // These types can never be primary, so a client requesting these types is allowed
2897 // to match an interface that isn't currently eligible to be primary (has default
2899 case IFRTYPE_FUNCTIONAL_WIFI_AWDL
:
2900 case IFRTYPE_FUNCTIONAL_INTCOPROC
:
2908 #define NECP_IFP_IS_ON_ORDERED_LIST(_ifp) ((_ifp)->if_ordered_link.tqe_next != NULL || (_ifp)->if_ordered_link.tqe_prev != NULL)
2911 necp_ifnet_matches_parameters(struct ifnet
*ifp
,
2912 struct necp_client_parsed_parameters
*parsed_parameters
,
2913 u_int32_t
*preferred_count
, bool ignore_require_if
)
2915 if (preferred_count
) {
2916 *preferred_count
= 0;
2919 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR
) {
2920 if (!necp_ifnet_matches_local_address(ifp
, &parsed_parameters
->local_addr
.sa
)) {
2925 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_FLAGS
) {
2926 if ((parsed_parameters
->flags
& NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE
) &&
2927 IFNET_IS_EXPENSIVE(ifp
)) {
2932 if (!ignore_require_if
&&
2933 (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
) &&
2934 !necp_ifnet_matches_type(ifp
, parsed_parameters
->required_interface_type
, FALSE
)) {
2938 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE
) {
2939 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
2940 if (parsed_parameters
->prohibited_interface_types
[i
] == 0) {
2944 if (necp_ifnet_matches_type(ifp
, parsed_parameters
->prohibited_interface_types
[i
], TRUE
)) {
2950 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF
) {
2951 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
2952 if (strlen(parsed_parameters
->prohibited_interfaces
[i
]) == 0) {
2956 if (necp_ifnet_matches_name(ifp
, parsed_parameters
->prohibited_interfaces
[i
], TRUE
)) {
2962 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT
) {
2963 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
2964 if (uuid_is_null(parsed_parameters
->required_netagents
[i
])) {
2968 if (!necp_ifnet_matches_agent(ifp
, &parsed_parameters
->required_netagents
[i
], FALSE
)) {
2974 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT
) {
2975 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
2976 if (uuid_is_null(parsed_parameters
->prohibited_netagents
[i
])) {
2980 if (necp_ifnet_matches_agent(ifp
, &parsed_parameters
->prohibited_netagents
[i
], TRUE
)) {
2986 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE
) {
2987 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
2988 if (strlen(parsed_parameters
->required_netagent_types
[i
].netagent_domain
) == 0 &&
2989 strlen(parsed_parameters
->required_netagent_types
[i
].netagent_type
) == 0) {
2993 if (!necp_necp_ifnet_matches_agent_type(ifp
, parsed_parameters
->required_netagent_types
[i
].netagent_domain
, parsed_parameters
->required_netagent_types
[i
].netagent_type
, FALSE
)) {
2999 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE
) {
3000 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
3001 if (strlen(parsed_parameters
->prohibited_netagent_types
[i
].netagent_domain
) == 0 &&
3002 strlen(parsed_parameters
->prohibited_netagent_types
[i
].netagent_type
) == 0) {
3006 if (necp_necp_ifnet_matches_agent_type(ifp
, parsed_parameters
->prohibited_netagent_types
[i
].netagent_domain
, parsed_parameters
->prohibited_netagent_types
[i
].netagent_type
, TRUE
)) {
3012 // Checked preferred properties
3013 if (preferred_count
) {
3014 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT
) {
3015 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
3016 if (uuid_is_null(parsed_parameters
->preferred_netagents
[i
])) {
3020 if (necp_ifnet_matches_agent(ifp
, &parsed_parameters
->preferred_netagents
[i
], TRUE
)) {
3021 (*preferred_count
)++;
3026 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE
) {
3027 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
3028 if (strlen(parsed_parameters
->preferred_netagent_types
[i
].netagent_domain
) == 0 &&
3029 strlen(parsed_parameters
->preferred_netagent_types
[i
].netagent_type
) == 0) {
3033 if (necp_necp_ifnet_matches_agent_type(ifp
, parsed_parameters
->preferred_netagent_types
[i
].netagent_domain
, parsed_parameters
->preferred_netagent_types
[i
].netagent_type
, TRUE
)) {
3034 (*preferred_count
)++;
3044 necp_find_matching_interface_index(struct necp_client_parsed_parameters
*parsed_parameters
, u_int
*return_ifindex
)
3046 struct ifnet
*ifp
= NULL
;
3047 u_int32_t best_preferred_count
= 0;
3048 bool has_preferred_fields
= FALSE
;
3049 *return_ifindex
= 0;
3051 if (parsed_parameters
->required_interface_index
!= 0) {
3052 *return_ifindex
= parsed_parameters
->required_interface_index
;
3056 if (!(parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS
)) {
3060 has_preferred_fields
= (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS
);
3062 // We have interesting parameters to parse and find a matching interface
3063 ifnet_head_lock_shared();
3065 if (!(parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS
)) {
3066 // We do have fields to match, but they are only prohibitory
3067 // If the first interface in the list matches, or there are no ordered interfaces, we don't need to scope
3068 ifp
= TAILQ_FIRST(&ifnet_ordered_head
);
3069 if (ifp
== NULL
|| necp_ifnet_matches_parameters(ifp
, parsed_parameters
, NULL
, false)) {
3070 // Don't set return_ifindex, so the client doesn't need to scope
3076 // First check the ordered interface list
3077 TAILQ_FOREACH(ifp
, &ifnet_ordered_head
, if_ordered_link
) {
3078 u_int32_t preferred_count
= 0;
3079 if (necp_ifnet_matches_parameters(ifp
, parsed_parameters
, &preferred_count
, false)) {
3080 if (preferred_count
> best_preferred_count
||
3081 *return_ifindex
== 0) {
3083 // Everything matched, and is most preferred. Return this interface.
3084 *return_ifindex
= ifp
->if_index
;
3085 best_preferred_count
= preferred_count
;
3087 if (!has_preferred_fields
) {
3094 // Then check the remaining interfaces
3095 if ((parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS
) &&
3096 ((!(parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
)) ||
3097 !necp_interface_type_is_primary_eligible(parsed_parameters
->required_interface_type
)) &&
3098 *return_ifindex
== 0) {
3099 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
) {
3100 u_int32_t preferred_count
= 0;
3101 if (NECP_IFP_IS_ON_ORDERED_LIST(ifp
)) {
3102 // This interface was in the ordered list, skip
3105 if (necp_ifnet_matches_parameters(ifp
, parsed_parameters
, &preferred_count
, false)) {
3106 if (preferred_count
> best_preferred_count
||
3107 *return_ifindex
== 0) {
3109 // Everything matched, and is most preferred. Return this interface.
3110 *return_ifindex
= ifp
->if_index
;
3111 best_preferred_count
= preferred_count
;
3113 if (!has_preferred_fields
) {
3123 if ((parsed_parameters
->valid_fields
== (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS
)) &&
3124 best_preferred_count
== 0) {
3125 // If only has preferred fields, and nothing was found, clear the interface index and return TRUE
3126 *return_ifindex
= 0;
3130 return (*return_ifindex
!= 0);
3135 necp_skywalk_priv_check_cred(proc_t p
, kauth_cred_t cred
)
3137 #pragma unused(p, cred)
3144 necp_open(struct proc
*p
, struct necp_open_args
*uap
, int *retval
)
3146 #pragma unused(retval)
3148 struct necp_fd_data
*fd_data
= NULL
;
3149 struct fileproc
*fp
= NULL
;
3152 if (uap
->flags
& NECP_OPEN_FLAG_OBSERVER
) {
3153 if (necp_skywalk_priv_check_cred(p
, kauth_cred_get()) != 0 &&
3154 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NETWORK_STATISTICS
, 0) != 0) {
3155 NECPLOG0(LOG_ERR
, "Client does not hold necessary entitlement to observe other NECP clients");
3161 error
= falloc(p
, &fp
, &fd
, vfs_context_current());
3166 if ((fd_data
= zalloc(necp_client_fd_zone
)) == NULL
) {
3171 memset(fd_data
, 0, sizeof(*fd_data
));
3173 fd_data
->necp_fd_type
= necp_fd_type_client
;
3174 fd_data
->flags
= uap
->flags
;
3175 RB_INIT(&fd_data
->clients
);
3176 TAILQ_INIT(&fd_data
->update_list
);
3177 lck_mtx_init(&fd_data
->fd_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
3178 klist_init(&fd_data
->si
.si_note
);
3179 fd_data
->proc_pid
= proc_pid(p
);
3181 fp
->f_fglob
->fg_flag
= FREAD
;
3182 fp
->f_fglob
->fg_ops
= &necp_fd_ops
;
3183 fp
->f_fglob
->fg_data
= fd_data
;
3187 *fdflags(p
, fd
) |= (UF_EXCLOSE
| UF_FORKCLOSE
);
3188 procfdtbl_releasefd(p
, fd
, NULL
);
3189 fp_drop(p
, fd
, fp
, 1);
3193 if (fd_data
->flags
& NECP_OPEN_FLAG_PUSH_OBSERVER
) {
3194 NECP_OBSERVER_LIST_LOCK_EXCLUSIVE();
3195 LIST_INSERT_HEAD(&necp_fd_observer_list
, fd_data
, chain
);
3196 OSIncrementAtomic(&necp_observer_fd_count
);
3197 NECP_OBSERVER_LIST_UNLOCK();
3199 // Walk all existing clients and add them
3200 NECP_CLIENT_TREE_LOCK_SHARED();
3201 struct necp_client
*existing_client
= NULL
;
3202 RB_FOREACH(existing_client
, _necp_client_global_tree
, &necp_client_global_tree
) {
3203 NECP_CLIENT_LOCK(existing_client
);
3204 necp_client_update_observer_add_internal(fd_data
, existing_client
);
3205 necp_client_update_observer_update_internal(fd_data
, existing_client
);
3206 NECP_CLIENT_UNLOCK(existing_client
);
3208 NECP_CLIENT_TREE_UNLOCK();
3210 NECP_FD_LIST_LOCK_EXCLUSIVE();
3211 LIST_INSERT_HEAD(&necp_fd_list
, fd_data
, chain
);
3212 OSIncrementAtomic(&necp_client_fd_count
);
3213 NECP_FD_LIST_UNLOCK();
3224 if (fd_data
!= NULL
) {
3225 zfree(necp_client_fd_zone
, fd_data
);
3234 necp_client_add(struct proc
*p
, struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
3237 struct necp_client
*client
= NULL
;
3239 if (fd_data
->flags
& NECP_OPEN_FLAG_PUSH_OBSERVER
) {
3240 NECPLOG0(LOG_ERR
, "NECP client observers with push enabled may not add their own clients");
3244 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
3245 uap
->buffer_size
== 0 || uap
->buffer_size
> NECP_MAX_CLIENT_PARAMETERS_SIZE
|| uap
->buffer
== 0) {
3249 if ((client
= _MALLOC(sizeof(struct necp_client
) + uap
->buffer_size
, M_NECP
,
3250 M_WAITOK
| M_ZERO
)) == NULL
) {
3255 error
= copyin(uap
->buffer
, client
->parameters
, uap
->buffer_size
);
3257 NECPLOG(LOG_ERR
, "necp_client_add parameters copyin error (%d)", error
);
3261 lck_mtx_init(&client
->lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
3262 lck_mtx_init(&client
->route_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
3263 necp_client_retain(client
); // Hold our reference until close
3265 client
->parameters_length
= uap
->buffer_size
;
3266 client
->proc_pid
= fd_data
->proc_pid
; // Save off proc pid in case the client will persist past fd
3267 client
->platform_binary
= ((csproc_get_platform_binary(p
) == 0) ? 0 : 1);
3269 uuid_generate_random(client
->client_id
);
3270 LIST_INIT(&client
->assertion_list
);
3271 LIST_INIT(&client
->flow_list
);
3273 error
= copyout(client
->client_id
, uap
->client_id
, sizeof(uuid_t
));
3275 NECPLOG(LOG_ERR
, "necp_client_add client_id copyout error (%d)", error
);
3279 necp_client_update_observer_add(client
);
3281 NECP_FD_LOCK(fd_data
);
3282 RB_INSERT(_necp_client_tree
, &fd_data
->clients
, client
);
3283 OSIncrementAtomic(&necp_client_count
);
3284 NECP_CLIENT_TREE_LOCK_EXCLUSIVE();
3285 RB_INSERT(_necp_client_global_tree
, &necp_client_global_tree
, client
);
3286 NECP_CLIENT_TREE_UNLOCK();
3288 // Prime the client result
3289 NECP_CLIENT_LOCK(client
);
3290 (void)necp_update_client_result(current_proc(), fd_data
, client
, NULL
);
3291 NECP_CLIENT_UNLOCK(client
);
3292 NECP_FD_UNLOCK(fd_data
);
3295 if (client
!= NULL
) {
3296 FREE(client
, M_NECP
);
3306 necp_client_remove(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
3309 struct necp_client
*client
= NULL
;
3310 struct necp_client
*temp_client
= NULL
;
3311 uuid_t client_id
= {};
3312 struct ifnet_stats_per_flow flow_ifnet_stats
= {};
3314 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
)) {
3319 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
3321 NECPLOG(LOG_ERR
, "necp_client_remove copyin client_id error (%d)", error
);
3325 if (uap
->buffer
!= 0 && uap
->buffer_size
== sizeof(flow_ifnet_stats
)) {
3326 error
= copyin(uap
->buffer
, &flow_ifnet_stats
, uap
->buffer_size
);
3328 NECPLOG(LOG_ERR
, "necp_client_remove flow_ifnet_stats copyin error (%d)", error
);
3331 } else if (uap
->buffer
!= 0) {
3332 NECPLOG(LOG_ERR
, "necp_client_remove unexpected parameters length (%zu)", uap
->buffer_size
);
3335 struct _necp_client_tree clients_to_close
;
3336 RB_INIT(&clients_to_close
);
3337 NECP_FD_LOCK(fd_data
);
3338 pid_t pid
= fd_data
->proc_pid
;
3339 RB_FOREACH_SAFE(client
, _necp_client_tree
, &fd_data
->clients
, temp_client
) {
3340 if (uuid_compare(client
->client_id
, client_id
) == 0) {
3341 NECP_CLIENT_TREE_LOCK_EXCLUSIVE();
3342 RB_REMOVE(_necp_client_global_tree
, &necp_client_global_tree
, client
);
3343 NECP_CLIENT_TREE_UNLOCK();
3344 RB_REMOVE(_necp_client_tree
, &fd_data
->clients
, client
);
3345 RB_INSERT(_necp_client_tree
, &clients_to_close
, client
);
3350 NECP_FD_UNLOCK(fd_data
);
3352 RB_FOREACH_SAFE(client
, _necp_client_tree
, &clients_to_close
, temp_client
) {
3353 RB_REMOVE(_necp_client_tree
, &clients_to_close
, client
);
3354 necp_destroy_client(client
, pid
, true);
3363 necp_client_check_tcp_heuristics(struct necp_client
*client
, struct necp_client_flow
*flow
, u_int32_t
*flags
, u_int8_t
*tfo_cookie
, u_int8_t
*tfo_cookie_len
)
3365 struct necp_client_parsed_parameters parsed_parameters
;
3368 error
= necp_client_parse_parameters(client
->parameters
,
3369 (u_int32_t
)client
->parameters_length
,
3370 &parsed_parameters
);
3372 NECPLOG(LOG_ERR
, "necp_client_parse_parameters error (%d)", error
);
3376 if ((flow
->remote_addr
.sa
.sa_family
!= AF_INET
&&
3377 flow
->remote_addr
.sa
.sa_family
!= AF_INET6
) ||
3378 (flow
->local_addr
.sa
.sa_family
!= AF_INET
&&
3379 flow
->local_addr
.sa
.sa_family
!= AF_INET6
)) {
3383 NECP_CLIENT_ROUTE_LOCK(client
);
3385 if (client
->current_route
== NULL
) {
3390 bool check_ecn
= false;
3392 if ((parsed_parameters
.flags
& NECP_CLIENT_PARAMETER_FLAG_ECN_ENABLE
) ==
3393 NECP_CLIENT_PARAMETER_FLAG_ECN_ENABLE
) {
3398 if ((parsed_parameters
.flags
& NECP_CLIENT_PARAMETER_FLAG_ECN_DISABLE
) ==
3399 NECP_CLIENT_PARAMETER_FLAG_ECN_DISABLE
) {
3403 if (client
->current_route
!= NULL
) {
3404 if (client
->current_route
->rt_ifp
->if_eflags
& IFEF_ECN_ENABLE
) {
3408 if (client
->current_route
->rt_ifp
->if_eflags
& IFEF_ECN_DISABLE
) {
3413 bool inbound
= ((parsed_parameters
.flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) == 0);
3414 if ((inbound
&& tcp_ecn_inbound
== 1) ||
3415 (!inbound
&& tcp_ecn_outbound
== 1)) {
3421 if (tcp_heuristic_do_ecn_with_address(client
->current_route
->rt_ifp
,
3422 (union sockaddr_in_4_6
*)&flow
->local_addr
)) {
3423 *flags
|= NECP_CLIENT_RESULT_FLAG_ECN_ENABLED
;
3427 if ((parsed_parameters
.flags
& NECP_CLIENT_PARAMETER_FLAG_TFO_ENABLE
) ==
3428 NECP_CLIENT_PARAMETER_FLAG_TFO_ENABLE
) {
3430 if (!tcp_heuristic_do_tfo_with_address(client
->current_route
->rt_ifp
,
3431 (union sockaddr_in_4_6
*)&flow
->local_addr
,
3432 (union sockaddr_in_4_6
*)&flow
->remote_addr
,
3433 tfo_cookie
, tfo_cookie_len
)) {
3434 *flags
|= NECP_CLIENT_RESULT_FLAG_FAST_OPEN_BLOCKED
;
3435 *tfo_cookie_len
= 0;
3438 *flags
|= NECP_CLIENT_RESULT_FLAG_FAST_OPEN_BLOCKED
;
3439 *tfo_cookie_len
= 0;
3442 NECP_CLIENT_ROUTE_UNLOCK(client
);
3448 necp_client_copy_internal(struct necp_client
*client
, bool client_is_observed
, struct necp_client_action_args
*uap
, int *retval
)
3452 if (uap
->action
== NECP_CLIENT_ACTION_COPY_PARAMETERS
) {
3453 if (uap
->buffer_size
< client
->parameters_length
) {
3457 error
= copyout(client
->parameters
, uap
->buffer
, client
->parameters_length
);
3459 NECPLOG(LOG_ERR
, "necp_client_copy parameters copyout error (%d)", error
);
3462 *retval
= client
->parameters_length
;
3463 } else if (uap
->action
== NECP_CLIENT_ACTION_COPY_UPDATED_RESULT
&&
3464 client
->result_read
&& client
->flow_result_read
) {
3465 // Copy updates only, but nothing to read
3466 // Just return 0 for bytes read
3468 } else if (uap
->action
== NECP_CLIENT_ACTION_COPY_RESULT
||
3469 uap
->action
== NECP_CLIENT_ACTION_COPY_UPDATED_RESULT
) {
3470 size_t assigned_results_size
= 0;
3471 struct necp_client_flow
*flow
= NULL
;
3472 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
3473 if (flow
->nexus
|| (flow
->socket
&& flow
->assigned
)) {
3474 size_t header_length
= 0;
3476 header_length
= sizeof(struct necp_client_nexus_flow_header
);
3478 header_length
= sizeof(struct necp_client_flow_header
);
3480 assigned_results_size
+= (header_length
+ flow
->assigned_results_length
);
3482 if (flow
->has_protoctl_event
) {
3483 assigned_results_size
+= sizeof(struct necp_client_flow_protoctl_event_header
);
3487 if (uap
->buffer_size
< (client
->result_length
+ assigned_results_size
)) {
3491 error
= copyout(client
->result
, uap
->buffer
, client
->result_length
);
3493 NECPLOG(LOG_ERR
, "necp_client_copy result copyout error (%d)", error
);
3497 size_t assigned_results_cursor
= 0;
3500 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
3501 if (flow
->nexus
|| (flow
->socket
&& flow
->assigned
)) {
3502 // Write TLV headers
3503 struct necp_client_nexus_flow_header header
;
3504 u_int32_t length
= 0;
3505 u_int32_t flags
= 0;
3506 u_int8_t tfo_cookie_len
= 0;
3510 if (flow
->check_tcp_heuristics
) {
3511 u_int8_t tfo_cookie
[NECP_TFO_COOKIE_LEN_MAX
];
3512 tfo_cookie_len
= NECP_TFO_COOKIE_LEN_MAX
;
3514 if (necp_client_check_tcp_heuristics(client
, flow
, &flags
,
3515 tfo_cookie
, &tfo_cookie_len
) != 0) {
3518 flow
->check_tcp_heuristics
= FALSE
;
3520 if (tfo_cookie_len
!= 0) {
3521 type
= NECP_CLIENT_RESULT_TFO_COOKIE
;
3522 length
= tfo_cookie_len
;
3523 memcpy(&header
.tfo_cookie_tlv_header
.type
, &type
, sizeof(type
));
3524 memcpy(&header
.tfo_cookie_tlv_header
.length
, &length
, sizeof(length
));
3525 memcpy(&header
.tfo_cookie_value
, tfo_cookie
, tfo_cookie_len
);
3531 size_t header_length
= 0;
3533 if (tfo_cookie_len
!= 0) {
3534 header_length
= sizeof(struct necp_client_nexus_flow_header
) - (NECP_TFO_COOKIE_LEN_MAX
- tfo_cookie_len
);
3536 header_length
= sizeof(struct necp_client_nexus_flow_header
) - sizeof(struct necp_tlv_header
) - NECP_TFO_COOKIE_LEN_MAX
;
3539 header_length
= sizeof(struct necp_client_flow_header
);
3542 type
= NECP_CLIENT_RESULT_FLAGS
;
3543 length
= sizeof(header
.flow_header
.flags_value
);
3544 memcpy(&header
.flow_header
.flags_tlv_header
.type
, &type
, sizeof(type
));
3545 memcpy(&header
.flow_header
.flags_tlv_header
.length
, &length
, sizeof(length
));
3546 if (flow
->assigned
) {
3547 flags
|= NECP_CLIENT_RESULT_FLAG_FLOW_ASSIGNED
;
3550 flags
|= NECP_CLIENT_RESULT_FLAG_FLOW_VIABLE
;
3552 memcpy(&header
.flow_header
.flags_value
, &flags
, sizeof(flags
));
3554 type
= NECP_CLIENT_RESULT_INTERFACE
;
3555 length
= sizeof(header
.flow_header
.interface_value
);
3556 memcpy(&header
.flow_header
.interface_tlv_header
.type
, &type
, sizeof(type
));
3557 memcpy(&header
.flow_header
.interface_tlv_header
.length
, &length
, sizeof(length
));
3559 struct necp_client_result_interface interface_struct
;
3560 interface_struct
.generation
= 0;
3561 interface_struct
.index
= flow
->interface_index
;
3563 memcpy(&header
.flow_header
.interface_value
, &interface_struct
, sizeof(interface_struct
));
3565 type
= NECP_CLIENT_RESULT_NETAGENT
;
3566 length
= sizeof(header
.agent_value
);
3567 memcpy(&header
.agent_tlv_header
.type
, &type
, sizeof(type
));
3568 memcpy(&header
.agent_tlv_header
.length
, &length
, sizeof(length
));
3570 struct necp_client_result_netagent agent_struct
;
3571 agent_struct
.generation
= 0;
3572 uuid_copy(agent_struct
.netagent_uuid
, flow
->u
.nexus_agent
);
3574 memcpy(&header
.agent_value
, &agent_struct
, sizeof(agent_struct
));
3577 // Don't include outer TLV header in length field
3578 type
= NECP_CLIENT_RESULT_FLOW
;
3579 length
= (header_length
- sizeof(struct necp_tlv_header
) + flow
->assigned_results_length
);
3580 if (flow
->has_protoctl_event
) {
3581 length
+= sizeof(struct necp_client_flow_protoctl_event_header
);
3583 memcpy(&header
.flow_header
.outer_header
.type
, &type
, sizeof(type
));
3584 memcpy(&header
.flow_header
.outer_header
.length
, &length
, sizeof(length
));
3586 error
= copyout(&header
, uap
->buffer
+ client
->result_length
+ assigned_results_cursor
, header_length
);
3588 NECPLOG(LOG_ERR
, "necp_client_copy assigned results tlv_header copyout error (%d)", error
);
3591 assigned_results_cursor
+= header_length
;
3593 if (flow
->assigned_results
&& flow
->assigned_results_length
) {
3595 error
= copyout(flow
->assigned_results
, uap
->buffer
+ client
->result_length
+ assigned_results_cursor
,
3596 flow
->assigned_results_length
);
3598 NECPLOG(LOG_ERR
, "necp_client_copy assigned results copyout error (%d)", error
);
3602 assigned_results_cursor
+= flow
->assigned_results_length
;
3604 /* Read the protocol event and reset it */
3605 if (flow
->has_protoctl_event
) {
3606 struct necp_client_flow_protoctl_event_header protoctl_event_header
;
3608 type
= NECP_CLIENT_RESULT_PROTO_CTL_EVENT
;
3609 length
= sizeof(protoctl_event_header
.protoctl_event
);
3611 memcpy(&protoctl_event_header
.protoctl_tlv_header
.type
, &type
, sizeof(type
));
3612 memcpy(&protoctl_event_header
.protoctl_tlv_header
.length
, &length
, sizeof(length
));
3613 memcpy(&protoctl_event_header
.protoctl_event
, &flow
->protoctl_event
,
3614 sizeof(flow
->protoctl_event
));
3616 error
= copyout(&protoctl_event_header
, uap
->buffer
+ client
->result_length
+ assigned_results_cursor
,
3617 sizeof(protoctl_event_header
));
3620 NECPLOG(LOG_ERR
, "necp_client_copy protocol control event results"
3621 " tlv_header copyout error (%d)", error
);
3624 assigned_results_cursor
+= sizeof(protoctl_event_header
);
3625 flow
->has_protoctl_event
= FALSE
;
3626 flow
->protoctl_event
.protoctl_event_code
= 0;
3627 flow
->protoctl_event
.protoctl_event_val
= 0;
3628 flow
->protoctl_event
.protoctl_event_tcp_seq_num
= 0;
3633 *retval
= client
->result_length
+ assigned_results_cursor
;
3635 if (!client_is_observed
) {
3636 client
->result_read
= TRUE
;
3637 client
->flow_result_read
= TRUE
;
3646 necp_client_copy(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
3649 struct necp_client
*find_client
= NULL
;
3650 struct necp_client
*client
= NULL
;
3652 uuid_clear(client_id
);
3656 if (uap
->buffer_size
== 0 || uap
->buffer
== 0) {
3661 if (uap
->action
!= NECP_CLIENT_ACTION_COPY_PARAMETERS
&&
3662 uap
->action
!= NECP_CLIENT_ACTION_COPY_RESULT
&&
3663 uap
->action
!= NECP_CLIENT_ACTION_COPY_UPDATED_RESULT
) {
3668 if (uap
->client_id
) {
3669 if (uap
->client_id_len
!= sizeof(uuid_t
)) {
3670 NECPLOG(LOG_ERR
, "Incorrect length (got %d, expected %d)", uap
->client_id_len
, sizeof(uuid_t
));
3675 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
3677 NECPLOG(LOG_ERR
, "necp_client_copy client_id copyin error (%d)", error
);
3682 NECP_FD_LOCK(fd_data
);
3683 RB_FOREACH(find_client
, _necp_client_tree
, &fd_data
->clients
) {
3684 NECP_CLIENT_LOCK(find_client
);
3685 if ((uap
->action
== NECP_CLIENT_ACTION_COPY_RESULT
|| uap
->action
== NECP_CLIENT_ACTION_COPY_UPDATED_RESULT
) &&
3686 uuid_is_null(client_id
)) {
3687 if (!find_client
->result_read
|| !find_client
->flow_result_read
) {
3688 client
= find_client
;
3690 } else if (uuid_compare(find_client
->client_id
, client_id
) == 0) {
3691 client
= find_client
;
3693 NECP_CLIENT_UNLOCK(find_client
);
3694 if (client
!= NULL
) {
3699 if (client
!= NULL
) {
3700 error
= necp_client_copy_internal(client
, FALSE
, uap
, retval
);
3703 // Unlock our own client before moving on or returning
3704 NECP_FD_UNLOCK(fd_data
);
3706 if (client
== NULL
) {
3707 if (fd_data
->flags
& NECP_OPEN_FLAG_OBSERVER
) {
3708 // Observers are allowed to lookup clients on other fds
3711 NECP_CLIENT_TREE_LOCK_SHARED();
3713 bool found_client
= FALSE
;
3715 struct necp_client find
;
3716 uuid_copy(find
.client_id
, client_id
);
3717 client
= RB_FIND(_necp_client_global_tree
, &necp_client_global_tree
, &find
);
3718 if (client
!= NULL
) {
3719 NECP_CLIENT_LOCK(client
);
3721 // Matched, copy out data
3722 found_client
= TRUE
;
3723 error
= necp_client_copy_internal(client
, TRUE
, uap
, retval
);
3725 NECP_CLIENT_UNLOCK(client
);
3729 NECP_CLIENT_TREE_UNLOCK();
3731 // No client found, fail
3732 if (!found_client
) {
3737 // No client found, and not allowed to search other fds, fail
3748 necp_client_copy_client_update(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
3754 if (!(fd_data
->flags
& NECP_OPEN_FLAG_PUSH_OBSERVER
)) {
3755 NECPLOG0(LOG_ERR
, "NECP fd is not observer, cannot copy client update");
3759 if (uap
->client_id_len
!= sizeof(uuid_t
) || uap
->client_id
== 0) {
3760 NECPLOG0(LOG_ERR
, "Client id invalid, cannot copy client update");
3764 if (uap
->buffer_size
== 0 || uap
->buffer
== 0) {
3765 NECPLOG0(LOG_ERR
, "Buffer invalid, cannot copy client update");
3769 NECP_FD_LOCK(fd_data
);
3770 struct necp_client_update
*client_update
= TAILQ_FIRST(&fd_data
->update_list
);
3771 if (client_update
!= NULL
) {
3772 TAILQ_REMOVE(&fd_data
->update_list
, client_update
, chain
);
3773 VERIFY(fd_data
->update_count
> 0);
3774 fd_data
->update_count
--;
3776 NECP_FD_UNLOCK(fd_data
);
3778 if (client_update
!= NULL
) {
3779 error
= copyout(client_update
->client_id
, uap
->client_id
, sizeof(uuid_t
));
3781 NECPLOG(LOG_ERR
, "Copy client update copyout client id error (%d)", error
);
3783 if (uap
->buffer_size
< client_update
->update_length
) {
3784 NECPLOG(LOG_ERR
, "Buffer size cannot hold update (%zu < %zu)", uap
->buffer_size
, client_update
->update_length
);
3787 error
= copyout(&client_update
->update
, uap
->buffer
, client_update
->update_length
);
3789 NECPLOG(LOG_ERR
, "Copy client update copyout error (%d)", error
);
3791 *retval
= client_update
->update_length
;
3796 FREE(client_update
, M_NECP
);
3797 client_update
= NULL
;
3806 necp_client_copy_parameters_locked(struct necp_client
*client
, struct necp_client_nexus_parameters
*parameters
)
3808 VERIFY(parameters
!= NULL
);
3810 struct necp_client_parsed_parameters parsed_parameters
= {};
3811 int error
= necp_client_parse_parameters(client
->parameters
, (u_int32_t
)client
->parameters_length
, &parsed_parameters
);
3813 parameters
->pid
= client
->proc_pid
;
3814 if (parsed_parameters
.valid_fields
& NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_PID
) {
3815 parameters
->epid
= parsed_parameters
.effective_pid
;
3817 parameters
->epid
= parameters
->pid
;
3819 memcpy(¶meters
->local_addr
, &parsed_parameters
.local_addr
, sizeof(parameters
->local_addr
));
3820 memcpy(¶meters
->remote_addr
, &parsed_parameters
.remote_addr
, sizeof(parameters
->remote_addr
));
3821 parameters
->ip_protocol
= parsed_parameters
.ip_protocol
;
3822 parameters
->traffic_class
= parsed_parameters
.traffic_class
;
3823 uuid_copy(parameters
->euuid
, parsed_parameters
.effective_uuid
);
3824 parameters
->is_listener
= (parsed_parameters
.flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) ? 1 : 0;
3825 parameters
->policy_id
= client
->policy_id
;
3827 // parse client result flag
3828 u_int32_t client_result_flags
= 0;
3829 u_int32_t value_size
= 0;
3830 u_int8_t
*flags_pointer
= NULL
;
3831 flags_pointer
= necp_buffer_get_tlv_value(client
->result
, 0, &value_size
);
3832 if (flags_pointer
&& value_size
== sizeof(client_result_flags
)) {
3833 memcpy(&client_result_flags
, flags_pointer
, value_size
);
3835 parameters
->allow_qos_marking
= (client_result_flags
& NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING
) ? 1 : 0;
3841 necp_client_copy_parameters(uuid_t client_id
, struct necp_client_nexus_parameters
*parameters
)
3844 struct necp_client
*client
= NULL
;
3846 if (parameters
== NULL
) {
3851 NECP_CLIENT_TREE_LOCK_SHARED();
3853 bool found_client
= FALSE
;
3854 struct necp_client find
;
3855 uuid_copy(find
.client_id
, client_id
);
3856 client
= RB_FIND(_necp_client_global_tree
, &necp_client_global_tree
, &find
);
3857 if (client
!= NULL
) {
3858 NECP_CLIENT_LOCK(client
);
3860 // Matched, parse parameters
3861 found_client
= TRUE
;
3862 error
= necp_client_copy_parameters_locked(client
, parameters
);
3864 NECP_CLIENT_UNLOCK(client
);
3868 NECP_CLIENT_TREE_UNLOCK();
3870 // No client found, fail
3871 if (!found_client
) {
3879 necp_client_list(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
3882 struct necp_client
*find_client
= NULL
;
3883 uuid_t
*list
= NULL
;
3884 u_int32_t requested_client_count
= 0;
3885 u_int32_t client_count
= 0;
3886 size_t copy_buffer_size
= 0;
3888 if (uap
->buffer_size
< sizeof(requested_client_count
) || uap
->buffer
== 0) {
3893 if (!(fd_data
->flags
& NECP_OPEN_FLAG_OBSERVER
)) {
3894 NECPLOG0(LOG_ERR
, "Client does not hold necessary entitlement to list other NECP clients");
3899 error
= copyin(uap
->buffer
, &requested_client_count
, sizeof(requested_client_count
));
3904 if (os_mul_overflow(sizeof(uuid_t
), requested_client_count
, ©_buffer_size
)) {
3909 if (uap
->buffer_size
- sizeof(requested_client_count
) != copy_buffer_size
) {
3914 if (copy_buffer_size
> NECP_MAX_CLIENT_LIST_SIZE
) {
3919 if (requested_client_count
> 0) {
3920 if ((list
= _MALLOC(copy_buffer_size
, M_NECP
, M_WAITOK
| M_ZERO
)) == NULL
) {
3927 NECP_CLIENT_TREE_LOCK_SHARED();
3930 RB_FOREACH(find_client
, _necp_client_global_tree
, &necp_client_global_tree
) {
3931 NECP_CLIENT_LOCK(find_client
);
3932 if (!uuid_is_null(find_client
->client_id
)) {
3933 if (client_count
< requested_client_count
) {
3934 uuid_copy(list
[client_count
], find_client
->client_id
);
3938 NECP_CLIENT_UNLOCK(find_client
);
3942 NECP_CLIENT_TREE_UNLOCK();
3944 error
= copyout(&client_count
, uap
->buffer
, sizeof(client_count
));
3946 NECPLOG(LOG_ERR
, "necp_client_list buffer copyout error (%d)", error
);
3950 if (requested_client_count
> 0 &&
3953 error
= copyout(list
, uap
->buffer
+ sizeof(client_count
), copy_buffer_size
);
3955 NECPLOG(LOG_ERR
, "necp_client_list client count copyout error (%d)", error
);
3970 necp_client_add_assertion(struct necp_client
*client
, uuid_t netagent_uuid
)
3972 struct necp_client_assertion
*new_assertion
= NULL
;
3974 MALLOC(new_assertion
, struct necp_client_assertion
*, sizeof(*new_assertion
), M_NECP
, M_WAITOK
);
3975 if (new_assertion
== NULL
) {
3976 NECPLOG0(LOG_ERR
, "Failed to allocate assertion");
3980 uuid_copy(new_assertion
->asserted_netagent
, netagent_uuid
);
3982 LIST_INSERT_HEAD(&client
->assertion_list
, new_assertion
, assertion_chain
);
3986 necp_client_remove_assertion(struct necp_client
*client
, uuid_t netagent_uuid
)
3988 struct necp_client_assertion
*found_assertion
= NULL
;
3989 struct necp_client_assertion
*search_assertion
= NULL
;
3990 LIST_FOREACH(search_assertion
, &client
->assertion_list
, assertion_chain
) {
3991 if (uuid_compare(search_assertion
->asserted_netagent
, netagent_uuid
) == 0) {
3992 found_assertion
= search_assertion
;
3997 if (found_assertion
== NULL
) {
3998 NECPLOG0(LOG_ERR
, "Netagent uuid not previously asserted");
4002 LIST_REMOVE(found_assertion
, assertion_chain
);
4003 FREE(found_assertion
, M_NECP
);
4008 necp_client_agent_action(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
4011 struct necp_client
*client
= NULL
;
4013 bool acted_on_agent
= FALSE
;
4014 u_int8_t
*parameters
= NULL
;
4015 size_t parameters_size
= uap
->buffer_size
;
4017 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
4018 uap
->buffer_size
== 0 || uap
->buffer
== 0) {
4023 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
4025 NECPLOG(LOG_ERR
, "necp_client_agent_action copyin client_id error (%d)", error
);
4029 if ((parameters
= _MALLOC(uap
->buffer_size
, M_NECP
, M_WAITOK
| M_ZERO
)) == NULL
) {
4034 error
= copyin(uap
->buffer
, parameters
, uap
->buffer_size
);
4036 NECPLOG(LOG_ERR
, "necp_client_agent_action parameters copyin error (%d)", error
);
4040 NECP_FD_LOCK(fd_data
);
4041 client
= necp_client_fd_find_client_and_lock(fd_data
, client_id
);
4042 if (client
!= NULL
) {
4044 while ((offset
+ sizeof(struct necp_tlv_header
)) <= parameters_size
) {
4045 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
4046 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
4048 if (length
> (parameters_size
- (offset
+ sizeof(struct necp_tlv_header
)))) {
4049 // If the length is larger than what can fit in the remaining parameters size, bail
4050 NECPLOG(LOG_ERR
, "Invalid TLV length (%u)", length
);
4055 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
4056 if (length
>= sizeof(uuid_t
) &&
4058 (type
== NECP_CLIENT_PARAMETER_TRIGGER_AGENT
||
4059 type
== NECP_CLIENT_PARAMETER_ASSERT_AGENT
||
4060 type
== NECP_CLIENT_PARAMETER_UNASSERT_AGENT
)) {
4063 uuid_copy(agent_uuid
, value
);
4064 u_int8_t netagent_message_type
= 0;
4065 if (type
== NECP_CLIENT_PARAMETER_TRIGGER_AGENT
) {
4066 netagent_message_type
= NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER
;
4067 } else if (type
== NECP_CLIENT_PARAMETER_ASSERT_AGENT
) {
4068 netagent_message_type
= NETAGENT_MESSAGE_TYPE_CLIENT_ASSERT
;
4069 } else if (type
== NECP_CLIENT_PARAMETER_UNASSERT_AGENT
) {
4070 netagent_message_type
= NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT
;
4073 // Before unasserting, verify that the assertion was already taken
4074 if (type
== NECP_CLIENT_PARAMETER_UNASSERT_AGENT
) {
4075 if (!necp_client_remove_assertion(client
, agent_uuid
)) {
4081 struct necp_client_nexus_parameters parsed_parameters
= {};
4082 necp_client_copy_parameters_locked(client
, &parsed_parameters
);
4084 error
= netagent_client_message_with_params(agent_uuid
,
4087 netagent_message_type
,
4091 acted_on_agent
= TRUE
;
4096 // Only save the assertion if the action succeeded
4097 if (type
== NECP_CLIENT_PARAMETER_ASSERT_AGENT
) {
4098 necp_client_add_assertion(client
, agent_uuid
);
4103 offset
+= sizeof(struct necp_tlv_header
) + length
;
4106 NECP_CLIENT_UNLOCK(client
);
4108 NECP_FD_UNLOCK(fd_data
);
4110 if (!acted_on_agent
&&
4116 if (parameters
!= NULL
) {
4117 FREE(parameters
, M_NECP
);
4125 necp_client_copy_agent(__unused
struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
4130 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
4131 uap
->buffer_size
== 0 || uap
->buffer
== 0) {
4132 NECPLOG0(LOG_ERR
, "necp_client_copy_agent bad input");
4137 error
= copyin(uap
->client_id
, agent_uuid
, sizeof(uuid_t
));
4139 NECPLOG(LOG_ERR
, "necp_client_copy_agent copyin agent_uuid error (%d)", error
);
4143 error
= netagent_copyout(agent_uuid
, uap
->buffer
, uap
->buffer_size
);
4145 // netagent_copyout already logs appropriate errors
4155 necp_client_agent_use(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
4158 struct necp_client
*client
= NULL
;
4160 struct necp_agent_use_parameters parameters
;
4162 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
4163 uap
->buffer_size
!= sizeof(parameters
) || uap
->buffer
== 0) {
4168 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
4170 NECPLOG(LOG_ERR
, "Copyin client_id error (%d)", error
);
4174 error
= copyin(uap
->buffer
, ¶meters
, uap
->buffer_size
);
4176 NECPLOG(LOG_ERR
, "Parameters copyin error (%d)", error
);
4180 NECP_FD_LOCK(fd_data
);
4181 client
= necp_client_fd_find_client_and_lock(fd_data
, client_id
);
4182 if (client
!= NULL
) {
4183 error
= netagent_use(parameters
.agent_uuid
, ¶meters
.out_use_count
);
4184 NECP_CLIENT_UNLOCK(client
);
4189 NECP_FD_UNLOCK(fd_data
);
4192 error
= copyout(¶meters
, uap
->buffer
, uap
->buffer_size
);
4194 NECPLOG(LOG_ERR
, "Parameters copyout error (%d)", error
);
4206 necp_client_copy_interface(__unused
struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
4209 u_int32_t interface_index
= 0;
4210 struct necp_interface_details interface_details
;
4212 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(u_int32_t
) ||
4213 uap
->buffer_size
< sizeof(interface_details
) || uap
->buffer
== 0) {
4214 NECPLOG0(LOG_ERR
, "necp_client_copy_interface bad input");
4219 error
= copyin(uap
->client_id
, &interface_index
, sizeof(u_int32_t
));
4221 NECPLOG(LOG_ERR
, "necp_client_copy_interface copyin interface_index error (%d)", error
);
4225 if (interface_index
== 0) {
4227 NECPLOG(LOG_ERR
, "necp_client_copy_interface bad interface_index (%d)", interface_index
);
4231 memset(&interface_details
, 0, sizeof(interface_details
));
4233 ifnet_head_lock_shared();
4234 ifnet_t interface
= NULL
;
4235 if (interface_index
!= IFSCOPE_NONE
&& interface_index
<= (u_int32_t
)if_index
) {
4236 interface
= ifindex2ifnet
[interface_index
];
4239 if (interface
!= NULL
) {
4240 if (interface
->if_xname
!= NULL
) {
4241 strlcpy((char *)&interface_details
.name
, interface
->if_xname
, sizeof(interface_details
.name
));
4243 interface_details
.index
= interface
->if_index
;
4244 interface_details
.generation
= ifnet_get_generation(interface
);
4245 if (interface
->if_delegated
.ifp
!= NULL
) {
4246 interface_details
.delegate_index
= interface
->if_delegated
.ifp
->if_index
;
4248 interface_details
.functional_type
= if_functional_type(interface
, TRUE
);
4249 if (IFNET_IS_EXPENSIVE(interface
)) {
4250 interface_details
.flags
|= NECP_INTERFACE_FLAG_EXPENSIVE
;
4252 if ((interface
->if_eflags
& IFEF_TXSTART
) == IFEF_TXSTART
) {
4253 interface_details
.flags
|= NECP_INTERFACE_FLAG_TXSTART
;
4255 if ((interface
->if_eflags
& IFEF_NOACKPRI
) == IFEF_NOACKPRI
) {
4256 interface_details
.flags
|= NECP_INTERFACE_FLAG_NOACKPRI
;
4258 interface_details
.mtu
= interface
->if_mtu
;
4260 u_int8_t ipv4_signature_len
= sizeof(interface_details
.ipv4_signature
.signature
);
4261 u_int16_t ipv4_signature_flags
;
4262 if (ifnet_get_netsignature(interface
, AF_INET
, &ipv4_signature_len
, &ipv4_signature_flags
,
4263 (u_int8_t
*)&interface_details
.ipv4_signature
) != 0) {
4264 ipv4_signature_len
= 0;
4266 interface_details
.ipv4_signature
.signature_len
= ipv4_signature_len
;
4268 u_int8_t ipv6_signature_len
= sizeof(interface_details
.ipv6_signature
.signature
);
4269 u_int16_t ipv6_signature_flags
;
4270 if (ifnet_get_netsignature(interface
, AF_INET6
, &ipv6_signature_len
, &ipv6_signature_flags
,
4271 (u_int8_t
*)&interface_details
.ipv6_signature
) != 0) {
4272 ipv6_signature_len
= 0;
4274 interface_details
.ipv6_signature
.signature_len
= ipv6_signature_len
;
4279 error
= copyout(&interface_details
, uap
->buffer
, sizeof(interface_details
));
4281 NECPLOG(LOG_ERR
, "necp_client_copy_interface copyout error (%d)", error
);
4292 necp_client_copy_route_statistics(__unused
struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
4295 struct necp_client
*client
= NULL
;
4298 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
4299 uap
->buffer_size
< sizeof(struct necp_stat_counts
) || uap
->buffer
== 0) {
4300 NECPLOG0(LOG_ERR
, "necp_client_copy_route_statistics bad input");
4305 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
4307 NECPLOG(LOG_ERR
, "necp_client_copy_route_statistics copyin client_id error (%d)", error
);
4312 NECP_FD_LOCK(fd_data
);
4313 client
= necp_client_fd_find_client_and_lock(fd_data
, client_id
);
4314 if (client
!= NULL
) {
4315 NECP_CLIENT_ROUTE_LOCK(client
);
4316 struct nstat_counts route_stats
= {};
4317 if (client
->current_route
!= NULL
&& client
->current_route
->rt_stats
!= NULL
) {
4318 struct nstat_counts
*rt_stats
= client
->current_route
->rt_stats
;
4319 atomic_get_64(route_stats
.nstat_rxpackets
, &rt_stats
->nstat_rxpackets
);
4320 atomic_get_64(route_stats
.nstat_rxbytes
, &rt_stats
->nstat_rxbytes
);
4321 atomic_get_64(route_stats
.nstat_txpackets
, &rt_stats
->nstat_txpackets
);
4322 atomic_get_64(route_stats
.nstat_txbytes
, &rt_stats
->nstat_txbytes
);
4323 route_stats
.nstat_rxduplicatebytes
= rt_stats
->nstat_rxduplicatebytes
;
4324 route_stats
.nstat_rxoutoforderbytes
= rt_stats
->nstat_rxoutoforderbytes
;
4325 route_stats
.nstat_txretransmit
= rt_stats
->nstat_txretransmit
;
4326 route_stats
.nstat_connectattempts
= rt_stats
->nstat_connectattempts
;
4327 route_stats
.nstat_connectsuccesses
= rt_stats
->nstat_connectsuccesses
;
4328 route_stats
.nstat_min_rtt
= rt_stats
->nstat_min_rtt
;
4329 route_stats
.nstat_avg_rtt
= rt_stats
->nstat_avg_rtt
;
4330 route_stats
.nstat_var_rtt
= rt_stats
->nstat_var_rtt
;
4333 // Unlock before copying out
4334 NECP_CLIENT_ROUTE_UNLOCK(client
);
4335 NECP_CLIENT_UNLOCK(client
);
4336 NECP_FD_UNLOCK(fd_data
);
4338 error
= copyout(&route_stats
, uap
->buffer
, sizeof(route_stats
));
4340 NECPLOG(LOG_ERR
, "necp_client_copy_route_statistics copyout error (%d)", error
);
4344 NECP_FD_UNLOCK(fd_data
);
4355 necp_client_update_cache(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
4358 struct necp_client
*client
= NULL
;
4361 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
)) {
4366 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
4368 NECPLOG(LOG_ERR
, "necp_client_update_cache copyin client_id error (%d)", error
);
4372 NECP_FD_LOCK(fd_data
);
4373 client
= necp_client_fd_find_client_and_lock(fd_data
, client_id
);
4374 if (client
== NULL
) {
4375 NECP_FD_UNLOCK(fd_data
);
4380 NECP_CLIENT_ROUTE_LOCK(client
);
4381 // This needs to be changed when TFO/ECN is supported by multiple flows
4382 struct necp_client_flow
*flow
= LIST_FIRST(&client
->flow_list
);
4384 (flow
->remote_addr
.sa
.sa_family
!= AF_INET
&&
4385 flow
->remote_addr
.sa
.sa_family
!= AF_INET6
) ||
4386 (flow
->local_addr
.sa
.sa_family
!= AF_INET
&&
4387 flow
->local_addr
.sa
.sa_family
!= AF_INET6
)) {
4389 NECPLOG(LOG_ERR
, "necp_client_update_cache no flow error (%d)", error
);
4393 necp_cache_buffer cache_buffer
;
4394 memset(&cache_buffer
, 0, sizeof(cache_buffer
));
4396 if (uap
->buffer_size
!= sizeof(necp_cache_buffer
) ||
4397 uap
->buffer
== USER_ADDR_NULL
) {
4402 error
= copyin(uap
->buffer
, &cache_buffer
, sizeof(cache_buffer
));
4404 NECPLOG(LOG_ERR
, "necp_client_update_cache copyin cache buffer error (%d)", error
);
4408 if (cache_buffer
.necp_cache_buf_type
== NECP_CLIENT_CACHE_TYPE_ECN
&&
4409 cache_buffer
.necp_cache_buf_ver
== NECP_CLIENT_CACHE_TYPE_ECN_VER_1
) {
4410 if (cache_buffer
.necp_cache_buf_size
!= sizeof(necp_tcp_ecn_cache
) ||
4411 cache_buffer
.necp_cache_buf_addr
== USER_ADDR_NULL
) {
4416 necp_tcp_ecn_cache ecn_cache_buffer
;
4417 memset(&ecn_cache_buffer
, 0, sizeof(ecn_cache_buffer
));
4419 error
= copyin(cache_buffer
.necp_cache_buf_addr
, &ecn_cache_buffer
, sizeof(necp_tcp_ecn_cache
));
4421 NECPLOG(LOG_ERR
, "necp_client_update_cache copyin ecn cache buffer error (%d)", error
);
4425 if (client
->current_route
!= NULL
&& client
->current_route
->rt_ifp
!= NULL
) {
4426 if (!client
->platform_binary
) {
4427 ecn_cache_buffer
.necp_tcp_ecn_heuristics_success
= 0;
4429 tcp_heuristics_ecn_update(&ecn_cache_buffer
, client
->current_route
->rt_ifp
,
4430 (union sockaddr_in_4_6
*)&flow
->local_addr
);
4432 } else if (cache_buffer
.necp_cache_buf_type
== NECP_CLIENT_CACHE_TYPE_TFO
&&
4433 cache_buffer
.necp_cache_buf_ver
== NECP_CLIENT_CACHE_TYPE_TFO_VER_1
) {
4434 if (cache_buffer
.necp_cache_buf_size
!= sizeof(necp_tcp_tfo_cache
) ||
4435 cache_buffer
.necp_cache_buf_addr
== USER_ADDR_NULL
) {
4440 necp_tcp_tfo_cache tfo_cache_buffer
;
4441 memset(&tfo_cache_buffer
, 0, sizeof(tfo_cache_buffer
));
4443 error
= copyin(cache_buffer
.necp_cache_buf_addr
, &tfo_cache_buffer
, sizeof(necp_tcp_tfo_cache
));
4445 NECPLOG(LOG_ERR
, "necp_client_update_cache copyin tfo cache buffer error (%d)", error
);
4449 if (client
->current_route
!= NULL
&& client
->current_route
->rt_ifp
!= NULL
) {
4450 if (!client
->platform_binary
) {
4451 tfo_cache_buffer
.necp_tcp_tfo_heuristics_success
= 0;
4453 tcp_heuristics_tfo_update(&tfo_cache_buffer
, client
->current_route
->rt_ifp
,
4454 (union sockaddr_in_4_6
*)&flow
->local_addr
,
4455 (union sockaddr_in_4_6
*)&flow
->remote_addr
);
4461 NECP_CLIENT_ROUTE_UNLOCK(client
);
4462 NECP_CLIENT_UNLOCK(client
);
4463 NECP_FD_UNLOCK(fd_data
);
4470 necp_client_action(struct proc
*p
, struct necp_client_action_args
*uap
, int *retval
)
4474 int return_value
= 0;
4475 struct necp_fd_data
*fd_data
= NULL
;
4476 error
= necp_find_fd_data(uap
->necp_fd
, &fd_data
);
4478 NECPLOG(LOG_ERR
, "necp_client_action find fd error (%d)", error
);
4482 u_int32_t action
= uap
->action
;
4484 case NECP_CLIENT_ACTION_ADD
: {
4485 return_value
= necp_client_add(p
, fd_data
, uap
, retval
);
4488 case NECP_CLIENT_ACTION_REMOVE
: {
4489 return_value
= necp_client_remove(fd_data
, uap
, retval
);
4492 case NECP_CLIENT_ACTION_COPY_PARAMETERS
:
4493 case NECP_CLIENT_ACTION_COPY_RESULT
:
4494 case NECP_CLIENT_ACTION_COPY_UPDATED_RESULT
: {
4495 return_value
= necp_client_copy(fd_data
, uap
, retval
);
4498 case NECP_CLIENT_ACTION_COPY_LIST
: {
4499 return_value
= necp_client_list(fd_data
, uap
, retval
);
4502 case NECP_CLIENT_ACTION_AGENT
: {
4503 return_value
= necp_client_agent_action(fd_data
, uap
, retval
);
4506 case NECP_CLIENT_ACTION_COPY_AGENT
: {
4507 return_value
= necp_client_copy_agent(fd_data
, uap
, retval
);
4510 case NECP_CLIENT_ACTION_AGENT_USE
: {
4511 return_value
= necp_client_agent_use(fd_data
, uap
, retval
);
4514 case NECP_CLIENT_ACTION_COPY_INTERFACE
: {
4515 return_value
= necp_client_copy_interface(fd_data
, uap
, retval
);
4518 case NECP_CLIENT_ACTION_COPY_ROUTE_STATISTICS
: {
4519 return_value
= necp_client_copy_route_statistics(fd_data
, uap
, retval
);
4522 case NECP_CLIENT_ACTION_UPDATE_CACHE
: {
4523 return_value
= necp_client_update_cache(fd_data
, uap
, retval
);
4526 case NECP_CLIENT_ACTION_COPY_CLIENT_UPDATE
: {
4527 return_value
= necp_client_copy_client_update(fd_data
, uap
, retval
);
4531 NECPLOG(LOG_ERR
, "necp_client_action unknown action (%u)", action
);
4532 return_value
= EINVAL
;
4537 file_drop(uap
->necp_fd
);
4539 return (return_value
);
4542 #define NECP_MAX_MATCH_POLICY_PARAMETER_SIZE 1024
4545 necp_match_policy(struct proc
*p
, struct necp_match_policy_args
*uap
, int32_t *retval
)
4547 #pragma unused(retval)
4548 u_int8_t
*parameters
= NULL
;
4549 struct necp_aggregate_result returned_result
;
4557 if (uap
->parameters
== 0 || uap
->parameters_size
== 0 || uap
->parameters_size
> NECP_MAX_MATCH_POLICY_PARAMETER_SIZE
|| uap
->returned_result
== 0) {
4562 MALLOC(parameters
, u_int8_t
*, uap
->parameters_size
, M_NECP
, M_WAITOK
| M_ZERO
);
4563 if (parameters
== NULL
) {
4567 // Copy parameters in
4568 error
= copyin(uap
->parameters
, parameters
, uap
->parameters_size
);
4573 error
= necp_application_find_policy_match_internal(p
, parameters
, uap
->parameters_size
,
4574 &returned_result
, NULL
, 0, NULL
, NULL
, NULL
, false);
4579 // Copy return value back
4580 error
= copyout(&returned_result
, uap
->returned_result
, sizeof(struct necp_aggregate_result
));
4585 if (parameters
!= NULL
) {
4586 FREE(parameters
, M_NECP
);
4591 /// Socket operations
4592 #define NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH 253
4595 necp_set_socket_attribute(u_int8_t
*buffer
, size_t buffer_length
, u_int8_t type
, char **buffer_p
)
4599 size_t string_size
= 0;
4600 char *local_string
= NULL
;
4601 u_int8_t
*value
= NULL
;
4603 cursor
= necp_buffer_find_tlv(buffer
, buffer_length
, 0, type
, 0);
4605 // This will clear out the parameter
4609 string_size
= necp_buffer_get_tlv_length(buffer
, cursor
);
4610 if (string_size
== 0 || string_size
> NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH
) {
4611 // This will clear out the parameter
4615 MALLOC(local_string
, char *, string_size
+ 1, M_NECP
, M_WAITOK
| M_ZERO
);
4616 if (local_string
== NULL
) {
4617 NECPLOG(LOG_ERR
, "Failed to allocate a socket attribute buffer (size %d)", string_size
);
4621 value
= necp_buffer_get_tlv_value(buffer
, cursor
, NULL
);
4622 if (value
== NULL
) {
4623 NECPLOG0(LOG_ERR
, "Failed to get socket attribute");
4627 memcpy(local_string
, value
, string_size
);
4628 local_string
[string_size
] = 0;
4631 if (*buffer_p
!= NULL
) {
4632 FREE(*buffer_p
, M_NECP
);
4636 *buffer_p
= local_string
;
4639 if (local_string
!= NULL
) {
4640 FREE(local_string
, M_NECP
);
4646 necp_set_socket_attributes(struct socket
*so
, struct sockopt
*sopt
)
4649 u_int8_t
*buffer
= NULL
;
4650 struct inpcb
*inp
= NULL
;
4652 if ((SOCK_DOM(so
) != PF_INET
4654 && SOCK_DOM(so
) != PF_INET6
4661 inp
= sotoinpcb(so
);
4663 size_t valsize
= sopt
->sopt_valsize
;
4665 valsize
> ((sizeof(struct necp_tlv_header
) + NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH
) * 2)) {
4669 MALLOC(buffer
, u_int8_t
*, valsize
, M_NECP
, M_WAITOK
| M_ZERO
);
4670 if (buffer
== NULL
) {
4674 error
= sooptcopyin(sopt
, buffer
, valsize
, 0);
4679 error
= necp_set_socket_attribute(buffer
, valsize
, NECP_TLV_ATTRIBUTE_DOMAIN
, &inp
->inp_necp_attributes
.inp_domain
);
4681 NECPLOG0(LOG_ERR
, "Could not set domain TLV for socket attributes");
4685 error
= necp_set_socket_attribute(buffer
, valsize
, NECP_TLV_ATTRIBUTE_ACCOUNT
, &inp
->inp_necp_attributes
.inp_account
);
4687 NECPLOG0(LOG_ERR
, "Could not set account TLV for socket attributes");
4692 NECPLOG(LOG_DEBUG
, "Set on socket: Domain %s, Account %s", inp
->inp_necp_attributes
.inp_domain
, inp
->inp_necp_attributes
.inp_account
);
4695 if (buffer
!= NULL
) {
4696 FREE(buffer
, M_NECP
);
4703 necp_get_socket_attributes(struct socket
*so
, struct sockopt
*sopt
)
4706 u_int8_t
*buffer
= NULL
;
4707 u_int8_t
*cursor
= NULL
;
4709 struct inpcb
*inp
= NULL
;
4711 if ((SOCK_DOM(so
) != PF_INET
4713 && SOCK_DOM(so
) != PF_INET6
4720 inp
= sotoinpcb(so
);
4721 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
4722 valsize
+= sizeof(struct necp_tlv_header
) + strlen(inp
->inp_necp_attributes
.inp_domain
);
4724 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
4725 valsize
+= sizeof(struct necp_tlv_header
) + strlen(inp
->inp_necp_attributes
.inp_account
);
4731 MALLOC(buffer
, u_int8_t
*, valsize
, M_NECP
, M_WAITOK
| M_ZERO
);
4732 if (buffer
== NULL
) {
4737 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
4738 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ATTRIBUTE_DOMAIN
, strlen(inp
->inp_necp_attributes
.inp_domain
), inp
->inp_necp_attributes
.inp_domain
,
4742 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
4743 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ATTRIBUTE_ACCOUNT
, strlen(inp
->inp_necp_attributes
.inp_account
), inp
->inp_necp_attributes
.inp_account
,
4747 error
= sooptcopyout(sopt
, buffer
, valsize
);
4752 if (buffer
!= NULL
) {
4753 FREE(buffer
, M_NECP
);
4760 necp_create_nexus_assign_message(uuid_t nexus_instance
, u_int32_t nexus_port
, void *key
, uint32_t key_length
,
4761 struct necp_client_endpoint
*local_endpoint
, struct necp_client_endpoint
*remote_endpoint
,
4762 u_int32_t flow_adv_index
, size_t *message_length
)
4764 u_int8_t
*buffer
= NULL
;
4765 u_int8_t
*cursor
= NULL
;
4767 bool has_nexus_assignment
= FALSE
;
4770 if (!uuid_is_null(nexus_instance
)) {
4771 has_nexus_assignment
= TRUE
;
4772 valsize
+= sizeof(struct necp_tlv_header
) + sizeof(uuid_t
);
4773 valsize
+= sizeof(struct necp_tlv_header
) + sizeof(u_int32_t
);
4775 if (flow_adv_index
!= NECP_FLOWADV_IDX_INVALID
) {
4776 valsize
+= sizeof(struct necp_tlv_header
) + sizeof(u_int32_t
);
4778 if (key
!= NULL
&& key_length
> 0) {
4779 valsize
+= sizeof(struct necp_tlv_header
) + key_length
;
4781 if (local_endpoint
!= NULL
) {
4782 valsize
+= sizeof(struct necp_tlv_header
) + sizeof(struct necp_client_endpoint
);
4784 if (remote_endpoint
!= NULL
) {
4785 valsize
+= sizeof(struct necp_tlv_header
) + sizeof(struct necp_client_endpoint
);
4791 MALLOC(buffer
, u_int8_t
*, valsize
, M_NETAGENT
, M_WAITOK
| M_ZERO
); // Use M_NETAGENT area, since it is expected upon free
4792 if (buffer
== NULL
) {
4797 if (has_nexus_assignment
) {
4798 cursor
= necp_buffer_write_tlv(cursor
, NECP_CLIENT_RESULT_NEXUS_INSTANCE
, sizeof(uuid_t
), nexus_instance
, buffer
, valsize
);
4799 cursor
= necp_buffer_write_tlv(cursor
, NECP_CLIENT_RESULT_NEXUS_PORT
, sizeof(u_int32_t
), &nexus_port
, buffer
, valsize
);
4801 if (flow_adv_index
!= NECP_FLOWADV_IDX_INVALID
) {
4802 cursor
= necp_buffer_write_tlv(cursor
, NECP_CLIENT_RESULT_NEXUS_PORT_FLOW_INDEX
, sizeof(u_int32_t
), &flow_adv_index
, buffer
, valsize
);
4804 if (key
!= NULL
&& key_length
> 0) {
4805 cursor
= necp_buffer_write_tlv(cursor
, NECP_CLIENT_PARAMETER_NEXUS_KEY
, key_length
, key
, buffer
, valsize
);
4807 if (local_endpoint
!= NULL
) {
4808 cursor
= necp_buffer_write_tlv(cursor
, NECP_CLIENT_RESULT_LOCAL_ENDPOINT
, sizeof(struct necp_client_endpoint
), local_endpoint
, buffer
, valsize
);
4810 if (remote_endpoint
!= NULL
) {
4811 cursor
= necp_buffer_write_tlv(cursor
, NECP_CLIENT_RESULT_REMOTE_ENDPOINT
, sizeof(struct necp_client_endpoint
), remote_endpoint
, buffer
, valsize
);
4814 *message_length
= valsize
;
4820 necp_inpcb_remove_cb(struct inpcb
*inp
)
4822 if (!uuid_is_null(inp
->necp_client_uuid
)) {
4823 necp_client_unregister_socket_flow(inp
->necp_client_uuid
, inp
);
4824 uuid_clear(inp
->necp_client_uuid
);
4829 necp_inpcb_dispose(struct inpcb
*inp
)
4831 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
4832 FREE(inp
->inp_necp_attributes
.inp_domain
, M_NECP
);
4833 inp
->inp_necp_attributes
.inp_domain
= NULL
;
4835 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
4836 FREE(inp
->inp_necp_attributes
.inp_account
, M_NECP
);
4837 inp
->inp_necp_attributes
.inp_account
= NULL
;
4842 necp_mppcb_dispose(struct mppcb
*mpp
)
4844 if (!uuid_is_null(mpp
->necp_client_uuid
)) {
4845 necp_client_unregister_multipath_cb(mpp
->necp_client_uuid
, mpp
);
4846 uuid_clear(mpp
->necp_client_uuid
);
4853 necp_client_init(void)
4857 necp_fd_grp_attr
= lck_grp_attr_alloc_init();
4858 if (necp_fd_grp_attr
== NULL
) {
4859 NECPLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed");
4864 necp_fd_mtx_grp
= lck_grp_alloc_init("necp_fd", necp_fd_grp_attr
);
4865 if (necp_fd_mtx_grp
== NULL
) {
4866 NECPLOG0(LOG_ERR
, "lck_grp_alloc_init failed");
4871 necp_fd_mtx_attr
= lck_attr_alloc_init();
4872 if (necp_fd_mtx_attr
== NULL
) {
4873 NECPLOG0(LOG_ERR
, "lck_attr_alloc_init failed");
4878 necp_client_fd_size
= sizeof(struct necp_fd_data
);
4879 necp_client_fd_zone
= zinit(necp_client_fd_size
,
4880 NECP_CLIENT_FD_ZONE_MAX
* necp_client_fd_size
,
4881 0, NECP_CLIENT_FD_ZONE_NAME
);
4882 if (necp_client_fd_zone
== NULL
) {
4883 NECPLOG0(LOG_ERR
, "zinit(necp_client_fd) failed");
4888 necp_flow_size
= sizeof(struct necp_client_flow
);
4889 necp_flow_zone
= zinit(necp_flow_size
,
4890 NECP_FLOW_ZONE_MAX
* necp_flow_size
,
4891 0, NECP_FLOW_ZONE_NAME
);
4892 if (necp_flow_zone
== NULL
) {
4893 NECPLOG0(LOG_ERR
, "zinit(necp_flow) failed");
4898 necp_client_update_tcall
= thread_call_allocate_with_options(necp_update_all_clients_callout
, NULL
,
4899 THREAD_CALL_PRIORITY_KERNEL
, THREAD_CALL_OPTIONS_ONCE
);
4900 VERIFY(necp_client_update_tcall
!= NULL
);
4902 lck_rw_init(&necp_fd_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
4903 lck_rw_init(&necp_observer_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
4904 lck_rw_init(&necp_client_tree_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
4905 lck_rw_init(&necp_collect_stats_list_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
4907 LIST_INIT(&necp_fd_list
);
4908 LIST_INIT(&necp_fd_observer_list
);
4909 LIST_INIT(&necp_collect_stats_client_list
);
4911 RB_INIT(&necp_client_global_tree
);
4915 if (necp_fd_mtx_attr
!= NULL
) {
4916 lck_attr_free(necp_fd_mtx_attr
);
4917 necp_fd_mtx_attr
= NULL
;
4919 if (necp_fd_mtx_grp
!= NULL
) {
4920 lck_grp_free(necp_fd_mtx_grp
);
4921 necp_fd_mtx_grp
= NULL
;
4923 if (necp_fd_grp_attr
!= NULL
) {
4924 lck_grp_attr_free(necp_fd_grp_attr
);
4925 necp_fd_grp_attr
= NULL
;