2 * Copyright (c) 2015-2018 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__
));
277 RB_ENTRY(necp_client
) link
;
278 RB_ENTRY(necp_client
) global_link
;
279 LIST_ENTRY(necp_client
) collect_stats_chain
;
281 decl_lck_mtx_data(, lock
);
282 decl_lck_mtx_data(, route_lock
);
283 uint32_t reference_count
;
286 unsigned result_read
: 1;
287 unsigned flow_result_read
: 1;
288 unsigned allow_multiple_flows
: 1;
290 unsigned defunct
: 1;
291 unsigned background
: 1;
292 unsigned background_update
: 1;
293 unsigned platform_binary
: 1;
295 size_t result_length
;
296 u_int8_t result
[NECP_MAX_CLIENT_RESULT_SIZE
];
298 necp_policy_id policy_id
;
300 u_int16_t ip_protocol
;
303 LIST_HEAD(_necp_client_flow_list
, necp_client_flow
) flow_list
;
304 LIST_HEAD(_necp_client_assertion_list
, necp_client_assertion
) assertion_list
;
306 struct rtentry
*current_route
;
308 void *interface_handle
;
309 void (*interface_cb
)(void *handle
, int action
, struct necp_client_flow
*flow
);
311 size_t parameters_length
;
312 u_int8_t parameters
[0];
315 #define NECP_CLIENT_LOCK(_c) lck_mtx_lock(&_c->lock)
316 #define NECP_CLIENT_UNLOCK(_c) lck_mtx_unlock(&_c->lock)
317 #define NECP_CLIENT_ASSERT_LOCKED(_c) LCK_MTX_ASSERT(&_c->lock, LCK_MTX_ASSERT_OWNED)
318 #define NECP_CLIENT_ASSERT_UNLOCKED(_c) LCK_MTX_ASSERT(&_c->lock, LCK_MTX_ASSERT_NOTOWNED)
320 #define NECP_CLIENT_ROUTE_LOCK(_c) lck_mtx_lock(&_c->route_lock)
321 #define NECP_CLIENT_ROUTE_UNLOCK(_c) lck_mtx_unlock(&_c->route_lock)
323 static void necp_client_retain_locked(struct necp_client
*client
);
324 static void necp_client_retain(struct necp_client
*client
);
325 static bool necp_client_release_locked(struct necp_client
*client
);
328 necp_client_add_assertion(struct necp_client
*client
, uuid_t netagent_uuid
);
331 necp_client_remove_assertion(struct necp_client
*client
, uuid_t netagent_uuid
);
333 LIST_HEAD(_necp_client_list
, necp_client
);
334 static struct _necp_client_list necp_collect_stats_client_list
;
336 struct necp_client_defunct
{
337 LIST_ENTRY(necp_client_defunct
) chain
;
344 LIST_HEAD(_necp_client_defunct_list
, necp_client_defunct
);
346 static int necp_client_id_cmp(struct necp_client
*client0
, struct necp_client
*client1
);
348 RB_HEAD(_necp_client_tree
, necp_client
);
349 RB_PROTOTYPE_PREV(_necp_client_tree
, necp_client
, link
, necp_client_id_cmp
);
350 RB_GENERATE_PREV(_necp_client_tree
, necp_client
, link
, necp_client_id_cmp
);
352 RB_HEAD(_necp_client_global_tree
, necp_client
);
353 RB_PROTOTYPE_PREV(_necp_client_global_tree
, necp_client
, global_link
, necp_client_id_cmp
);
354 RB_GENERATE_PREV(_necp_client_global_tree
, necp_client
, global_link
, necp_client_id_cmp
);
356 static struct _necp_client_global_tree necp_client_global_tree
;
358 struct necp_client_update
{
359 TAILQ_ENTRY(necp_client_update
) chain
;
363 size_t update_length
;
364 struct necp_client_observer_update update
;
368 struct necp_fd_data
{
369 u_int8_t necp_fd_type
;
370 LIST_ENTRY(necp_fd_data
) chain
;
371 struct _necp_client_tree clients
;
372 TAILQ_HEAD(_necp_client_update_list
, necp_client_update
) update_list
;
376 decl_lck_mtx_data(, fd_lock
);
380 #define NECP_FD_LOCK(_f) lck_mtx_lock(&_f->fd_lock)
381 #define NECP_FD_UNLOCK(_f) lck_mtx_unlock(&_f->fd_lock)
382 #define NECP_FD_ASSERT_LOCKED(_f) LCK_MTX_ASSERT(&_f->fd_lock, LCK_MTX_ASSERT_OWNED)
383 #define NECP_FD_ASSERT_UNLOCKED(_f) LCK_MTX_ASSERT(&_f->fd_lock, LCK_MTX_ASSERT_NOTOWNED)
385 static LIST_HEAD(_necp_fd_list
, necp_fd_data
) necp_fd_list
;
386 static LIST_HEAD(_necp_fd_observer_list
, necp_fd_data
) necp_fd_observer_list
;
388 #define NECP_CLIENT_FD_ZONE_MAX 128
389 #define NECP_CLIENT_FD_ZONE_NAME "necp.clientfd"
391 static unsigned int necp_client_fd_size
; /* size of zone element */
392 static struct zone
*necp_client_fd_zone
; /* zone for necp_fd_data */
394 #define NECP_FLOW_ZONE_MAX 512
395 #define NECP_FLOW_ZONE_NAME "necp.flow"
397 static unsigned int necp_flow_size
; /* size of necp_client_flow */
398 static struct mcache
*necp_flow_cache
; /* cache for necp_client_flow */
401 static lck_grp_attr_t
*necp_fd_grp_attr
= NULL
;
402 static lck_attr_t
*necp_fd_mtx_attr
= NULL
;
403 static lck_grp_t
*necp_fd_mtx_grp
= NULL
;
405 decl_lck_rw_data(static, necp_fd_lock
);
406 decl_lck_rw_data(static, necp_observer_lock
);
407 decl_lck_rw_data(static, necp_client_tree_lock
);
408 decl_lck_rw_data(static, necp_collect_stats_list_lock
);
410 #define NECP_STATS_LIST_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_collect_stats_list_lock)
411 #define NECP_STATS_LIST_LOCK_SHARED() lck_rw_lock_shared(&necp_collect_stats_list_lock)
412 #define NECP_STATS_LIST_UNLOCK() lck_rw_done(&necp_collect_stats_list_lock)
414 #define NECP_CLIENT_TREE_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_client_tree_lock)
415 #define NECP_CLIENT_TREE_LOCK_SHARED() lck_rw_lock_shared(&necp_client_tree_lock)
416 #define NECP_CLIENT_TREE_UNLOCK() lck_rw_done(&necp_client_tree_lock)
418 #define NECP_FD_LIST_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_fd_lock)
419 #define NECP_FD_LIST_LOCK_SHARED() lck_rw_lock_shared(&necp_fd_lock)
420 #define NECP_FD_LIST_UNLOCK() lck_rw_done(&necp_fd_lock)
422 #define NECP_OBSERVER_LIST_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_observer_lock)
423 #define NECP_OBSERVER_LIST_LOCK_SHARED() lck_rw_lock_shared(&necp_observer_lock)
424 #define NECP_OBSERVER_LIST_UNLOCK() lck_rw_done(&necp_observer_lock)
428 // Take NECP_FD_LIST_LOCK when accessing or modifying the necp_fd_list
429 // Take NECP_CLIENT_TREE_LOCK when accessing or modifying the necp_client_global_tree
430 // Take NECP_STATS_LIST_LOCK when accessing or modifying the necp_collect_stats_client_list
431 // Take NECP_FD_LOCK when accessing or modifying an necp_fd_data entry
432 // Take NECP_CLIENT_LOCK when accessing or modifying a single necp_client
433 // Take NECP_CLIENT_ROUTE_LOCK when accessing or modifying a client's route
435 // Precedence, where 1 is the first lock that must be taken
436 // 1. NECP_FD_LIST_LOCK
437 // 2. NECP_FD_LOCK (any)
438 // 3. NECP_CLIENT_TREE_LOCK
439 // 4. NECP_CLIENT_LOCK (any)
440 // 5. NECP_STATS_LIST_LOCK
441 // 6. NECP_CLIENT_ROUTE_LOCK (any)
443 static thread_call_t necp_client_update_tcall
;
446 /// NECP file descriptor functions
449 noop_read(struct fileproc
*fp
, struct uio
*uio
, int flags
, vfs_context_t ctx
)
451 #pragma unused(fp, uio, flags, ctx)
456 noop_write(struct fileproc
*fp
, struct uio
*uio
, int flags
,
459 #pragma unused(fp, uio, flags, ctx)
464 noop_ioctl(struct fileproc
*fp
, unsigned long com
, caddr_t data
,
467 #pragma unused(fp, com, data, ctx)
472 necp_fd_notify(struct necp_fd_data
*fd_data
, bool locked
)
474 struct selinfo
*si
= &fd_data
->si
;
477 NECP_FD_LOCK(fd_data
);
482 // use a non-zero hint to tell the notification from the
483 // call done in kqueue_scan() which uses 0
484 KNOTE(&si
->si_note
, 1); // notification
487 NECP_FD_UNLOCK(fd_data
);
492 necp_fd_poll(struct necp_fd_data
*fd_data
, int events
, void *wql
, struct proc
*p
, int is_kevent
)
494 #pragma unused(wql, p, is_kevent)
497 u_int want_rx
= events
& (POLLIN
| POLLRDNORM
);
499 if (fd_data
->flags
& NECP_OPEN_FLAG_PUSH_OBSERVER
) {
500 // Push-mode observers are readable when they have a new update
501 if (!TAILQ_EMPTY(&fd_data
->update_list
)) {
505 // Standard fds are readable when some client is unread
506 struct necp_client
*client
= NULL
;
507 bool has_unread_clients
= FALSE
;
508 RB_FOREACH(client
, _necp_client_tree
, &fd_data
->clients
) {
509 NECP_CLIENT_LOCK(client
);
510 if (!client
->result_read
|| !client
->flow_result_read
) {
511 has_unread_clients
= TRUE
;
513 NECP_CLIENT_UNLOCK(client
);
514 if (has_unread_clients
) {
519 if (has_unread_clients
) {
528 static struct necp_client
*
529 necp_client_fd_find_client_and_lock(struct necp_fd_data
*client_fd
, uuid_t client_id
)
531 struct necp_client find
;
532 NECP_FD_ASSERT_LOCKED(client_fd
);
533 uuid_copy(find
.client_id
, client_id
);
534 struct necp_client
*client
= RB_FIND(_necp_client_tree
, &client_fd
->clients
, &find
);
536 if (client
!= NULL
) {
537 NECP_CLIENT_LOCK(client
);
544 necp_client_id_cmp(struct necp_client
*client0
, struct necp_client
*client1
)
546 return (uuid_compare(client0
->client_id
, client1
->client_id
));
550 necpop_select(struct fileproc
*fp
, int which
, void *wql
, vfs_context_t ctx
)
552 #pragma unused(fp, which, wql, ctx)
554 struct necp_fd_data
*fd_data
= NULL
;
559 fd_data
= (struct necp_fd_data
*)fp
->f_fglob
->fg_data
;
560 if (fd_data
== NULL
) {
564 procp
= vfs_context_proc(ctx
);
577 NECP_FD_LOCK(fd_data
);
578 revents
= necp_fd_poll(fd_data
, events
, wql
, procp
, 0);
579 NECP_FD_UNLOCK(fd_data
);
581 return ((events
& revents
) ? 1 : 0);
585 necp_fd_knrdetach(struct knote
*kn
)
587 struct necp_fd_data
*fd_data
= (struct necp_fd_data
*)kn
->kn_hook
;
588 struct selinfo
*si
= &fd_data
->si
;
590 NECP_FD_LOCK(fd_data
);
591 KNOTE_DETACH(&si
->si_note
, kn
);
592 NECP_FD_UNLOCK(fd_data
);
596 necp_fd_knread(struct knote
*kn
, long hint
)
598 #pragma unused(kn, hint)
599 return 1; /* assume we are ready */
603 necp_fd_knrprocess(struct knote
*kn
, struct filt_process_s
*data
, struct kevent_internal_s
*kev
)
606 struct necp_fd_data
*fd_data
;
610 fd_data
= (struct necp_fd_data
*)kn
->kn_hook
;
612 NECP_FD_LOCK(fd_data
);
613 revents
= necp_fd_poll(fd_data
, POLLIN
, NULL
, current_proc(), 1);
614 res
= ((revents
& POLLIN
) != 0);
616 *kev
= kn
->kn_kevent
;
618 NECP_FD_UNLOCK(fd_data
);
623 necp_fd_knrtouch(struct knote
*kn
, struct kevent_internal_s
*kev
)
626 struct necp_fd_data
*fd_data
;
629 fd_data
= (struct necp_fd_data
*)kn
->kn_hook
;
631 NECP_FD_LOCK(fd_data
);
632 if ((kn
->kn_status
& KN_UDATA_SPECIFIC
) == 0)
633 kn
->kn_udata
= kev
->udata
;
634 revents
= necp_fd_poll(fd_data
, POLLIN
, NULL
, current_proc(), 1);
635 NECP_FD_UNLOCK(fd_data
);
637 return ((revents
& POLLIN
) != 0);
640 SECURITY_READ_ONLY_EARLY(struct filterops
) necp_fd_rfiltops
= {
642 .f_detach
= necp_fd_knrdetach
,
643 .f_event
= necp_fd_knread
,
644 .f_touch
= necp_fd_knrtouch
,
645 .f_process
= necp_fd_knrprocess
,
649 necpop_kqfilter(struct fileproc
*fp
, struct knote
*kn
,
650 __unused
struct kevent_internal_s
*kev
, vfs_context_t ctx
)
652 #pragma unused(fp, ctx)
653 struct necp_fd_data
*fd_data
= NULL
;
656 if (kn
->kn_filter
!= EVFILT_READ
) {
657 NECPLOG(LOG_ERR
, "bad filter request %d", kn
->kn_filter
);
658 kn
->kn_flags
= EV_ERROR
;
659 kn
->kn_data
= EINVAL
;
663 fd_data
= (struct necp_fd_data
*)kn
->kn_fp
->f_fglob
->fg_data
;
664 if (fd_data
== NULL
) {
665 NECPLOG0(LOG_ERR
, "No channel for kqfilter");
666 kn
->kn_flags
= EV_ERROR
;
667 kn
->kn_data
= ENOENT
;
671 NECP_FD_LOCK(fd_data
);
672 kn
->kn_filtid
= EVFILTID_NECP_FD
;
673 kn
->kn_hook
= fd_data
;
674 KNOTE_ATTACH(&fd_data
->si
.si_note
, kn
);
676 revents
= necp_fd_poll(fd_data
, POLLIN
, NULL
, current_proc(), 1);
678 NECP_FD_UNLOCK(fd_data
);
680 return ((revents
& POLLIN
) != 0);
685 necp_set_client_defunct(struct necp_client
*client
)
687 bool updated
= FALSE
;
689 u_int32_t value_size
= 0;
691 client
->defunct
= TRUE
;
693 u_int8_t
*flags_pointer
= necp_buffer_get_tlv_value(client
->result
, 0, &value_size
);
694 if (flags_pointer
&& value_size
== sizeof(flags
)) {
695 memcpy(&flags
, flags_pointer
, value_size
);
697 flags
|= NECP_CLIENT_RESULT_FLAG_DEFUNCT
;
699 (void)necp_buffer_write_tlv_if_different(client
->result
, NECP_CLIENT_RESULT_FLAGS
,
700 sizeof(flags
), &flags
, &updated
, client
->result
, sizeof(client
->result
));
703 client
->result_read
= FALSE
;
711 necp_defunct_client_for_policy(struct necp_client
*client
,
712 struct _necp_client_defunct_list
*defunct_list
)
714 NECP_CLIENT_ASSERT_LOCKED(client
);
716 if (!client
->defunct
) {
717 bool needs_defunct
= false;
718 struct necp_client_flow
*search_flow
= NULL
;
719 LIST_FOREACH(search_flow
, &client
->flow_list
, flow_chain
) {
720 if (search_flow
->nexus
&&
721 !uuid_is_null(search_flow
->u
.nexus_agent
) &&
722 search_flow
->requested_nexus
) {
724 // Save defunct values for the nexus
725 if (defunct_list
!= NULL
) {
726 // Sleeping alloc won't fail; copy only what's necessary
727 struct necp_client_defunct
*client_defunct
= _MALLOC(sizeof (struct necp_client_defunct
),
728 M_NECP
, M_WAITOK
| M_ZERO
);
729 uuid_copy(client_defunct
->nexus_agent
, search_flow
->u
.nexus_agent
);
730 uuid_copy(client_defunct
->client_id
, client
->client_id
);
731 client_defunct
->proc_pid
= client
->proc_pid
;
733 // Add to the list provided by caller
734 LIST_INSERT_HEAD(defunct_list
, client_defunct
, chain
);
737 needs_defunct
= true;
742 // Only set defunct if there was some assigned flow
743 client
->defunct
= true;
749 necp_client_free(struct necp_client
*client
)
751 NECP_CLIENT_ASSERT_LOCKED(client
);
753 NECP_CLIENT_UNLOCK(client
);
755 lck_mtx_destroy(&client
->route_lock
, necp_fd_mtx_grp
);
756 lck_mtx_destroy(&client
->lock
, necp_fd_mtx_grp
);
758 FREE(client
, M_NECP
);
762 necp_client_retain_locked(struct necp_client
*client
)
764 NECP_CLIENT_ASSERT_LOCKED(client
);
766 client
->reference_count
++;
767 ASSERT(client
->reference_count
!= 0);
771 necp_client_retain(struct necp_client
*client
)
773 NECP_CLIENT_LOCK(client
);
774 necp_client_retain_locked(client
);
775 NECP_CLIENT_UNLOCK(client
);
779 necp_client_release_locked(struct necp_client
*client
)
781 NECP_CLIENT_ASSERT_LOCKED(client
);
783 uint32_t old_ref
= client
->reference_count
;
785 ASSERT(client
->reference_count
!= 0);
786 if (--client
->reference_count
== 0) {
787 necp_client_free(client
);
790 return (old_ref
== 1);
795 necp_client_update_observer_add_internal(struct necp_fd_data
*observer_fd
, struct necp_client
*client
)
797 NECP_FD_LOCK(observer_fd
);
799 if (observer_fd
->update_count
>= necp_observer_message_limit
) {
800 NECP_FD_UNLOCK(observer_fd
);
804 struct necp_client_update
*client_update
= _MALLOC(sizeof(struct necp_client_update
) + client
->parameters_length
,
805 M_NECP
, M_WAITOK
| M_ZERO
);
806 if (client_update
!= NULL
) {
807 client_update
->update_length
= sizeof(struct necp_client_observer_update
) + client
->parameters_length
;
808 uuid_copy(client_update
->client_id
, client
->client_id
);
809 client_update
->update
.update_type
= NECP_CLIENT_UPDATE_TYPE_PARAMETERS
;
810 memcpy(client_update
->update
.tlv_buffer
, client
->parameters
, client
->parameters_length
);
811 TAILQ_INSERT_TAIL(&observer_fd
->update_list
, client_update
, chain
);
812 observer_fd
->update_count
++;
814 necp_fd_notify(observer_fd
, true);
817 NECP_FD_UNLOCK(observer_fd
);
821 necp_client_update_observer_update_internal(struct necp_fd_data
*observer_fd
, struct necp_client
*client
)
823 NECP_FD_LOCK(observer_fd
);
825 if (observer_fd
->update_count
>= necp_observer_message_limit
) {
826 NECP_FD_UNLOCK(observer_fd
);
830 struct necp_client_update
*client_update
= _MALLOC(sizeof(struct necp_client_update
) + client
->result_length
,
831 M_NECP
, M_WAITOK
| M_ZERO
);
832 if (client_update
!= NULL
) {
833 client_update
->update_length
= sizeof(struct necp_client_observer_update
) + client
->result_length
;
834 uuid_copy(client_update
->client_id
, client
->client_id
);
835 client_update
->update
.update_type
= NECP_CLIENT_UPDATE_TYPE_RESULT
;
836 memcpy(client_update
->update
.tlv_buffer
, client
->result
, client
->result_length
);
837 TAILQ_INSERT_TAIL(&observer_fd
->update_list
, client_update
, chain
);
838 observer_fd
->update_count
++;
840 necp_fd_notify(observer_fd
, true);
843 NECP_FD_UNLOCK(observer_fd
);
847 necp_client_update_observer_remove_internal(struct necp_fd_data
*observer_fd
, struct necp_client
*client
)
849 NECP_FD_LOCK(observer_fd
);
851 if (observer_fd
->update_count
>= necp_observer_message_limit
) {
852 NECP_FD_UNLOCK(observer_fd
);
856 struct necp_client_update
*client_update
= _MALLOC(sizeof(struct necp_client_update
),
857 M_NECP
, M_WAITOK
| M_ZERO
);
858 if (client_update
!= NULL
) {
859 client_update
->update_length
= sizeof(struct necp_client_observer_update
);
860 uuid_copy(client_update
->client_id
, client
->client_id
);
861 client_update
->update
.update_type
= NECP_CLIENT_UPDATE_TYPE_REMOVE
;
862 TAILQ_INSERT_TAIL(&observer_fd
->update_list
, client_update
, chain
);
863 observer_fd
->update_count
++;
865 necp_fd_notify(observer_fd
, true);
868 NECP_FD_UNLOCK(observer_fd
);
872 necp_client_update_observer_add(struct necp_client
*client
)
874 NECP_OBSERVER_LIST_LOCK_SHARED();
876 if (LIST_EMPTY(&necp_fd_observer_list
)) {
877 // No observers, bail
878 NECP_OBSERVER_LIST_UNLOCK();
882 struct necp_fd_data
*observer_fd
= NULL
;
883 LIST_FOREACH(observer_fd
, &necp_fd_observer_list
, chain
) {
884 necp_client_update_observer_add_internal(observer_fd
, client
);
887 NECP_OBSERVER_LIST_UNLOCK();
891 necp_client_update_observer_update(struct necp_client
*client
)
893 NECP_OBSERVER_LIST_LOCK_SHARED();
895 if (LIST_EMPTY(&necp_fd_observer_list
)) {
896 // No observers, bail
897 NECP_OBSERVER_LIST_UNLOCK();
901 struct necp_fd_data
*observer_fd
= NULL
;
902 LIST_FOREACH(observer_fd
, &necp_fd_observer_list
, chain
) {
903 necp_client_update_observer_update_internal(observer_fd
, client
);
906 NECP_OBSERVER_LIST_UNLOCK();
910 necp_client_update_observer_remove(struct necp_client
*client
)
912 NECP_OBSERVER_LIST_LOCK_SHARED();
914 if (LIST_EMPTY(&necp_fd_observer_list
)) {
915 // No observers, bail
916 NECP_OBSERVER_LIST_UNLOCK();
920 struct necp_fd_data
*observer_fd
= NULL
;
921 LIST_FOREACH(observer_fd
, &necp_fd_observer_list
, chain
) {
922 necp_client_update_observer_remove_internal(observer_fd
, client
);
925 NECP_OBSERVER_LIST_UNLOCK();
929 necp_destroy_client(struct necp_client
*client
, pid_t pid
, bool abort
)
931 NECP_CLIENT_ASSERT_UNLOCKED(client
);
933 necp_client_update_observer_remove(client
);
935 NECP_CLIENT_LOCK(client
);
938 NECP_CLIENT_ROUTE_LOCK(client
);
939 if (client
->current_route
!= NULL
) {
940 rtfree(client
->current_route
);
941 client
->current_route
= NULL
;
943 NECP_CLIENT_ROUTE_UNLOCK(client
);
945 // Remove flow assignments
946 struct necp_client_flow
*search_flow
= NULL
;
947 struct necp_client_flow
*temp_flow
= NULL
;
948 LIST_FOREACH_SAFE(search_flow
, &client
->flow_list
, flow_chain
, temp_flow
) {
949 if (search_flow
->nexus
&&
950 !uuid_is_null(search_flow
->u
.nexus_agent
) &&
951 search_flow
->requested_nexus
) {
952 // Note that if we had defuncted the client earlier, this would result in a harmless ENOENT
953 int netagent_error
= netagent_client_message(search_flow
->u
.nexus_agent
, client
->client_id
, pid
,
954 abort
? NETAGENT_MESSAGE_TYPE_ABORT_NEXUS
: NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS
);
955 if (netagent_error
!= 0 && netagent_error
!= ENOENT
) {
956 NECPLOG(LOG_ERR
, "necp_client_remove close nexus error (%d)", netagent_error
);
958 uuid_clear(search_flow
->u
.nexus_agent
);
960 if (search_flow
->assigned_results
!= NULL
) {
961 FREE(search_flow
->assigned_results
, M_NETAGENT
);
962 search_flow
->assigned_results
= NULL
;
964 LIST_REMOVE(search_flow
, flow_chain
);
965 if (search_flow
->socket
) {
966 OSDecrementAtomic(&necp_socket_flow_count
);
968 OSDecrementAtomic(&necp_if_flow_count
);
970 mcache_free(necp_flow_cache
, search_flow
);
973 // Remove agent assertions
974 struct necp_client_assertion
*search_assertion
= NULL
;
975 struct necp_client_assertion
*temp_assertion
= NULL
;
976 LIST_FOREACH_SAFE(search_assertion
, &client
->assertion_list
, assertion_chain
, temp_assertion
) {
977 int netagent_error
= netagent_client_message(search_assertion
->asserted_netagent
, client
->client_id
, pid
, NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT
);
978 if (netagent_error
!= 0) {
979 NECPLOG((netagent_error
== ENOENT
? LOG_DEBUG
: LOG_ERR
),
980 "necp_client_remove unassert agent error (%d)", netagent_error
);
982 LIST_REMOVE(search_assertion
, assertion_chain
);
983 FREE(search_assertion
, M_NECP
);
986 if (!necp_client_release_locked(client
)) {
987 NECP_CLIENT_UNLOCK(client
);
990 OSDecrementAtomic(&necp_client_count
);
994 necpop_close(struct fileglob
*fg
, vfs_context_t ctx
)
997 struct necp_fd_data
*fd_data
= NULL
;
1000 fd_data
= (struct necp_fd_data
*)fg
->fg_data
;
1003 if (fd_data
!= NULL
) {
1004 struct _necp_client_tree clients_to_close
;
1005 RB_INIT(&clients_to_close
);
1007 // Remove from list quickly
1008 if (fd_data
->flags
& NECP_OPEN_FLAG_PUSH_OBSERVER
) {
1009 NECP_OBSERVER_LIST_LOCK_EXCLUSIVE();
1010 LIST_REMOVE(fd_data
, chain
);
1011 NECP_OBSERVER_LIST_UNLOCK();
1013 NECP_FD_LIST_LOCK_EXCLUSIVE();
1014 LIST_REMOVE(fd_data
, chain
);
1015 NECP_FD_LIST_UNLOCK();
1018 NECP_FD_LOCK(fd_data
);
1019 pid_t pid
= fd_data
->proc_pid
;
1020 struct necp_client
*client
= NULL
;
1021 struct necp_client
*temp_client
= NULL
;
1022 RB_FOREACH_SAFE(client
, _necp_client_tree
, &fd_data
->clients
, temp_client
) {
1023 NECP_CLIENT_TREE_LOCK_EXCLUSIVE();
1024 RB_REMOVE(_necp_client_global_tree
, &necp_client_global_tree
, client
);
1025 NECP_CLIENT_TREE_UNLOCK();
1026 RB_REMOVE(_necp_client_tree
, &fd_data
->clients
, client
);
1027 RB_INSERT(_necp_client_tree
, &clients_to_close
, client
);
1030 struct necp_client_update
*client_update
= NULL
;
1031 struct necp_client_update
*temp_update
= NULL
;
1032 TAILQ_FOREACH_SAFE(client_update
, &fd_data
->update_list
, chain
, temp_update
) {
1033 // Flush pending updates
1034 TAILQ_REMOVE(&fd_data
->update_list
, client_update
, chain
);
1035 FREE(client_update
, M_NECP
);
1037 fd_data
->update_count
= 0;
1040 NECP_FD_UNLOCK(fd_data
);
1042 selthreadclear(&fd_data
->si
);
1044 lck_mtx_destroy(&fd_data
->fd_lock
, necp_fd_mtx_grp
);
1046 if (fd_data
->flags
& NECP_OPEN_FLAG_PUSH_OBSERVER
) {
1047 OSDecrementAtomic(&necp_observer_fd_count
);
1049 OSDecrementAtomic(&necp_client_fd_count
);
1052 zfree(necp_client_fd_zone
, fd_data
);
1055 RB_FOREACH_SAFE(client
, _necp_client_tree
, &clients_to_close
, temp_client
) {
1056 RB_REMOVE(_necp_client_tree
, &clients_to_close
, client
);
1057 necp_destroy_client(client
, pid
, true);
1064 /// NECP client utilities
1067 necp_address_is_wildcard(const union necp_sockaddr_union
* const addr
)
1069 return ((addr
->sa
.sa_family
== AF_INET
&& addr
->sin
.sin_addr
.s_addr
== INADDR_ANY
) ||
1070 (addr
->sa
.sa_family
== AF_INET6
&& IN6_IS_ADDR_UNSPECIFIED(&addr
->sin6
.sin6_addr
)));
1074 necp_find_fd_data(int fd
, struct necp_fd_data
**fd_data
)
1076 proc_t p
= current_proc();
1077 struct fileproc
*fp
= NULL
;
1080 proc_fdlock_spin(p
);
1081 if ((error
= fp_lookup(p
, fd
, &fp
, 1)) != 0) {
1084 if (fp
->f_fglob
->fg_ops
->fo_type
!= DTYPE_NETPOLICY
) {
1085 fp_drop(p
, fd
, fp
, 1);
1089 *fd_data
= (struct necp_fd_data
*)fp
->f_fglob
->fg_data
;
1098 necp_client_add_socket_flow(struct necp_client
*client
, struct inpcb
*inp
)
1100 struct necp_client_flow
*new_flow
= mcache_alloc(necp_flow_cache
, MCR_SLEEP
);
1101 if (new_flow
== NULL
) {
1102 NECPLOG0(LOG_ERR
, "Failed to allocate socket flow");
1106 memset(new_flow
, 0, sizeof(*new_flow
));
1108 new_flow
->socket
= TRUE
;
1109 new_flow
->u
.socket_handle
= inp
;
1110 new_flow
->u
.cb
= inp
->necp_cb
;
1112 OSIncrementAtomic(&necp_socket_flow_count
);
1114 LIST_INSERT_HEAD(&client
->flow_list
, new_flow
, flow_chain
);
1118 necp_client_add_interface_flow(struct necp_client
*client
, uint32_t interface_index
)
1120 struct necp_client_flow
*new_flow
= mcache_alloc(necp_flow_cache
, MCR_SLEEP
);
1121 if (new_flow
== NULL
) {
1122 NECPLOG0(LOG_ERR
, "Failed to allocate interface flow");
1126 memset(new_flow
, 0, sizeof(*new_flow
));
1128 // Neither nexus nor socket
1129 new_flow
->interface_index
= interface_index
;
1130 new_flow
->u
.socket_handle
= client
->interface_handle
;
1131 new_flow
->u
.cb
= client
->interface_cb
;
1133 OSIncrementAtomic(&necp_if_flow_count
);
1135 LIST_INSERT_HEAD(&client
->flow_list
, new_flow
, flow_chain
);
1139 necp_client_add_interface_flow_if_needed(struct necp_client
*client
, uint32_t interface_index
)
1141 if (!client
->allow_multiple_flows
||
1142 interface_index
== IFSCOPE_NONE
) {
1143 // Interface not set, or client not allowed to use this mode
1147 struct necp_client_flow
*flow
= NULL
;
1148 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
1149 if (!flow
->nexus
&& !flow
->socket
&& flow
->interface_index
== interface_index
) {
1150 // Already have the flow
1151 flow
->invalid
= FALSE
;
1153 flow
->u
.socket_handle
= client
->interface_handle
;
1154 flow
->u
.cb
= client
->interface_cb
;
1159 necp_client_add_interface_flow(client
, interface_index
);
1163 necp_client_flow_is_viable(proc_t proc
, struct necp_client
*client
,
1164 struct necp_client_flow
*flow
)
1166 struct necp_aggregate_result result
;
1167 bool ignore_address
= (client
->allow_multiple_flows
&& !flow
->nexus
&& !flow
->socket
);
1169 flow
->necp_flow_flags
= 0;
1170 int error
= necp_application_find_policy_match_internal(proc
, client
->parameters
,
1171 (u_int32_t
)client
->parameters_length
,
1172 &result
, &flow
->necp_flow_flags
,
1173 flow
->interface_index
,
1174 &flow
->local_addr
, &flow
->remote_addr
, NULL
, ignore_address
);
1176 return (error
== 0 &&
1177 result
.routed_interface_index
!= IFSCOPE_NONE
&&
1178 result
.routing_result
!= NECP_KERNEL_POLICY_RESULT_DROP
);
1182 necp_client_update_flows(proc_t proc
,
1183 struct necp_client
*client
,
1184 struct _necp_client_defunct_list
*defunct_list
,
1185 bool *defuncted_by_flow
)
1187 NECP_CLIENT_ASSERT_LOCKED(client
);
1189 bool client_updated
= FALSE
;
1190 struct necp_client_flow
*flow
= NULL
;
1191 struct necp_client_flow
*temp_flow
= NULL
;
1192 LIST_FOREACH_SAFE(flow
, &client
->flow_list
, flow_chain
, temp_flow
) {
1193 // Check policy result for flow
1194 int old_flags
= flow
->necp_flow_flags
;
1195 bool viable
= necp_client_flow_is_viable(proc
, client
, flow
);
1197 // TODO: Defunct nexus flows that are blocked by policy
1199 if (flow
->viable
!= viable
) {
1200 flow
->viable
= viable
;
1201 client_updated
= TRUE
;
1204 if ((old_flags
& (NECP_CLIENT_RESULT_FLAG_HAS_IPV4
| NECP_CLIENT_RESULT_FLAG_HAS_IPV6
)) !=
1205 (flow
->necp_flow_flags
& (NECP_CLIENT_RESULT_FLAG_HAS_IPV4
| NECP_CLIENT_RESULT_FLAG_HAS_IPV6
))) {
1206 client_updated
= TRUE
;
1209 if (flow
->viable
&& client_updated
&& (flow
->socket
|| (!flow
->socket
&& !flow
->nexus
)) && flow
->u
.cb
) {
1210 flow
->u
.cb(flow
->u
.socket_handle
, NECP_CLIENT_CBACTION_VIABLE
, flow
);
1213 if (!flow
->viable
|| flow
->invalid
) {
1214 if (client_updated
&& (flow
->socket
|| (!flow
->socket
&& !flow
->nexus
)) && flow
->u
.cb
) {
1215 flow
->u
.cb(flow
->u
.socket_handle
, NECP_CLIENT_CBACTION_NONVIABLE
, flow
);
1217 // The callback might change the viable-flag of the
1218 // flow depending on its policy. Thus, we need to
1219 // check again the flags after the callback.
1223 (void)defuncted_by_flow
;
1225 // Handle flows that no longer match
1226 if (!flow
->viable
|| flow
->invalid
) {
1227 // Drop them as long as they aren't assigned data
1228 if (!flow
->requested_nexus
&& !flow
->assigned
) {
1229 if (flow
->assigned_results
!= NULL
) {
1230 FREE(flow
->assigned_results
, M_NETAGENT
);
1231 flow
->assigned_results
= NULL
;
1232 client_updated
= TRUE
;
1234 LIST_REMOVE(flow
, flow_chain
);
1236 OSDecrementAtomic(&necp_socket_flow_count
);
1238 OSDecrementAtomic(&necp_if_flow_count
);
1240 mcache_free(necp_flow_cache
, flow
);
1245 return (client_updated
);
1249 necp_client_mark_all_nonsocket_flows_as_invalid(struct necp_client
*client
)
1251 struct necp_client_flow
*flow
= NULL
;
1252 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
1253 if (!flow
->socket
) { // Socket flows are not marked as invalid
1254 flow
->invalid
= TRUE
;
1260 necp_netagent_applies_to_client(__unused
struct necp_client
*client
,
1261 const struct necp_client_parsed_parameters
*parameters
,
1262 uuid_t netagent_uuid
, bool allow_nexus
,
1263 uint32_t interface_index
, u_int16_t interface_flags
)
1265 #pragma unused(interface_index, interface_flags)
1266 bool applies
= FALSE
;
1267 u_int32_t flags
= netagent_get_flags(netagent_uuid
);
1268 if (!(flags
& NETAGENT_FLAG_REGISTERED
)) {
1269 // Unregistered agents never apply
1274 (flags
& NETAGENT_FLAG_NEXUS_PROVIDER
)) {
1275 // Hide nexus providers unless allowed
1276 // Direct interfaces and direct policies are allowed to use a nexus
1277 // Delegate interfaces or re-scoped interfaces are not allowed
1281 if (flags
& NETAGENT_FLAG_SPECIFIC_USE_ONLY
) {
1282 // Specific use agents only apply when required
1283 bool required
= FALSE
;
1284 if (parameters
!= NULL
) {
1285 // Check required agent UUIDs
1286 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1287 if (uuid_is_null(parameters
->required_netagents
[i
])) {
1290 if (uuid_compare(parameters
->required_netagents
[i
], netagent_uuid
) == 0) {
1297 // Check required agent types
1298 bool fetched_type
= FALSE
;
1299 char netagent_domain
[NETAGENT_DOMAINSIZE
];
1300 char netagent_type
[NETAGENT_TYPESIZE
];
1301 memset(&netagent_domain
, 0, NETAGENT_DOMAINSIZE
);
1302 memset(&netagent_type
, 0, NETAGENT_TYPESIZE
);
1304 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1305 if (strlen(parameters
->required_netagent_types
[i
].netagent_domain
) == 0 ||
1306 strlen(parameters
->required_netagent_types
[i
].netagent_type
) == 0) {
1310 if (!fetched_type
) {
1311 if (netagent_get_agent_domain_and_type(netagent_uuid
, netagent_domain
, netagent_type
)) {
1312 fetched_type
= TRUE
;
1318 if ((strlen(parameters
->required_netagent_types
[i
].netagent_domain
) == 0 ||
1319 strncmp(netagent_domain
, parameters
->required_netagent_types
[i
].netagent_domain
, NETAGENT_DOMAINSIZE
) == 0) &&
1320 (strlen(parameters
->required_netagent_types
[i
].netagent_type
) == 0 ||
1321 strncmp(netagent_type
, parameters
->required_netagent_types
[i
].netagent_type
, NETAGENT_TYPESIZE
) == 0)) {
1339 necp_client_add_agent_flows_for_interface(struct necp_client
*client
,
1340 const struct necp_client_parsed_parameters
*parsed_parameters
,
1343 if (ifp
!= NULL
&& ifp
->if_agentids
!= NULL
) {
1344 for (u_int32_t i
= 0; i
< ifp
->if_agentcount
; i
++) {
1345 if (uuid_is_null(ifp
->if_agentids
[i
])) {
1348 u_int16_t if_flags
= nstat_ifnet_to_flags(ifp
);
1349 // Relies on the side effect that nexus agents that apply will create flows
1350 (void)necp_netagent_applies_to_client(client
, parsed_parameters
, ifp
->if_agentids
[i
], TRUE
, ifp
->if_index
, if_flags
);
1356 necp_client_address_is_valid(struct sockaddr
*address
)
1358 if (address
->sa_family
== AF_INET
) {
1359 return (address
->sa_len
== sizeof(struct sockaddr_in
));
1360 } else if (address
->sa_family
== AF_INET6
) {
1361 return (address
->sa_len
== sizeof(struct sockaddr_in6
));
1368 necp_client_parse_parameters(u_int8_t
*parameters
,
1369 u_int32_t parameters_size
,
1370 struct necp_client_parsed_parameters
*parsed_parameters
)
1375 u_int32_t num_prohibited_interfaces
= 0;
1376 u_int32_t num_prohibited_interface_types
= 0;
1377 u_int32_t num_required_agents
= 0;
1378 u_int32_t num_prohibited_agents
= 0;
1379 u_int32_t num_preferred_agents
= 0;
1380 u_int32_t num_required_agent_types
= 0;
1381 u_int32_t num_prohibited_agent_types
= 0;
1382 u_int32_t num_preferred_agent_types
= 0;
1384 if (parsed_parameters
== NULL
) {
1388 memset(parsed_parameters
, 0, sizeof(struct necp_client_parsed_parameters
));
1390 while ((offset
+ sizeof(struct necp_tlv_header
)) <= parameters_size
) {
1391 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
1392 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
1394 if (length
> (parameters_size
- (offset
+ sizeof(struct necp_tlv_header
)))) {
1395 // If the length is larger than what can fit in the remaining parameters size, bail
1396 NECPLOG(LOG_ERR
, "Invalid TLV length (%u)", length
);
1401 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
1402 if (value
!= NULL
) {
1404 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE
: {
1405 if (length
<= IFXNAMSIZ
&& length
> 0) {
1406 ifnet_t bound_interface
= NULL
;
1407 char interface_name
[IFXNAMSIZ
];
1408 memcpy(interface_name
, value
, length
);
1409 interface_name
[length
- 1] = 0; // Make sure the string is NULL terminated
1410 if (ifnet_find_by_name(interface_name
, &bound_interface
) == 0) {
1411 parsed_parameters
->required_interface_index
= bound_interface
->if_index
;
1412 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF
;
1413 ifnet_release(bound_interface
);
1418 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS
: {
1419 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
1420 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
1421 if (necp_client_address_is_valid(&address_struct
->address
.sa
)) {
1422 memcpy(&parsed_parameters
->local_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
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_LOCAL_ENDPOINT
: {
1435 if (length
>= sizeof(struct necp_client_endpoint
)) {
1436 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
1437 if (necp_client_address_is_valid(&endpoint
->u
.sa
)) {
1438 memcpy(&parsed_parameters
->local_addr
, &endpoint
->u
.sa
, sizeof(union necp_sockaddr_union
));
1439 if (!necp_address_is_wildcard(&parsed_parameters
->local_addr
)) {
1440 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR
;
1442 if ((parsed_parameters
->local_addr
.sa
.sa_family
== AF_INET
&& parsed_parameters
->local_addr
.sin
.sin_port
) ||
1443 (parsed_parameters
->local_addr
.sa
.sa_family
== AF_INET6
&& parsed_parameters
->local_addr
.sin6
.sin6_port
)) {
1444 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_LOCAL_PORT
;
1450 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS
: {
1451 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
1452 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
1453 if (necp_client_address_is_valid(&address_struct
->address
.sa
)) {
1454 memcpy(&parsed_parameters
->remote_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
1455 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR
;
1460 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT
: {
1461 if (length
>= sizeof(struct necp_client_endpoint
)) {
1462 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
1463 if (necp_client_address_is_valid(&endpoint
->u
.sa
)) {
1464 memcpy(&parsed_parameters
->remote_addr
, &endpoint
->u
.sa
, sizeof(union necp_sockaddr_union
));
1465 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR
;
1470 case NECP_CLIENT_PARAMETER_PROHIBIT_INTERFACE
: {
1471 if (num_prohibited_interfaces
>= NECP_MAX_PARSED_PARAMETERS
) {
1474 if (length
<= IFXNAMSIZ
&& length
> 0) {
1475 memcpy(parsed_parameters
->prohibited_interfaces
[num_prohibited_interfaces
], value
, length
);
1476 parsed_parameters
->prohibited_interfaces
[num_prohibited_interfaces
][length
- 1] = 0; // Make sure the string is NULL terminated
1477 num_prohibited_interfaces
++;
1478 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF
;
1482 case NECP_CLIENT_PARAMETER_REQUIRE_IF_TYPE
: {
1483 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
) {
1486 if (length
>= sizeof(u_int8_t
)) {
1487 memcpy(&parsed_parameters
->required_interface_type
, value
, sizeof(u_int8_t
));
1488 if (parsed_parameters
->required_interface_type
) {
1489 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
;
1494 case NECP_CLIENT_PARAMETER_PROHIBIT_IF_TYPE
: {
1495 if (num_prohibited_interface_types
>= NECP_MAX_PARSED_PARAMETERS
) {
1498 if (length
>= sizeof(u_int8_t
)) {
1499 memcpy(&parsed_parameters
->prohibited_interface_types
[num_prohibited_interface_types
], value
, sizeof(u_int8_t
));
1500 num_prohibited_interface_types
++;
1501 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE
;
1505 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT
: {
1506 if (num_required_agents
>= NECP_MAX_PARSED_PARAMETERS
) {
1509 if (length
>= sizeof(uuid_t
)) {
1510 memcpy(&parsed_parameters
->required_netagents
[num_required_agents
], value
, sizeof(uuid_t
));
1511 num_required_agents
++;
1512 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT
;
1516 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT
: {
1517 if (num_prohibited_agents
>= NECP_MAX_PARSED_PARAMETERS
) {
1520 if (length
>= sizeof(uuid_t
)) {
1521 memcpy(&parsed_parameters
->prohibited_netagents
[num_prohibited_agents
], value
, sizeof(uuid_t
));
1522 num_prohibited_agents
++;
1523 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT
;
1527 case NECP_CLIENT_PARAMETER_PREFER_AGENT
: {
1528 if (num_preferred_agents
>= NECP_MAX_PARSED_PARAMETERS
) {
1531 if (length
>= sizeof(uuid_t
)) {
1532 memcpy(&parsed_parameters
->preferred_netagents
[num_preferred_agents
], value
, sizeof(uuid_t
));
1533 num_preferred_agents
++;
1534 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT
;
1538 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE
: {
1539 if (num_required_agent_types
>= NECP_MAX_PARSED_PARAMETERS
) {
1542 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
1543 memcpy(&parsed_parameters
->required_netagent_types
[num_required_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
1544 num_required_agent_types
++;
1545 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE
;
1549 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT_TYPE
: {
1550 if (num_prohibited_agent_types
>= NECP_MAX_PARSED_PARAMETERS
) {
1553 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
1554 memcpy(&parsed_parameters
->prohibited_netagent_types
[num_prohibited_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
1555 num_prohibited_agent_types
++;
1556 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE
;
1560 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE
: {
1561 if (num_preferred_agent_types
>= NECP_MAX_PARSED_PARAMETERS
) {
1564 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
1565 memcpy(&parsed_parameters
->preferred_netagent_types
[num_preferred_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
1566 num_preferred_agent_types
++;
1567 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE
;
1571 case NECP_CLIENT_PARAMETER_FLAGS
: {
1572 if (length
>= sizeof(u_int32_t
)) {
1573 memcpy(&parsed_parameters
->flags
, value
, sizeof(parsed_parameters
->flags
));
1574 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_FLAGS
;
1578 case NECP_CLIENT_PARAMETER_IP_PROTOCOL
: {
1579 if (length
>= sizeof(parsed_parameters
->ip_protocol
)) {
1580 memcpy(&parsed_parameters
->ip_protocol
, value
, sizeof(parsed_parameters
->ip_protocol
));
1581 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_IP_PROTOCOL
;
1585 case NECP_CLIENT_PARAMETER_PID
: {
1586 if (length
>= sizeof(parsed_parameters
->effective_pid
)) {
1587 memcpy(&parsed_parameters
->effective_pid
, value
, sizeof(parsed_parameters
->effective_pid
));
1588 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_PID
;
1592 case NECP_CLIENT_PARAMETER_APPLICATION
: {
1593 if (length
>= sizeof(parsed_parameters
->effective_uuid
)) {
1594 memcpy(&parsed_parameters
->effective_uuid
, value
, sizeof(parsed_parameters
->effective_uuid
));
1595 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_UUID
;
1599 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS
: {
1600 if (length
>= sizeof(parsed_parameters
->traffic_class
)) {
1601 memcpy(&parsed_parameters
->traffic_class
, value
, sizeof(parsed_parameters
->traffic_class
));
1602 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_TRAFFIC_CLASS
;
1613 offset
+= sizeof(struct necp_tlv_header
) + length
;
1620 necp_client_parse_result(u_int8_t
*result
,
1621 u_int32_t result_size
,
1622 union necp_sockaddr_union
*local_address
,
1623 union necp_sockaddr_union
*remote_address
)
1628 while ((offset
+ sizeof(struct necp_tlv_header
)) <= result_size
) {
1629 u_int8_t type
= necp_buffer_get_tlv_type(result
, offset
);
1630 u_int32_t length
= necp_buffer_get_tlv_length(result
, offset
);
1632 if (length
> 0 && (offset
+ sizeof(struct necp_tlv_header
) + length
) <= result_size
) {
1633 u_int8_t
*value
= necp_buffer_get_tlv_value(result
, offset
, NULL
);
1634 if (value
!= NULL
) {
1636 case NECP_CLIENT_RESULT_LOCAL_ENDPOINT
: {
1637 if (length
>= sizeof(struct necp_client_endpoint
)) {
1638 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
1639 if (local_address
!= NULL
&& necp_client_address_is_valid(&endpoint
->u
.sa
)) {
1640 memcpy(local_address
, &endpoint
->u
.sa
, endpoint
->u
.sa
.sa_len
);
1645 case NECP_CLIENT_RESULT_REMOTE_ENDPOINT
: {
1646 if (length
>= sizeof(struct necp_client_endpoint
)) {
1647 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
1648 if (remote_address
!= NULL
&& necp_client_address_is_valid(&endpoint
->u
.sa
)) {
1649 memcpy(remote_address
, &endpoint
->u
.sa
, endpoint
->u
.sa
.sa_len
);
1661 offset
+= sizeof(struct necp_tlv_header
) + length
;
1668 necp_client_register_socket_flow(pid_t pid
, uuid_t client_id
, struct inpcb
*inp
)
1671 bool found_client
= FALSE
;
1673 NECP_CLIENT_TREE_LOCK_SHARED();
1675 struct necp_client find
;
1676 uuid_copy(find
.client_id
, client_id
);
1677 struct necp_client
*client
= RB_FIND(_necp_client_global_tree
, &necp_client_global_tree
, &find
);
1678 if (client
!= NULL
) {
1679 NECP_CLIENT_LOCK(client
);
1681 if (!pid
|| client
->proc_pid
== pid
) {
1682 // Found the right client!
1683 found_client
= TRUE
;
1684 necp_client_add_socket_flow(client
, inp
);
1687 NECP_CLIENT_UNLOCK(client
);
1690 NECP_CLIENT_TREE_UNLOCK();
1692 if (!found_client
) {
1696 * Count the sockets that have the NECP client UUID set
1698 struct socket
*so
= inp
->inp_socket
;
1699 if (!(so
->so_flags1
& SOF1_HAS_NECP_CLIENT_UUID
)) {
1700 so
->so_flags1
|= SOF1_HAS_NECP_CLIENT_UUID
;
1701 INC_ATOMIC_INT64_LIM(net_api_stats
.nas_socket_necp_clientuuid_total
);
1709 necp_client_add_multipath_cb(struct necp_client
*client
, struct mppcb
*mpp
)
1711 struct necp_client_flow
*flow
= NULL
;
1713 client
->interface_handle
= mpp
;
1714 client
->interface_cb
= mpp
->necp_cb
;
1716 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
1717 if (flow
->nexus
|| flow
->socket
) {
1721 flow
->u
.socket_handle
= mpp
;
1722 flow
->u
.cb
= mpp
->necp_cb
;
1724 if (flow
->viable
&& flow
->u
.cb
) {
1725 flow
->u
.cb(mpp
, NECP_CLIENT_CBACTION_INITIAL
, flow
);
1731 necp_client_register_multipath_cb(pid_t pid
, uuid_t client_id
, struct mppcb
*mpp
)
1734 bool found_client
= FALSE
;
1736 NECP_CLIENT_TREE_LOCK_SHARED();
1738 struct necp_client find
;
1739 uuid_copy(find
.client_id
, client_id
);
1740 struct necp_client
*client
= RB_FIND(_necp_client_global_tree
, &necp_client_global_tree
, &find
);
1741 if (client
!= NULL
) {
1742 NECP_CLIENT_LOCK(client
);
1744 if (!pid
|| client
->proc_pid
== pid
) {
1745 // Found the right client!
1746 found_client
= TRUE
;
1747 necp_client_add_multipath_cb(client
, mpp
);
1750 NECP_CLIENT_UNLOCK(client
);
1753 NECP_CLIENT_TREE_UNLOCK();
1755 if (!found_client
) {
1762 #define NETAGENT_DOMAIN_NETEXT "NetworkExtension"
1763 #define NETAGENT_TYPE_PATHCTRL "PathController"
1766 necp_client_unregister_socket_flow(uuid_t client_id
, void *handle
)
1769 struct necp_fd_data
*client_fd
= NULL
;
1770 bool found_client
= FALSE
;
1771 bool client_updated
= FALSE
;
1773 NECP_FD_LIST_LOCK_SHARED();
1774 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
1775 NECP_FD_LOCK(client_fd
);
1777 struct necp_client
*client
= necp_client_fd_find_client_and_lock(client_fd
, client_id
);
1778 if (client
!= NULL
) {
1779 // Found the right client!
1780 found_client
= TRUE
;
1782 // Remove flow assignment
1783 struct necp_client_flow
*search_flow
= NULL
;
1784 struct necp_client_flow
*temp_flow
= NULL
;
1785 LIST_FOREACH_SAFE(search_flow
, &client
->flow_list
, flow_chain
, temp_flow
) {
1786 if (search_flow
->socket
&& search_flow
->u
.socket_handle
== handle
) {
1787 if (search_flow
->assigned_results
!= NULL
) {
1788 FREE(search_flow
->assigned_results
, M_NETAGENT
);
1789 search_flow
->assigned_results
= NULL
;
1791 client_updated
= TRUE
;
1792 LIST_REMOVE(search_flow
, flow_chain
);
1793 OSDecrementAtomic(&necp_socket_flow_count
);
1794 mcache_free(necp_flow_cache
, search_flow
);
1798 NECP_CLIENT_UNLOCK(client
);
1801 if (client_updated
) {
1802 client
->flow_result_read
= FALSE
;
1803 necp_fd_notify(client_fd
, true);
1805 NECP_FD_UNLOCK(client_fd
);
1811 NECP_FD_LIST_UNLOCK();
1813 if (!found_client
) {
1821 necp_client_unregister_multipath_cb(uuid_t client_id
, void *handle
)
1824 bool found_client
= FALSE
;
1826 NECP_CLIENT_TREE_LOCK_SHARED();
1828 struct necp_client find
;
1829 uuid_copy(find
.client_id
, client_id
);
1830 struct necp_client
*client
= RB_FIND(_necp_client_global_tree
, &necp_client_global_tree
, &find
);
1831 if (client
!= NULL
) {
1832 NECP_CLIENT_LOCK(client
);
1834 // Found the right client!
1835 found_client
= TRUE
;
1837 // Remove flow assignment
1838 struct necp_client_flow
*search_flow
= NULL
;
1839 struct necp_client_flow
*temp_flow
= NULL
;
1840 LIST_FOREACH_SAFE(search_flow
, &client
->flow_list
, flow_chain
, temp_flow
) {
1841 if (!search_flow
->socket
&& !search_flow
->nexus
&&
1842 search_flow
->u
.socket_handle
== handle
) {
1843 search_flow
->u
.socket_handle
= NULL
;
1844 search_flow
->u
.cb
= NULL
;
1848 client
->interface_handle
= NULL
;
1849 client
->interface_cb
= NULL
;
1851 NECP_CLIENT_UNLOCK(client
);
1854 NECP_CLIENT_TREE_UNLOCK();
1856 if (!found_client
) {
1864 necp_client_assign_from_socket(pid_t pid
, uuid_t client_id
, struct inpcb
*inp
)
1867 struct necp_fd_data
*client_fd
= NULL
;
1868 bool found_client
= FALSE
;
1869 bool client_updated
= FALSE
;
1871 NECP_FD_LIST_LOCK_SHARED();
1872 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
1873 if (pid
&& client_fd
->proc_pid
!= pid
) {
1877 proc_t proc
= proc_find(client_fd
->proc_pid
);
1878 if (proc
== PROC_NULL
) {
1882 NECP_FD_LOCK(client_fd
);
1884 struct necp_client
*client
= necp_client_fd_find_client_and_lock(client_fd
, client_id
);
1885 if (client
!= NULL
) {
1886 // Found the right client!
1887 found_client
= TRUE
;
1889 struct necp_client_flow
*flow
= NULL
;
1890 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
1891 if (flow
->socket
&& flow
->u
.socket_handle
== inp
) {
1892 // Release prior results and route
1893 if (flow
->assigned_results
!= NULL
) {
1894 FREE(flow
->assigned_results
, M_NETAGENT
);
1895 flow
->assigned_results
= NULL
;
1899 if ((inp
->inp_flags
& INP_BOUND_IF
) && inp
->inp_boundifp
) {
1900 ifp
= inp
->inp_boundifp
;
1902 ifp
= inp
->inp_last_outifp
;
1906 flow
->interface_index
= ifp
->if_index
;
1908 flow
->interface_index
= IFSCOPE_NONE
;
1911 if (inp
->inp_vflag
& INP_IPV4
) {
1912 flow
->local_addr
.sin
.sin_family
= AF_INET
;
1913 flow
->local_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
1914 flow
->local_addr
.sin
.sin_port
= inp
->inp_lport
;
1915 memcpy(&flow
->local_addr
.sin
.sin_addr
, &inp
->inp_laddr
, sizeof(struct in_addr
));
1917 flow
->remote_addr
.sin
.sin_family
= AF_INET
;
1918 flow
->remote_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
1919 flow
->remote_addr
.sin
.sin_port
= inp
->inp_fport
;
1920 memcpy(&flow
->remote_addr
.sin
.sin_addr
, &inp
->inp_faddr
, sizeof(struct in_addr
));
1921 } else if (inp
->inp_vflag
& INP_IPV6
) {
1922 in6_ip6_to_sockaddr(&inp
->in6p_laddr
, inp
->inp_lport
, &flow
->local_addr
.sin6
, sizeof(flow
->local_addr
));
1923 in6_ip6_to_sockaddr(&inp
->in6p_faddr
, inp
->inp_fport
, &flow
->remote_addr
.sin6
, sizeof(flow
->remote_addr
));
1926 flow
->viable
= necp_client_flow_is_viable(proc
, client
, flow
);
1929 uuid_clear(empty_uuid
);
1930 flow
->assigned
= TRUE
;
1931 flow
->assigned_results
= necp_create_nexus_assign_message(empty_uuid
, 0, NULL
, 0,
1932 (struct necp_client_endpoint
*)&flow
->local_addr
,
1933 (struct necp_client_endpoint
*)&flow
->remote_addr
,
1934 0, &flow
->assigned_results_length
);
1935 client
->flow_result_read
= FALSE
;
1936 client_updated
= TRUE
;
1941 NECP_CLIENT_UNLOCK(client
);
1943 if (client_updated
) {
1944 necp_fd_notify(client_fd
, true);
1946 NECP_FD_UNLOCK(client_fd
);
1955 NECP_FD_LIST_UNLOCK();
1957 if (!found_client
) {
1959 } else if (!client_updated
) {
1967 necp_update_flow_protoctl_event(uuid_t netagent_uuid
, uuid_t client_id
,
1968 uint32_t protoctl_event_code
, uint32_t protoctl_event_val
,
1969 uint32_t protoctl_event_tcp_seq_number
)
1972 struct necp_fd_data
*client_fd
= NULL
;
1973 bool found_client
= FALSE
;
1974 bool client_updated
= FALSE
;
1976 NECP_FD_LIST_LOCK_SHARED();
1977 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
1978 proc_t proc
= proc_find(client_fd
->proc_pid
);
1979 if (proc
== PROC_NULL
) {
1983 NECP_FD_LOCK(client_fd
);
1985 struct necp_client
*client
= necp_client_fd_find_client_and_lock(client_fd
, client_id
);
1986 if (client
!= NULL
) {
1987 /* Found the right client! */
1988 found_client
= TRUE
;
1990 struct necp_client_flow
*flow
= NULL
;
1991 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
1992 // Verify that the client nexus agent matches
1994 uuid_compare(flow
->u
.nexus_agent
,
1995 netagent_uuid
) == 0) {
1996 flow
->has_protoctl_event
= TRUE
;
1997 flow
->protoctl_event
.protoctl_event_code
= protoctl_event_code
;
1998 flow
->protoctl_event
.protoctl_event_val
= protoctl_event_val
;
1999 flow
->protoctl_event
.protoctl_event_tcp_seq_num
= protoctl_event_tcp_seq_number
;
2000 client
->flow_result_read
= FALSE
;
2001 client_updated
= TRUE
;
2006 NECP_CLIENT_UNLOCK(client
);
2009 if (client_updated
) {
2010 necp_fd_notify(client_fd
, true);
2013 NECP_FD_UNLOCK(client_fd
);
2021 NECP_FD_LIST_UNLOCK();
2023 if (!found_client
) {
2025 } else if (!client_updated
) {
2032 necp_assign_client_result_locked(struct proc
*proc
,
2033 struct necp_fd_data
*client_fd
,
2034 struct necp_client
*client
,
2035 uuid_t netagent_uuid
,
2036 u_int8_t
*assigned_results
,
2037 size_t assigned_results_length
,
2040 bool client_updated
= FALSE
;
2042 NECP_FD_ASSERT_LOCKED(client_fd
);
2043 NECP_CLIENT_ASSERT_LOCKED(client
);
2045 struct necp_client_flow
*flow
= NULL
;
2046 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
2047 // Verify that the client nexus agent matches
2049 uuid_compare(flow
->u
.nexus_agent
, netagent_uuid
) == 0) {
2050 // Release prior results and route
2051 if (flow
->assigned_results
!= NULL
) {
2052 FREE(flow
->assigned_results
, M_NETAGENT
);
2053 flow
->assigned_results
= NULL
;
2056 if (assigned_results
!= NULL
&& assigned_results_length
> 0) {
2057 int error
= necp_client_parse_result(assigned_results
, (u_int32_t
)assigned_results_length
,
2058 &flow
->local_addr
, &flow
->remote_addr
);
2062 flow
->viable
= necp_client_flow_is_viable(proc
, client
, flow
);
2064 flow
->assigned
= TRUE
;
2065 flow
->assigned_results
= assigned_results
;
2066 flow
->assigned_results_length
= assigned_results_length
;
2067 client
->flow_result_read
= FALSE
;
2068 client_updated
= TRUE
;
2073 if (client_updated
&& notify_fd
) {
2074 necp_fd_notify(client_fd
, true);
2077 // if not updated, client must free assigned_results
2078 return (client_updated
);
2082 necp_assign_client_result(uuid_t netagent_uuid
, uuid_t client_id
,
2083 u_int8_t
*assigned_results
, size_t assigned_results_length
)
2086 struct necp_fd_data
*client_fd
= NULL
;
2087 bool found_client
= FALSE
;
2088 bool client_updated
= FALSE
;
2090 NECP_FD_LIST_LOCK_SHARED();
2092 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
2093 proc_t proc
= proc_find(client_fd
->proc_pid
);
2094 if (proc
== PROC_NULL
) {
2098 NECP_FD_LOCK(client_fd
);
2099 struct necp_client
*client
= necp_client_fd_find_client_and_lock(client_fd
, client_id
);
2100 if (client
!= NULL
) {
2101 // Found the right client!
2102 found_client
= TRUE
;
2104 if (necp_assign_client_result_locked(proc
, client_fd
, client
, netagent_uuid
,
2105 assigned_results
, assigned_results_length
, true)) {
2106 client_updated
= TRUE
;
2109 NECP_CLIENT_UNLOCK(client
);
2111 NECP_FD_UNLOCK(client_fd
);
2121 NECP_FD_LIST_UNLOCK();
2123 // upon error, client must free assigned_results
2124 if (!found_client
) {
2126 } else if (!client_updated
) {
2136 necp_update_client_result(proc_t proc
,
2137 struct necp_fd_data
*client_fd
,
2138 struct necp_client
*client
,
2139 struct _necp_client_defunct_list
*defunct_list
)
2141 struct necp_client_result_netagent netagent
;
2142 struct necp_aggregate_result result
;
2143 struct necp_client_parsed_parameters
*parsed_parameters
= NULL
;
2144 u_int32_t flags
= 0;
2145 struct rtentry
*route
= NULL
;
2147 NECP_CLIENT_ASSERT_LOCKED(client
);
2149 MALLOC(parsed_parameters
, struct necp_client_parsed_parameters
*, sizeof(*parsed_parameters
), M_NECP
, (M_WAITOK
| M_ZERO
));
2150 if (parsed_parameters
== NULL
) {
2151 NECPLOG0(LOG_ERR
, "Failed to allocate parsed parameters");
2155 // Nexus flows will be brought back if they are still valid
2156 necp_client_mark_all_nonsocket_flows_as_invalid(client
);
2158 int error
= necp_client_parse_parameters(client
->parameters
, (u_int32_t
)client
->parameters_length
, parsed_parameters
);
2160 FREE(parsed_parameters
, M_NECP
);
2164 // Update saved IP protocol
2165 client
->ip_protocol
= parsed_parameters
->ip_protocol
;
2167 // Check parameters to find best interface
2168 u_int matching_if_index
= 0;
2169 if (necp_find_matching_interface_index(parsed_parameters
, &matching_if_index
)) {
2170 if (matching_if_index
!= 0) {
2171 parsed_parameters
->required_interface_index
= matching_if_index
;
2173 // Interface found or not needed, match policy.
2174 error
= necp_application_find_policy_match_internal(proc
, client
->parameters
,
2175 (u_int32_t
)client
->parameters_length
,
2176 &result
, &flags
, matching_if_index
,
2177 NULL
, NULL
, &route
, false);
2179 if (route
!= NULL
) {
2182 FREE(parsed_parameters
, M_NECP
);
2186 // Reset current route
2187 NECP_CLIENT_ROUTE_LOCK(client
);
2188 if (client
->current_route
!= NULL
) {
2189 rtfree(client
->current_route
);
2191 client
->current_route
= route
;
2192 NECP_CLIENT_ROUTE_UNLOCK(client
);
2194 // Interface not found. Clear out the whole result, make everything fail.
2195 memset(&result
, 0, sizeof(result
));
2198 // Save the last policy id on the client
2199 client
->policy_id
= result
.policy_id
;
2201 if ((parsed_parameters
->flags
& NECP_CLIENT_PARAMETER_FLAG_MULTIPATH
) ||
2202 ((parsed_parameters
->flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) &&
2203 result
.routing_result
!= NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
)) {
2204 client
->allow_multiple_flows
= TRUE
;
2206 client
->allow_multiple_flows
= FALSE
;
2209 // If the original request was scoped, and the policy result matches, make sure the result is scoped
2210 if ((result
.routing_result
== NECP_KERNEL_POLICY_RESULT_NONE
||
2211 result
.routing_result
== NECP_KERNEL_POLICY_RESULT_PASS
) &&
2212 result
.routed_interface_index
!= IFSCOPE_NONE
&&
2213 parsed_parameters
->required_interface_index
== result
.routed_interface_index
) {
2214 result
.routing_result
= NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
;
2215 result
.routing_result_parameter
.scoped_interface_index
= result
.routed_interface_index
;
2218 if (defunct_list
!= NULL
&&
2219 result
.routing_result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
2220 // If we are forced to drop the client, defunct it if it has flows
2221 necp_defunct_client_for_policy(client
, defunct_list
);
2224 // Recalculate flags
2225 if (client
->defunct
) {
2226 flags
|= NECP_CLIENT_RESULT_FLAG_DEFUNCT
;
2228 if (parsed_parameters
->flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) {
2229 // Listeners are valid as long as they aren't dropped
2230 if (result
.routing_result
!= NECP_KERNEL_POLICY_RESULT_DROP
) {
2231 flags
|= NECP_CLIENT_RESULT_FLAG_SATISFIED
;
2233 } else if (result
.routed_interface_index
!= 0) {
2234 // Clients without flows determine viability based on having some routable interface
2235 flags
|= NECP_CLIENT_RESULT_FLAG_SATISFIED
;
2238 bool updated
= FALSE
;
2239 u_int8_t
*cursor
= client
->result
;
2240 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_FLAGS
, sizeof(flags
), &flags
, &updated
, client
->result
, sizeof(client
->result
));
2241 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_CLIENT_ID
, sizeof(uuid_t
), client
->client_id
, &updated
,
2242 client
->result
, sizeof(client
->result
));
2243 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_POLICY_RESULT
, sizeof(result
.routing_result
), &result
.routing_result
, &updated
,
2244 client
->result
, sizeof(client
->result
));
2245 if (result
.routing_result_parameter
.tunnel_interface_index
!= 0) {
2246 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_POLICY_RESULT_PARAMETER
,
2247 sizeof(result
.routing_result_parameter
), &result
.routing_result_parameter
, &updated
,
2248 client
->result
, sizeof(client
->result
));
2250 if (result
.filter_control_unit
!= 0) {
2251 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_FILTER_CONTROL_UNIT
,
2252 sizeof(result
.filter_control_unit
), &result
.filter_control_unit
, &updated
,
2253 client
->result
, sizeof(client
->result
));
2255 if (result
.routed_interface_index
!= 0) {
2256 u_int routed_interface_index
= result
.routed_interface_index
;
2257 if (result
.routing_result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
2258 parsed_parameters
->required_interface_index
!= IFSCOPE_NONE
&&
2259 parsed_parameters
->required_interface_index
!= result
.routed_interface_index
) {
2260 routed_interface_index
= parsed_parameters
->required_interface_index
;
2263 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_INTERFACE_INDEX
,
2264 sizeof(routed_interface_index
), &routed_interface_index
, &updated
,
2265 client
->result
, sizeof(client
->result
));
2267 if (client_fd
&& client_fd
->flags
& NECP_OPEN_FLAG_BACKGROUND
) {
2268 u_int32_t effective_traffic_class
= SO_TC_BK_SYS
;
2269 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_EFFECTIVE_TRAFFIC_CLASS
,
2270 sizeof(effective_traffic_class
), &effective_traffic_class
, &updated
,
2271 client
->result
, sizeof(client
->result
));
2273 if (client
->background_update
) {
2274 u_int32_t background
= client
->background
;
2275 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_TRAFFIC_MGMT_BG
,
2276 sizeof(background
), &background
, &updated
,
2277 client
->result
, sizeof(client
->result
));
2279 client
->background_update
= 0;
2282 NECP_CLIENT_ROUTE_LOCK(client
);
2283 if (client
->current_route
!= NULL
) {
2284 const u_int32_t route_mtu
= get_maxmtu(client
->current_route
);
2285 if (route_mtu
!= 0) {
2286 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_EFFECTIVE_MTU
,
2287 sizeof(route_mtu
), &route_mtu
, &updated
,
2288 client
->result
, sizeof(client
->result
));
2291 NECP_CLIENT_ROUTE_UNLOCK(client
);
2293 if (result
.mss_recommended
!= 0) {
2294 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_RECOMMENDED_MSS
,
2295 sizeof(result
.mss_recommended
), &result
.mss_recommended
, &updated
,
2296 client
->result
, sizeof(client
->result
));
2299 for (int i
= 0; i
< NECP_MAX_NETAGENTS
; i
++) {
2300 if (uuid_is_null(result
.netagents
[i
])) {
2303 uuid_copy(netagent
.netagent_uuid
, result
.netagents
[i
]);
2304 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
2305 if (necp_netagent_applies_to_client(client
, parsed_parameters
, netagent
.netagent_uuid
, TRUE
, 0, 0)) {
2306 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
,
2307 client
->result
, sizeof(client
->result
));
2311 ifnet_head_lock_shared();
2312 ifnet_t direct_interface
= NULL
;
2313 ifnet_t delegate_interface
= NULL
;
2314 ifnet_t original_scoped_interface
= NULL
;
2316 if (result
.routed_interface_index
!= IFSCOPE_NONE
&& result
.routed_interface_index
<= (u_int32_t
)if_index
) {
2317 direct_interface
= ifindex2ifnet
[result
.routed_interface_index
];
2318 } else if (parsed_parameters
->required_interface_index
!= IFSCOPE_NONE
&&
2319 parsed_parameters
->required_interface_index
<= (u_int32_t
)if_index
) {
2320 // If the request was scoped, but the route didn't match, still grab the agents
2321 direct_interface
= ifindex2ifnet
[parsed_parameters
->required_interface_index
];
2322 } else if (result
.routed_interface_index
== IFSCOPE_NONE
&&
2323 result
.routing_result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
&&
2324 result
.routing_result_parameter
.scoped_interface_index
!= IFSCOPE_NONE
) {
2325 direct_interface
= ifindex2ifnet
[result
.routing_result_parameter
.scoped_interface_index
];
2327 if (direct_interface
!= NULL
) {
2328 delegate_interface
= direct_interface
->if_delegated
.ifp
;
2330 if (result
.routing_result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
2331 parsed_parameters
->required_interface_index
!= IFSCOPE_NONE
&&
2332 parsed_parameters
->required_interface_index
!= result
.routing_result_parameter
.tunnel_interface_index
&&
2333 parsed_parameters
->required_interface_index
<= (u_int32_t
)if_index
) {
2334 original_scoped_interface
= ifindex2ifnet
[parsed_parameters
->required_interface_index
];
2337 if (original_scoped_interface
!= NULL
) {
2338 struct necp_client_result_interface interface_struct
;
2339 interface_struct
.index
= original_scoped_interface
->if_index
;
2340 interface_struct
.generation
= ifnet_get_generation(original_scoped_interface
);
2341 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_INTERFACE
, sizeof(interface_struct
), &interface_struct
, &updated
,
2342 client
->result
, sizeof(client
->result
));
2344 if (direct_interface
!= NULL
) {
2345 struct necp_client_result_interface interface_struct
;
2346 interface_struct
.index
= direct_interface
->if_index
;
2347 interface_struct
.generation
= ifnet_get_generation(direct_interface
);
2348 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_INTERFACE
, sizeof(interface_struct
), &interface_struct
, &updated
,
2349 client
->result
, sizeof(client
->result
));
2351 if (delegate_interface
!= NULL
) {
2352 struct necp_client_result_interface interface_struct
;
2353 interface_struct
.index
= delegate_interface
->if_index
;
2354 interface_struct
.generation
= ifnet_get_generation(delegate_interface
);
2355 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_INTERFACE
, sizeof(interface_struct
), &interface_struct
, &updated
,
2356 client
->result
, sizeof(client
->result
));
2359 // Update multipath/listener interface flows
2360 if (parsed_parameters
->flags
& NECP_CLIENT_PARAMETER_FLAG_MULTIPATH
) {
2361 // Get multipath interface options from ordered list
2362 struct ifnet
*multi_interface
= NULL
;
2363 TAILQ_FOREACH(multi_interface
, &ifnet_ordered_head
, if_ordered_link
) {
2364 if (necp_ifnet_matches_parameters(multi_interface
, parsed_parameters
, NULL
, true)) {
2365 // Add multipath interface flows for kernel MPTCP
2366 necp_client_add_interface_flow_if_needed(client
, multi_interface
->if_index
);
2368 // Add nexus agents for multipath
2369 necp_client_add_agent_flows_for_interface(client
, parsed_parameters
, multi_interface
);
2372 } else if ((parsed_parameters
->flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) &&
2373 result
.routing_result
!= NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
2374 // Get listener interface options from global list
2375 struct ifnet
*listen_interface
= NULL
;
2376 TAILQ_FOREACH(listen_interface
, &ifnet_head
, if_link
) {
2377 if (necp_ifnet_matches_parameters(listen_interface
, parsed_parameters
, NULL
, false)) {
2378 // Add nexus agents for listeners
2379 necp_client_add_agent_flows_for_interface(client
, parsed_parameters
, listen_interface
);
2385 if (original_scoped_interface
!= NULL
) {
2386 ifnet_lock_shared(original_scoped_interface
);
2387 if (original_scoped_interface
->if_agentids
!= NULL
) {
2388 for (u_int32_t i
= 0; i
< original_scoped_interface
->if_agentcount
; i
++) {
2389 if (uuid_is_null(original_scoped_interface
->if_agentids
[i
])) {
2392 u_int16_t if_flags
= nstat_ifnet_to_flags(original_scoped_interface
);
2393 uuid_copy(netagent
.netagent_uuid
, original_scoped_interface
->if_agentids
[i
]);
2394 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
2395 if (necp_netagent_applies_to_client(client
, parsed_parameters
, netagent
.netagent_uuid
, FALSE
, original_scoped_interface
->if_index
, if_flags
)) {
2396 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
,
2397 client
->result
, sizeof(client
->result
));
2401 ifnet_lock_done(original_scoped_interface
);
2403 if (direct_interface
!= NULL
) {
2404 ifnet_lock_shared(direct_interface
);
2405 if (direct_interface
->if_agentids
!= NULL
) {
2406 for (u_int32_t i
= 0; i
< direct_interface
->if_agentcount
; i
++) {
2407 if (uuid_is_null(direct_interface
->if_agentids
[i
])) {
2410 u_int16_t if_flags
= nstat_ifnet_to_flags(direct_interface
);
2411 uuid_copy(netagent
.netagent_uuid
, direct_interface
->if_agentids
[i
]);
2412 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
2413 if (necp_netagent_applies_to_client(client
, parsed_parameters
, netagent
.netagent_uuid
, TRUE
, direct_interface
->if_index
, if_flags
)) {
2414 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
,
2415 client
->result
, sizeof(client
->result
));
2419 ifnet_lock_done(direct_interface
);
2421 if (delegate_interface
!= NULL
) {
2422 ifnet_lock_shared(delegate_interface
);
2423 if (delegate_interface
->if_agentids
!= NULL
) {
2424 for (u_int32_t i
= 0; i
< delegate_interface
->if_agentcount
; i
++) {
2425 if (uuid_is_null(delegate_interface
->if_agentids
[i
])) {
2428 u_int16_t if_flags
= nstat_ifnet_to_flags(delegate_interface
);
2429 uuid_copy(netagent
.netagent_uuid
, delegate_interface
->if_agentids
[i
]);
2430 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
2431 if (necp_netagent_applies_to_client(client
, parsed_parameters
, netagent
.netagent_uuid
, FALSE
, delegate_interface
->if_index
, if_flags
)) {
2432 cursor
= necp_buffer_write_tlv_if_different(cursor
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
,
2433 client
->result
, sizeof(client
->result
));
2437 ifnet_lock_done(delegate_interface
);
2441 size_t new_result_length
= (cursor
- client
->result
);
2442 if (new_result_length
!= client
->result_length
) {
2443 client
->result_length
= new_result_length
;
2447 // Update flow viability/flags
2448 bool defuncted_by_flow
= FALSE
;
2449 if (necp_client_update_flows(proc
, client
, defunct_list
, &defuncted_by_flow
)) {
2451 if (defuncted_by_flow
&& client
->defunct
) {
2452 // Reset initial TLV
2453 flags
|= NECP_CLIENT_RESULT_FLAG_DEFUNCT
;
2454 (void)necp_buffer_write_tlv_if_different(client
->result
, NECP_CLIENT_RESULT_FLAGS
, sizeof(flags
), &flags
, &updated
, client
->result
, sizeof(client
->result
));
2459 client
->result_read
= FALSE
;
2460 necp_client_update_observer_update(client
);
2463 FREE(parsed_parameters
, M_NECP
);
2468 necp_defunct_client_fd_locked(struct necp_fd_data
*client_fd
, struct _necp_client_defunct_list
*defunct_list
, struct proc
*proc
)
2470 #pragma unused(proc)
2471 bool updated_result
= FALSE
;
2472 struct necp_client
*client
= NULL
;
2474 NECP_FD_ASSERT_LOCKED(client_fd
);
2476 RB_FOREACH(client
, _necp_client_tree
, &client_fd
->clients
) {
2477 NECP_CLIENT_LOCK(client
);
2478 if (!client
->defunct
) {
2479 updated_result
= necp_set_client_defunct(client
);
2481 // Prepare close events to be sent to the nexus to effectively remove the flows
2482 struct necp_client_flow
*search_flow
= NULL
;
2483 LIST_FOREACH(search_flow
, &client
->flow_list
, flow_chain
) {
2484 if (search_flow
->nexus
&&
2485 !uuid_is_null(search_flow
->u
.nexus_agent
) &&
2486 search_flow
->requested_nexus
) {
2488 struct necp_client_defunct
*client_defunct
;
2490 // Sleeping alloc won't fail; copy only what's necessary
2491 client_defunct
= _MALLOC(sizeof (struct necp_client_defunct
), M_NECP
, M_WAITOK
| M_ZERO
);
2492 uuid_copy(client_defunct
->nexus_agent
, search_flow
->u
.nexus_agent
);
2493 uuid_copy(client_defunct
->client_id
, client
->client_id
);
2494 client_defunct
->proc_pid
= client
->proc_pid
;
2496 // Add to the list provided by caller
2497 LIST_INSERT_HEAD(defunct_list
, client_defunct
, chain
);
2501 NECP_CLIENT_UNLOCK(client
);
2505 if (updated_result
) {
2506 necp_fd_notify(client_fd
, true);
2511 necp_update_client_fd_locked(struct necp_fd_data
*client_fd
,
2513 struct _necp_client_defunct_list
*defunct_list
)
2515 struct necp_client
*client
= NULL
;
2516 bool updated_result
= FALSE
;
2517 NECP_FD_ASSERT_LOCKED(client_fd
);
2518 RB_FOREACH(client
, _necp_client_tree
, &client_fd
->clients
) {
2519 NECP_CLIENT_LOCK(client
);
2520 if (necp_update_client_result(proc
, client_fd
, client
, defunct_list
)) {
2521 updated_result
= TRUE
;
2523 NECP_CLIENT_UNLOCK(client
);
2525 if (updated_result
) {
2526 necp_fd_notify(client_fd
, true);
2532 necp_update_all_clients_callout(__unused thread_call_param_t dummy
,
2533 __unused thread_call_param_t arg
)
2535 struct necp_fd_data
*client_fd
= NULL
;
2537 struct _necp_client_defunct_list defunct_list
;
2538 LIST_INIT(&defunct_list
);
2540 NECP_FD_LIST_LOCK_SHARED();
2542 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
2543 proc_t proc
= proc_find(client_fd
->proc_pid
);
2544 if (proc
== PROC_NULL
) {
2548 // Update all clients on one fd
2549 NECP_FD_LOCK(client_fd
);
2550 necp_update_client_fd_locked(client_fd
, proc
, &defunct_list
);
2551 NECP_FD_UNLOCK(client_fd
);
2557 NECP_FD_LIST_UNLOCK();
2559 // Handle the case in which some clients became newly defunct
2560 if (!LIST_EMPTY(&defunct_list
)) {
2561 struct necp_client_defunct
*client_defunct
= NULL
;
2562 struct necp_client_defunct
*temp_client_defunct
= NULL
;
2564 // For each newly defunct client, send a message to the nexus to remove the flow
2565 LIST_FOREACH_SAFE(client_defunct
, &defunct_list
, chain
, temp_client_defunct
) {
2566 if (!uuid_is_null(client_defunct
->nexus_agent
)) {
2567 int netagent_error
= netagent_client_message(client_defunct
->nexus_agent
,
2568 client_defunct
->client_id
,
2569 client_defunct
->proc_pid
,
2570 NETAGENT_MESSAGE_TYPE_ABORT_NEXUS
);
2571 if (netagent_error
!= 0) {
2572 char namebuf
[MAXCOMLEN
+1];
2573 (void) strlcpy(namebuf
, "unknown", sizeof (namebuf
));
2574 proc_name(client_defunct
->proc_pid
, namebuf
, sizeof (namebuf
));
2575 NECPLOG((netagent_error
== ENOENT
? LOG_DEBUG
: LOG_ERR
), "necp_update_client abort nexus error (%d) for pid %d %s", netagent_error
, client_defunct
->proc_pid
, namebuf
);
2578 LIST_REMOVE(client_defunct
, chain
);
2579 FREE(client_defunct
, M_NECP
);
2582 ASSERT(LIST_EMPTY(&defunct_list
));
2586 necp_update_all_clients(void)
2588 if (necp_client_update_tcall
== NULL
) {
2589 // Don't try to update clients if the module is not initialized
2593 uint64_t deadline
= 0;
2594 uint64_t leeway
= 0;
2595 clock_interval_to_deadline(necp_timeout_microseconds
, NSEC_PER_USEC
, &deadline
);
2596 clock_interval_to_absolutetime_interval(necp_timeout_leeway_microseconds
, NSEC_PER_USEC
, &leeway
);
2598 thread_call_enter_delayed_with_leeway(necp_client_update_tcall
, NULL
,
2599 deadline
, leeway
, THREAD_CALL_DELAY_LEEWAY
);
2603 necp_set_client_as_background(proc_t proc
,
2604 struct fileproc
*fp
,
2607 bool updated_result
= FALSE
;
2608 struct necp_client
*client
= NULL
;
2610 if (proc
== PROC_NULL
) {
2611 NECPLOG0(LOG_ERR
, "NULL proc");
2616 NECPLOG0(LOG_ERR
, "NULL fp");
2620 struct necp_fd_data
*client_fd
= (struct necp_fd_data
*)fp
->f_fglob
->fg_data
;
2621 if (client_fd
== NULL
) {
2622 NECPLOG0(LOG_ERR
, "Could not find client structure for backgrounded client");
2626 if (client_fd
->necp_fd_type
!= necp_fd_type_client
) {
2627 // Not a client fd, ignore
2628 NECPLOG0(LOG_ERR
, "Not a client fd, ignore");
2632 NECP_FD_LOCK(client_fd
);
2634 RB_FOREACH(client
, _necp_client_tree
, &client_fd
->clients
) {
2635 NECP_CLIENT_LOCK(client
);
2637 bool has_assigned_flow
= FALSE
;
2638 struct necp_client_flow
*search_flow
= NULL
;
2639 LIST_FOREACH(search_flow
, &client
->flow_list
, flow_chain
) {
2640 if (search_flow
->assigned
) {
2641 has_assigned_flow
= TRUE
;
2646 if (has_assigned_flow
) {
2647 client
->background
= background
;
2648 client
->background_update
= TRUE
;
2649 updated_result
= TRUE
;
2652 NECP_CLIENT_UNLOCK(client
);
2654 if (updated_result
) {
2655 necp_update_client_fd_locked(client_fd
, proc
, NULL
);
2657 NECP_FD_UNLOCK(client_fd
);
2661 necp_fd_memstatus(proc_t proc
, uint32_t status
,
2662 struct necp_fd_data
*client_fd
)
2664 #pragma unused(proc, status, client_fd)
2665 ASSERT(proc
!= PROC_NULL
);
2666 ASSERT(client_fd
!= NULL
);
2668 // Nothing to reap for the process or client for now,
2669 // but this is where we would trigger that in future.
2673 necp_fd_defunct(proc_t proc
, struct necp_fd_data
*client_fd
)
2675 struct _necp_client_defunct_list defunct_list
;
2677 ASSERT(proc
!= PROC_NULL
);
2678 ASSERT(client_fd
!= NULL
);
2680 if (client_fd
->necp_fd_type
!= necp_fd_type_client
) {
2681 // Not a client fd, ignore
2685 // Our local temporary list
2686 LIST_INIT(&defunct_list
);
2688 // Need to hold lock so ntstats defunct the same set of clients
2689 NECP_FD_LOCK(client_fd
);
2690 necp_defunct_client_fd_locked(client_fd
, &defunct_list
, proc
);
2691 NECP_FD_UNLOCK(client_fd
);
2693 if (!LIST_EMPTY(&defunct_list
)) {
2694 struct necp_client_defunct
*client_defunct
= NULL
;
2695 struct necp_client_defunct
*temp_client_defunct
= NULL
;
2697 // For each defunct client, remove flow from the nexus
2698 LIST_FOREACH_SAFE(client_defunct
, &defunct_list
, chain
, temp_client_defunct
) {
2699 if (!uuid_is_null(client_defunct
->nexus_agent
)) {
2700 int netagent_error
= netagent_client_message(client_defunct
->nexus_agent
,
2701 client_defunct
->client_id
,
2702 client_defunct
->proc_pid
,
2703 NETAGENT_MESSAGE_TYPE_ABORT_NEXUS
);
2704 if (netagent_error
!= 0) {
2705 NECPLOG((netagent_error
== ENOENT
? LOG_DEBUG
: LOG_ERR
), "necp_defunct_client abort nexus error (%d)", netagent_error
);
2708 LIST_REMOVE(client_defunct
, chain
);
2709 FREE(client_defunct
, M_NECP
);
2712 ASSERT(LIST_EMPTY(&defunct_list
));
2716 necp_client_remove_agent_from_result(struct necp_client
*client
, uuid_t netagent_uuid
)
2720 u_int8_t
*result_buffer
= client
->result
;
2721 while ((offset
+ sizeof(struct necp_tlv_header
)) <= client
->result_length
) {
2722 u_int8_t type
= necp_buffer_get_tlv_type(result_buffer
, offset
);
2723 u_int32_t length
= necp_buffer_get_tlv_length(result_buffer
, offset
);
2725 size_t tlv_total_length
= (sizeof(struct necp_tlv_header
) + length
);
2726 if (type
== NECP_CLIENT_RESULT_NETAGENT
&&
2727 length
== sizeof(struct necp_client_result_netagent
) &&
2728 (offset
+ tlv_total_length
) <= client
->result_length
) {
2729 struct necp_client_result_netagent
*value
= ((struct necp_client_result_netagent
*)(void *)
2730 necp_buffer_get_tlv_value(result_buffer
, offset
, NULL
));
2731 if (uuid_compare(value
->netagent_uuid
, netagent_uuid
) == 0) {
2732 // Found a netagent to remove
2733 // Shift bytes down to remove the tlv, and adjust total length
2734 // Don't adjust the current offset
2735 memmove(result_buffer
+ offset
,
2736 result_buffer
+ offset
+ tlv_total_length
,
2737 client
->result_length
- (offset
+ tlv_total_length
));
2738 client
->result_length
-= tlv_total_length
;
2739 memset(result_buffer
+ client
->result_length
, 0, sizeof(client
->result
) - client
->result_length
);
2744 offset
+= tlv_total_length
;
2749 necp_force_update_client(uuid_t client_id
, uuid_t remove_netagent_uuid
)
2751 struct necp_fd_data
*client_fd
= NULL
;
2753 NECP_FD_LIST_LOCK_SHARED();
2755 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
2756 bool updated_result
= FALSE
;
2757 NECP_FD_LOCK(client_fd
);
2758 struct necp_client
*client
= necp_client_fd_find_client_and_lock(client_fd
, client_id
);
2759 if (client
!= NULL
) {
2760 if (!uuid_is_null(remove_netagent_uuid
)) {
2761 necp_client_remove_agent_from_result(client
, remove_netagent_uuid
);
2763 client
->flow_result_read
= FALSE
;
2764 // Found the client, break
2765 updated_result
= TRUE
;
2766 NECP_CLIENT_UNLOCK(client
);
2768 if (updated_result
) {
2769 necp_fd_notify(client_fd
, true);
2771 NECP_FD_UNLOCK(client_fd
);
2772 if (updated_result
) {
2773 // Found the client, break
2778 NECP_FD_LIST_UNLOCK();
2782 /// Interface matching
2784 #define NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
2785 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF | \
2786 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
2787 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE | \
2788 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
2789 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT | \
2790 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
2791 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
2792 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE | \
2793 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
2795 #define NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
2796 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
2797 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
2798 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
2799 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
2800 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
2802 #define NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
2803 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
2806 necp_ifnet_matches_type(struct ifnet
*ifp
, u_int8_t interface_type
, bool check_delegates
)
2808 struct ifnet
*check_ifp
= ifp
;
2810 if (if_functional_type(check_ifp
, TRUE
) == interface_type
) {
2813 if (!check_delegates
) {
2816 check_ifp
= check_ifp
->if_delegated
.ifp
;
2823 necp_ifnet_matches_name(struct ifnet
*ifp
, const char *interface_name
, bool check_delegates
)
2825 struct ifnet
*check_ifp
= ifp
;
2827 if (strncmp(check_ifp
->if_xname
, interface_name
, IFXNAMSIZ
) == 0) {
2830 if (!check_delegates
) {
2833 check_ifp
= check_ifp
->if_delegated
.ifp
;
2839 necp_ifnet_matches_agent(struct ifnet
*ifp
, uuid_t
*agent_uuid
, bool check_delegates
)
2841 struct ifnet
*check_ifp
= ifp
;
2843 while (check_ifp
!= NULL
) {
2844 ifnet_lock_shared(check_ifp
);
2845 if (check_ifp
->if_agentids
!= NULL
) {
2846 for (u_int32_t index
= 0; index
< check_ifp
->if_agentcount
; index
++) {
2847 if (uuid_compare(check_ifp
->if_agentids
[index
], *agent_uuid
) == 0) {
2848 ifnet_lock_done(check_ifp
);
2853 ifnet_lock_done(check_ifp
);
2855 if (!check_delegates
) {
2858 check_ifp
= check_ifp
->if_delegated
.ifp
;
2864 necp_necp_ifnet_matches_agent_type(struct ifnet
*ifp
, const char *agent_domain
, const char *agent_type
, bool check_delegates
)
2866 struct ifnet
*check_ifp
= ifp
;
2868 while (check_ifp
!= NULL
) {
2869 ifnet_lock_shared(check_ifp
);
2870 if (check_ifp
->if_agentids
!= NULL
) {
2871 for (u_int32_t index
= 0; index
< check_ifp
->if_agentcount
; index
++) {
2872 if (uuid_is_null(check_ifp
->if_agentids
[index
])) {
2876 char if_agent_domain
[NETAGENT_DOMAINSIZE
] = { 0 };
2877 char if_agent_type
[NETAGENT_TYPESIZE
] = { 0 };
2879 if (netagent_get_agent_domain_and_type(check_ifp
->if_agentids
[index
], if_agent_domain
, if_agent_type
)) {
2880 if ((strlen(agent_domain
) == 0 ||
2881 strncmp(if_agent_domain
, agent_domain
, NETAGENT_DOMAINSIZE
) == 0) &&
2882 (strlen(agent_type
) == 0 ||
2883 strncmp(if_agent_type
, agent_type
, NETAGENT_TYPESIZE
) == 0)) {
2884 ifnet_lock_done(check_ifp
);
2890 ifnet_lock_done(check_ifp
);
2892 if (!check_delegates
) {
2895 check_ifp
= check_ifp
->if_delegated
.ifp
;
2901 necp_ifnet_matches_local_address(struct ifnet
*ifp
, struct sockaddr
*sa
)
2903 struct ifaddr
*ifa
= NULL
;
2904 bool matched_local_address
= FALSE
;
2906 // Transform sa into the ifaddr form
2907 // IPv6 Scope IDs are always embedded in the ifaddr list
2908 struct sockaddr_storage address
;
2909 u_int ifscope
= IFSCOPE_NONE
;
2910 (void)sa_copy(sa
, &address
, &ifscope
);
2911 SIN(&address
)->sin_port
= 0;
2912 if (address
.ss_family
== AF_INET6
) {
2913 SIN6(&address
)->sin6_scope_id
= 0;
2916 ifa
= ifa_ifwithaddr_scoped_locked((struct sockaddr
*)&address
, ifp
->if_index
);
2917 matched_local_address
= (ifa
!= NULL
);
2920 ifaddr_release(ifa
);
2923 return (matched_local_address
);
2927 necp_interface_type_is_primary_eligible(u_int8_t interface_type
)
2929 switch (interface_type
) {
2930 // These types can never be primary, so a client requesting these types is allowed
2931 // to match an interface that isn't currently eligible to be primary (has default
2933 case IFRTYPE_FUNCTIONAL_WIFI_AWDL
:
2934 case IFRTYPE_FUNCTIONAL_INTCOPROC
:
2942 #define NECP_IFP_IS_ON_ORDERED_LIST(_ifp) ((_ifp)->if_ordered_link.tqe_next != NULL || (_ifp)->if_ordered_link.tqe_prev != NULL)
2945 necp_ifnet_matches_parameters(struct ifnet
*ifp
,
2946 struct necp_client_parsed_parameters
*parsed_parameters
,
2947 u_int32_t
*preferred_count
, bool ignore_require_if
)
2949 if (preferred_count
) {
2950 *preferred_count
= 0;
2953 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR
) {
2954 if (!necp_ifnet_matches_local_address(ifp
, &parsed_parameters
->local_addr
.sa
)) {
2959 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_FLAGS
) {
2960 if ((parsed_parameters
->flags
& NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE
) &&
2961 IFNET_IS_EXPENSIVE(ifp
)) {
2966 if (!ignore_require_if
&&
2967 (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
) &&
2968 !necp_ifnet_matches_type(ifp
, parsed_parameters
->required_interface_type
, FALSE
)) {
2972 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE
) {
2973 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
2974 if (parsed_parameters
->prohibited_interface_types
[i
] == 0) {
2978 if (necp_ifnet_matches_type(ifp
, parsed_parameters
->prohibited_interface_types
[i
], TRUE
)) {
2984 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF
) {
2985 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
2986 if (strlen(parsed_parameters
->prohibited_interfaces
[i
]) == 0) {
2990 if (necp_ifnet_matches_name(ifp
, parsed_parameters
->prohibited_interfaces
[i
], TRUE
)) {
2996 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT
) {
2997 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
2998 if (uuid_is_null(parsed_parameters
->required_netagents
[i
])) {
3002 if (!necp_ifnet_matches_agent(ifp
, &parsed_parameters
->required_netagents
[i
], FALSE
)) {
3008 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT
) {
3009 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
3010 if (uuid_is_null(parsed_parameters
->prohibited_netagents
[i
])) {
3014 if (necp_ifnet_matches_agent(ifp
, &parsed_parameters
->prohibited_netagents
[i
], TRUE
)) {
3020 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE
) {
3021 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
3022 if (strlen(parsed_parameters
->required_netagent_types
[i
].netagent_domain
) == 0 &&
3023 strlen(parsed_parameters
->required_netagent_types
[i
].netagent_type
) == 0) {
3027 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
)) {
3033 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE
) {
3034 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
3035 if (strlen(parsed_parameters
->prohibited_netagent_types
[i
].netagent_domain
) == 0 &&
3036 strlen(parsed_parameters
->prohibited_netagent_types
[i
].netagent_type
) == 0) {
3040 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
)) {
3046 // Checked preferred properties
3047 if (preferred_count
) {
3048 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT
) {
3049 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
3050 if (uuid_is_null(parsed_parameters
->preferred_netagents
[i
])) {
3054 if (necp_ifnet_matches_agent(ifp
, &parsed_parameters
->preferred_netagents
[i
], TRUE
)) {
3055 (*preferred_count
)++;
3060 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE
) {
3061 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
3062 if (strlen(parsed_parameters
->preferred_netagent_types
[i
].netagent_domain
) == 0 &&
3063 strlen(parsed_parameters
->preferred_netagent_types
[i
].netagent_type
) == 0) {
3067 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
)) {
3068 (*preferred_count
)++;
3078 necp_find_matching_interface_index(struct necp_client_parsed_parameters
*parsed_parameters
, u_int
*return_ifindex
)
3080 struct ifnet
*ifp
= NULL
;
3081 u_int32_t best_preferred_count
= 0;
3082 bool has_preferred_fields
= FALSE
;
3083 *return_ifindex
= 0;
3085 if (parsed_parameters
->required_interface_index
!= 0) {
3086 *return_ifindex
= parsed_parameters
->required_interface_index
;
3090 if (!(parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS
)) {
3094 has_preferred_fields
= (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS
);
3096 // We have interesting parameters to parse and find a matching interface
3097 ifnet_head_lock_shared();
3099 if (!(parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS
)) {
3100 // We do have fields to match, but they are only prohibitory
3101 // If the first interface in the list matches, or there are no ordered interfaces, we don't need to scope
3102 ifp
= TAILQ_FIRST(&ifnet_ordered_head
);
3103 if (ifp
== NULL
|| necp_ifnet_matches_parameters(ifp
, parsed_parameters
, NULL
, false)) {
3104 // Don't set return_ifindex, so the client doesn't need to scope
3110 // First check the ordered interface list
3111 TAILQ_FOREACH(ifp
, &ifnet_ordered_head
, if_ordered_link
) {
3112 u_int32_t preferred_count
= 0;
3113 if (necp_ifnet_matches_parameters(ifp
, parsed_parameters
, &preferred_count
, false)) {
3114 if (preferred_count
> best_preferred_count
||
3115 *return_ifindex
== 0) {
3117 // Everything matched, and is most preferred. Return this interface.
3118 *return_ifindex
= ifp
->if_index
;
3119 best_preferred_count
= preferred_count
;
3121 if (!has_preferred_fields
) {
3128 // Then check the remaining interfaces
3129 if ((parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS
) &&
3130 ((!(parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
)) ||
3131 !necp_interface_type_is_primary_eligible(parsed_parameters
->required_interface_type
)) &&
3132 *return_ifindex
== 0) {
3133 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
) {
3134 u_int32_t preferred_count
= 0;
3135 if (NECP_IFP_IS_ON_ORDERED_LIST(ifp
)) {
3136 // This interface was in the ordered list, skip
3139 if (necp_ifnet_matches_parameters(ifp
, parsed_parameters
, &preferred_count
, false)) {
3140 if (preferred_count
> best_preferred_count
||
3141 *return_ifindex
== 0) {
3143 // Everything matched, and is most preferred. Return this interface.
3144 *return_ifindex
= ifp
->if_index
;
3145 best_preferred_count
= preferred_count
;
3147 if (!has_preferred_fields
) {
3157 if ((parsed_parameters
->valid_fields
== (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS
)) &&
3158 best_preferred_count
== 0) {
3159 // If only has preferred fields, and nothing was found, clear the interface index and return TRUE
3160 *return_ifindex
= 0;
3164 return (*return_ifindex
!= 0);
3169 necp_skywalk_priv_check_cred(proc_t p
, kauth_cred_t cred
)
3171 #pragma unused(p, cred)
3178 necp_open(struct proc
*p
, struct necp_open_args
*uap
, int *retval
)
3180 #pragma unused(retval)
3182 struct necp_fd_data
*fd_data
= NULL
;
3183 struct fileproc
*fp
= NULL
;
3186 if (uap
->flags
& NECP_OPEN_FLAG_OBSERVER
) {
3187 if (necp_skywalk_priv_check_cred(p
, kauth_cred_get()) != 0 &&
3188 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NETWORK_STATISTICS
, 0) != 0) {
3189 NECPLOG0(LOG_ERR
, "Client does not hold necessary entitlement to observe other NECP clients");
3195 error
= falloc(p
, &fp
, &fd
, vfs_context_current());
3200 if ((fd_data
= zalloc(necp_client_fd_zone
)) == NULL
) {
3205 memset(fd_data
, 0, sizeof(*fd_data
));
3207 fd_data
->necp_fd_type
= necp_fd_type_client
;
3208 fd_data
->flags
= uap
->flags
;
3209 RB_INIT(&fd_data
->clients
);
3210 TAILQ_INIT(&fd_data
->update_list
);
3211 lck_mtx_init(&fd_data
->fd_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
3212 klist_init(&fd_data
->si
.si_note
);
3213 fd_data
->proc_pid
= proc_pid(p
);
3215 fp
->f_fglob
->fg_flag
= FREAD
;
3216 fp
->f_fglob
->fg_ops
= &necp_fd_ops
;
3217 fp
->f_fglob
->fg_data
= fd_data
;
3221 *fdflags(p
, fd
) |= (UF_EXCLOSE
| UF_FORKCLOSE
);
3222 procfdtbl_releasefd(p
, fd
, NULL
);
3223 fp_drop(p
, fd
, fp
, 1);
3227 if (fd_data
->flags
& NECP_OPEN_FLAG_PUSH_OBSERVER
) {
3228 NECP_OBSERVER_LIST_LOCK_EXCLUSIVE();
3229 LIST_INSERT_HEAD(&necp_fd_observer_list
, fd_data
, chain
);
3230 OSIncrementAtomic(&necp_observer_fd_count
);
3231 NECP_OBSERVER_LIST_UNLOCK();
3233 // Walk all existing clients and add them
3234 NECP_CLIENT_TREE_LOCK_SHARED();
3235 struct necp_client
*existing_client
= NULL
;
3236 RB_FOREACH(existing_client
, _necp_client_global_tree
, &necp_client_global_tree
) {
3237 NECP_CLIENT_LOCK(existing_client
);
3238 necp_client_update_observer_add_internal(fd_data
, existing_client
);
3239 necp_client_update_observer_update_internal(fd_data
, existing_client
);
3240 NECP_CLIENT_UNLOCK(existing_client
);
3242 NECP_CLIENT_TREE_UNLOCK();
3244 NECP_FD_LIST_LOCK_EXCLUSIVE();
3245 LIST_INSERT_HEAD(&necp_fd_list
, fd_data
, chain
);
3246 OSIncrementAtomic(&necp_client_fd_count
);
3247 NECP_FD_LIST_UNLOCK();
3258 if (fd_data
!= NULL
) {
3259 zfree(necp_client_fd_zone
, fd_data
);
3268 necp_client_add(struct proc
*p
, struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
3271 struct necp_client
*client
= NULL
;
3273 if (fd_data
->flags
& NECP_OPEN_FLAG_PUSH_OBSERVER
) {
3274 NECPLOG0(LOG_ERR
, "NECP client observers with push enabled may not add their own clients");
3278 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
3279 uap
->buffer_size
== 0 || uap
->buffer_size
> NECP_MAX_CLIENT_PARAMETERS_SIZE
|| uap
->buffer
== 0) {
3283 if ((client
= _MALLOC(sizeof(struct necp_client
) + uap
->buffer_size
, M_NECP
,
3284 M_WAITOK
| M_ZERO
)) == NULL
) {
3289 error
= copyin(uap
->buffer
, client
->parameters
, uap
->buffer_size
);
3291 NECPLOG(LOG_ERR
, "necp_client_add parameters copyin error (%d)", error
);
3295 lck_mtx_init(&client
->lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
3296 lck_mtx_init(&client
->route_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
3297 necp_client_retain(client
); // Hold our reference until close
3299 client
->parameters_length
= uap
->buffer_size
;
3300 client
->proc_pid
= fd_data
->proc_pid
; // Save off proc pid in case the client will persist past fd
3301 client
->platform_binary
= ((csproc_get_platform_binary(p
) == 0) ? 0 : 1);
3303 uuid_generate_random(client
->client_id
);
3304 LIST_INIT(&client
->assertion_list
);
3305 LIST_INIT(&client
->flow_list
);
3307 error
= copyout(client
->client_id
, uap
->client_id
, sizeof(uuid_t
));
3309 NECPLOG(LOG_ERR
, "necp_client_add client_id copyout error (%d)", error
);
3313 necp_client_update_observer_add(client
);
3315 NECP_FD_LOCK(fd_data
);
3316 RB_INSERT(_necp_client_tree
, &fd_data
->clients
, client
);
3317 OSIncrementAtomic(&necp_client_count
);
3318 NECP_CLIENT_TREE_LOCK_EXCLUSIVE();
3319 RB_INSERT(_necp_client_global_tree
, &necp_client_global_tree
, client
);
3320 NECP_CLIENT_TREE_UNLOCK();
3322 // Prime the client result
3323 NECP_CLIENT_LOCK(client
);
3324 (void)necp_update_client_result(current_proc(), fd_data
, client
, NULL
);
3325 NECP_CLIENT_UNLOCK(client
);
3326 NECP_FD_UNLOCK(fd_data
);
3329 if (client
!= NULL
) {
3330 FREE(client
, M_NECP
);
3340 necp_client_remove(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
3343 struct necp_client
*client
= NULL
;
3344 struct necp_client find
= {};
3345 uuid_t client_id
= {};
3346 struct ifnet_stats_per_flow flow_ifnet_stats
= {};
3348 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
)) {
3353 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
3355 NECPLOG(LOG_ERR
, "necp_client_remove copyin client_id error (%d)", error
);
3359 if (uap
->buffer
!= 0 && uap
->buffer_size
== sizeof(flow_ifnet_stats
)) {
3360 error
= copyin(uap
->buffer
, &flow_ifnet_stats
, uap
->buffer_size
);
3362 NECPLOG(LOG_ERR
, "necp_client_remove flow_ifnet_stats copyin error (%d)", error
);
3363 // Not fatal; make sure to zero-out stats in case of partial copy
3364 memset(&flow_ifnet_stats
, 0, sizeof (flow_ifnet_stats
));
3367 } else if (uap
->buffer
!= 0) {
3368 NECPLOG(LOG_ERR
, "necp_client_remove unexpected parameters length (%zu)", uap
->buffer_size
);
3371 NECP_FD_LOCK(fd_data
);
3373 pid_t pid
= fd_data
->proc_pid
;
3374 uuid_copy(find
.client_id
, client_id
);
3375 client
= RB_FIND(_necp_client_tree
, &fd_data
->clients
, &find
);
3376 if (client
!= NULL
) {
3377 NECP_CLIENT_TREE_LOCK_EXCLUSIVE();
3378 RB_REMOVE(_necp_client_global_tree
, &necp_client_global_tree
, client
);
3379 NECP_CLIENT_TREE_UNLOCK();
3380 RB_REMOVE(_necp_client_tree
, &fd_data
->clients
, client
);
3383 NECP_FD_UNLOCK(fd_data
);
3385 if (client
!= NULL
) {
3387 necp_destroy_client(client
, pid
, true);
3390 NECPLOG(LOG_ERR
, "necp_client_remove invalid client_id (%d)", error
);
3400 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
)
3402 struct necp_client_parsed_parameters parsed_parameters
;
3405 error
= necp_client_parse_parameters(client
->parameters
,
3406 (u_int32_t
)client
->parameters_length
,
3407 &parsed_parameters
);
3409 NECPLOG(LOG_ERR
, "necp_client_parse_parameters error (%d)", error
);
3413 if ((flow
->remote_addr
.sa
.sa_family
!= AF_INET
&&
3414 flow
->remote_addr
.sa
.sa_family
!= AF_INET6
) ||
3415 (flow
->local_addr
.sa
.sa_family
!= AF_INET
&&
3416 flow
->local_addr
.sa
.sa_family
!= AF_INET6
)) {
3420 NECP_CLIENT_ROUTE_LOCK(client
);
3422 if (client
->current_route
== NULL
) {
3427 bool check_ecn
= false;
3429 if ((parsed_parameters
.flags
& NECP_CLIENT_PARAMETER_FLAG_ECN_ENABLE
) ==
3430 NECP_CLIENT_PARAMETER_FLAG_ECN_ENABLE
) {
3435 if ((parsed_parameters
.flags
& NECP_CLIENT_PARAMETER_FLAG_ECN_DISABLE
) ==
3436 NECP_CLIENT_PARAMETER_FLAG_ECN_DISABLE
) {
3440 if (client
->current_route
!= NULL
) {
3441 if (client
->current_route
->rt_ifp
->if_eflags
& IFEF_ECN_ENABLE
) {
3445 if (client
->current_route
->rt_ifp
->if_eflags
& IFEF_ECN_DISABLE
) {
3450 bool inbound
= ((parsed_parameters
.flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) == 0);
3451 if ((inbound
&& tcp_ecn_inbound
== 1) ||
3452 (!inbound
&& tcp_ecn_outbound
== 1)) {
3458 if (tcp_heuristic_do_ecn_with_address(client
->current_route
->rt_ifp
,
3459 (union sockaddr_in_4_6
*)&flow
->local_addr
)) {
3460 *flags
|= NECP_CLIENT_RESULT_FLAG_ECN_ENABLED
;
3464 if ((parsed_parameters
.flags
& NECP_CLIENT_PARAMETER_FLAG_TFO_ENABLE
) ==
3465 NECP_CLIENT_PARAMETER_FLAG_TFO_ENABLE
) {
3467 if (!tcp_heuristic_do_tfo_with_address(client
->current_route
->rt_ifp
,
3468 (union sockaddr_in_4_6
*)&flow
->local_addr
,
3469 (union sockaddr_in_4_6
*)&flow
->remote_addr
,
3470 tfo_cookie
, tfo_cookie_len
)) {
3471 *flags
|= NECP_CLIENT_RESULT_FLAG_FAST_OPEN_BLOCKED
;
3472 *tfo_cookie_len
= 0;
3475 *flags
|= NECP_CLIENT_RESULT_FLAG_FAST_OPEN_BLOCKED
;
3476 *tfo_cookie_len
= 0;
3479 NECP_CLIENT_ROUTE_UNLOCK(client
);
3485 necp_client_copy_internal(struct necp_client
*client
, bool client_is_observed
, struct necp_client_action_args
*uap
, int *retval
)
3489 if (uap
->action
== NECP_CLIENT_ACTION_COPY_PARAMETERS
) {
3490 if (uap
->buffer_size
< client
->parameters_length
) {
3494 error
= copyout(client
->parameters
, uap
->buffer
, client
->parameters_length
);
3496 NECPLOG(LOG_ERR
, "necp_client_copy parameters copyout error (%d)", error
);
3499 *retval
= client
->parameters_length
;
3500 } else if (uap
->action
== NECP_CLIENT_ACTION_COPY_UPDATED_RESULT
&&
3501 client
->result_read
&& client
->flow_result_read
) {
3502 // Copy updates only, but nothing to read
3503 // Just return 0 for bytes read
3505 } else if (uap
->action
== NECP_CLIENT_ACTION_COPY_RESULT
||
3506 uap
->action
== NECP_CLIENT_ACTION_COPY_UPDATED_RESULT
) {
3507 size_t assigned_results_size
= 0;
3508 struct necp_client_flow
*flow
= NULL
;
3509 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
3510 if (flow
->nexus
|| (flow
->socket
&& flow
->assigned
)) {
3511 size_t header_length
= 0;
3513 header_length
= sizeof(struct necp_client_nexus_flow_header
);
3515 header_length
= sizeof(struct necp_client_flow_header
);
3517 assigned_results_size
+= (header_length
+ flow
->assigned_results_length
);
3519 if (flow
->has_protoctl_event
) {
3520 assigned_results_size
+= sizeof(struct necp_client_flow_protoctl_event_header
);
3524 if (uap
->buffer_size
< (client
->result_length
+ assigned_results_size
)) {
3528 error
= copyout(client
->result
, uap
->buffer
, client
->result_length
);
3530 NECPLOG(LOG_ERR
, "necp_client_copy result copyout error (%d)", error
);
3534 size_t assigned_results_cursor
= 0;
3537 LIST_FOREACH(flow
, &client
->flow_list
, flow_chain
) {
3538 if (flow
->nexus
|| (flow
->socket
&& flow
->assigned
)) {
3539 // Write TLV headers
3540 struct necp_client_nexus_flow_header header
= {};
3541 u_int32_t length
= 0;
3542 u_int32_t flags
= 0;
3543 u_int8_t tfo_cookie_len
= 0;
3547 if (flow
->check_tcp_heuristics
) {
3548 u_int8_t tfo_cookie
[NECP_TFO_COOKIE_LEN_MAX
];
3549 tfo_cookie_len
= NECP_TFO_COOKIE_LEN_MAX
;
3551 if (necp_client_check_tcp_heuristics(client
, flow
, &flags
,
3552 tfo_cookie
, &tfo_cookie_len
) != 0) {
3555 flow
->check_tcp_heuristics
= FALSE
;
3557 if (tfo_cookie_len
!= 0) {
3558 type
= NECP_CLIENT_RESULT_TFO_COOKIE
;
3559 length
= tfo_cookie_len
;
3560 memcpy(&header
.tfo_cookie_tlv_header
.type
, &type
, sizeof(type
));
3561 memcpy(&header
.tfo_cookie_tlv_header
.length
, &length
, sizeof(length
));
3562 memcpy(&header
.tfo_cookie_value
, tfo_cookie
, tfo_cookie_len
);
3568 size_t header_length
= 0;
3570 if (tfo_cookie_len
!= 0) {
3571 header_length
= sizeof(struct necp_client_nexus_flow_header
) - (NECP_TFO_COOKIE_LEN_MAX
- tfo_cookie_len
);
3573 header_length
= sizeof(struct necp_client_nexus_flow_header
) - sizeof(struct necp_tlv_header
) - NECP_TFO_COOKIE_LEN_MAX
;
3576 header_length
= sizeof(struct necp_client_flow_header
);
3579 type
= NECP_CLIENT_RESULT_FLAGS
;
3580 length
= sizeof(header
.flow_header
.flags_value
);
3581 memcpy(&header
.flow_header
.flags_tlv_header
.type
, &type
, sizeof(type
));
3582 memcpy(&header
.flow_header
.flags_tlv_header
.length
, &length
, sizeof(length
));
3583 if (flow
->assigned
) {
3584 flags
|= NECP_CLIENT_RESULT_FLAG_FLOW_ASSIGNED
;
3587 flags
|= NECP_CLIENT_RESULT_FLAG_FLOW_VIABLE
;
3589 memcpy(&header
.flow_header
.flags_value
, &flags
, sizeof(flags
));
3591 type
= NECP_CLIENT_RESULT_INTERFACE
;
3592 length
= sizeof(header
.flow_header
.interface_value
);
3593 memcpy(&header
.flow_header
.interface_tlv_header
.type
, &type
, sizeof(type
));
3594 memcpy(&header
.flow_header
.interface_tlv_header
.length
, &length
, sizeof(length
));
3596 struct necp_client_result_interface interface_struct
;
3597 interface_struct
.generation
= 0;
3598 interface_struct
.index
= flow
->interface_index
;
3600 memcpy(&header
.flow_header
.interface_value
, &interface_struct
, sizeof(interface_struct
));
3602 type
= NECP_CLIENT_RESULT_NETAGENT
;
3603 length
= sizeof(header
.agent_value
);
3604 memcpy(&header
.agent_tlv_header
.type
, &type
, sizeof(type
));
3605 memcpy(&header
.agent_tlv_header
.length
, &length
, sizeof(length
));
3607 struct necp_client_result_netagent agent_struct
;
3608 agent_struct
.generation
= 0;
3609 uuid_copy(agent_struct
.netagent_uuid
, flow
->u
.nexus_agent
);
3611 memcpy(&header
.agent_value
, &agent_struct
, sizeof(agent_struct
));
3614 // Don't include outer TLV header in length field
3615 type
= NECP_CLIENT_RESULT_FLOW
;
3616 length
= (header_length
- sizeof(struct necp_tlv_header
) + flow
->assigned_results_length
);
3617 if (flow
->has_protoctl_event
) {
3618 length
+= sizeof(struct necp_client_flow_protoctl_event_header
);
3620 memcpy(&header
.flow_header
.outer_header
.type
, &type
, sizeof(type
));
3621 memcpy(&header
.flow_header
.outer_header
.length
, &length
, sizeof(length
));
3623 error
= copyout(&header
, uap
->buffer
+ client
->result_length
+ assigned_results_cursor
, header_length
);
3625 NECPLOG(LOG_ERR
, "necp_client_copy assigned results tlv_header copyout error (%d)", error
);
3628 assigned_results_cursor
+= header_length
;
3630 if (flow
->assigned_results
&& flow
->assigned_results_length
) {
3632 error
= copyout(flow
->assigned_results
, uap
->buffer
+ client
->result_length
+ assigned_results_cursor
,
3633 flow
->assigned_results_length
);
3635 NECPLOG(LOG_ERR
, "necp_client_copy assigned results copyout error (%d)", error
);
3639 assigned_results_cursor
+= flow
->assigned_results_length
;
3641 /* Read the protocol event and reset it */
3642 if (flow
->has_protoctl_event
) {
3643 struct necp_client_flow_protoctl_event_header protoctl_event_header
= {};
3645 type
= NECP_CLIENT_RESULT_PROTO_CTL_EVENT
;
3646 length
= sizeof(protoctl_event_header
.protoctl_event
);
3648 memcpy(&protoctl_event_header
.protoctl_tlv_header
.type
, &type
, sizeof(type
));
3649 memcpy(&protoctl_event_header
.protoctl_tlv_header
.length
, &length
, sizeof(length
));
3650 memcpy(&protoctl_event_header
.protoctl_event
, &flow
->protoctl_event
,
3651 sizeof(flow
->protoctl_event
));
3653 error
= copyout(&protoctl_event_header
, uap
->buffer
+ client
->result_length
+ assigned_results_cursor
,
3654 sizeof(protoctl_event_header
));
3657 NECPLOG(LOG_ERR
, "necp_client_copy protocol control event results"
3658 " tlv_header copyout error (%d)", error
);
3661 assigned_results_cursor
+= sizeof(protoctl_event_header
);
3662 flow
->has_protoctl_event
= FALSE
;
3663 flow
->protoctl_event
.protoctl_event_code
= 0;
3664 flow
->protoctl_event
.protoctl_event_val
= 0;
3665 flow
->protoctl_event
.protoctl_event_tcp_seq_num
= 0;
3670 *retval
= client
->result_length
+ assigned_results_cursor
;
3672 if (!client_is_observed
) {
3673 client
->result_read
= TRUE
;
3674 client
->flow_result_read
= TRUE
;
3683 necp_client_copy(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
3686 struct necp_client
*client
= NULL
;
3688 uuid_clear(client_id
);
3692 if (uap
->buffer_size
== 0 || uap
->buffer
== 0) {
3697 if (uap
->action
!= NECP_CLIENT_ACTION_COPY_PARAMETERS
&&
3698 uap
->action
!= NECP_CLIENT_ACTION_COPY_RESULT
&&
3699 uap
->action
!= NECP_CLIENT_ACTION_COPY_UPDATED_RESULT
) {
3704 if (uap
->client_id
) {
3705 if (uap
->client_id_len
!= sizeof(uuid_t
)) {
3706 NECPLOG(LOG_ERR
, "Incorrect length (got %d, expected %d)", uap
->client_id_len
, sizeof(uuid_t
));
3711 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
3713 NECPLOG(LOG_ERR
, "necp_client_copy client_id copyin error (%d)", error
);
3718 const bool is_wildcard
= (bool)uuid_is_null(client_id
);
3720 NECP_FD_LOCK(fd_data
);
3723 if (uap
->action
== NECP_CLIENT_ACTION_COPY_RESULT
|| uap
->action
== NECP_CLIENT_ACTION_COPY_UPDATED_RESULT
) {
3724 struct necp_client
*find_client
= NULL
;
3725 RB_FOREACH(find_client
, _necp_client_tree
, &fd_data
->clients
) {
3726 NECP_CLIENT_LOCK(find_client
);
3727 if (!find_client
->result_read
|| !find_client
->flow_result_read
) {
3728 client
= find_client
;
3729 // Leave the client locked, and break
3732 NECP_CLIENT_UNLOCK(find_client
);
3736 client
= necp_client_fd_find_client_and_lock(fd_data
, client_id
);
3739 if (client
!= NULL
) {
3740 // If client is set, it is locked
3741 error
= necp_client_copy_internal(client
, FALSE
, uap
, retval
);
3742 NECP_CLIENT_UNLOCK(client
);
3745 // Unlock our own fd before moving on or returning
3746 NECP_FD_UNLOCK(fd_data
);
3748 if (client
== NULL
) {
3749 if (fd_data
->flags
& NECP_OPEN_FLAG_OBSERVER
) {
3750 // Observers are allowed to lookup clients on other fds
3753 NECP_CLIENT_TREE_LOCK_SHARED();
3755 bool found_client
= FALSE
;
3757 struct necp_client find
;
3758 uuid_copy(find
.client_id
, client_id
);
3759 client
= RB_FIND(_necp_client_global_tree
, &necp_client_global_tree
, &find
);
3760 if (client
!= NULL
) {
3761 NECP_CLIENT_LOCK(client
);
3763 // Matched, copy out data
3764 found_client
= TRUE
;
3765 error
= necp_client_copy_internal(client
, TRUE
, uap
, retval
);
3767 NECP_CLIENT_UNLOCK(client
);
3771 NECP_CLIENT_TREE_UNLOCK();
3773 // No client found, fail
3774 if (!found_client
) {
3779 // No client found, and not allowed to search other fds, fail
3790 necp_client_copy_client_update(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
3796 if (!(fd_data
->flags
& NECP_OPEN_FLAG_PUSH_OBSERVER
)) {
3797 NECPLOG0(LOG_ERR
, "NECP fd is not observer, cannot copy client update");
3801 if (uap
->client_id_len
!= sizeof(uuid_t
) || uap
->client_id
== 0) {
3802 NECPLOG0(LOG_ERR
, "Client id invalid, cannot copy client update");
3806 if (uap
->buffer_size
== 0 || uap
->buffer
== 0) {
3807 NECPLOG0(LOG_ERR
, "Buffer invalid, cannot copy client update");
3811 NECP_FD_LOCK(fd_data
);
3812 struct necp_client_update
*client_update
= TAILQ_FIRST(&fd_data
->update_list
);
3813 if (client_update
!= NULL
) {
3814 TAILQ_REMOVE(&fd_data
->update_list
, client_update
, chain
);
3815 VERIFY(fd_data
->update_count
> 0);
3816 fd_data
->update_count
--;
3818 NECP_FD_UNLOCK(fd_data
);
3820 if (client_update
!= NULL
) {
3821 error
= copyout(client_update
->client_id
, uap
->client_id
, sizeof(uuid_t
));
3823 NECPLOG(LOG_ERR
, "Copy client update copyout client id error (%d)", error
);
3825 if (uap
->buffer_size
< client_update
->update_length
) {
3826 NECPLOG(LOG_ERR
, "Buffer size cannot hold update (%zu < %zu)", uap
->buffer_size
, client_update
->update_length
);
3829 error
= copyout(&client_update
->update
, uap
->buffer
, client_update
->update_length
);
3831 NECPLOG(LOG_ERR
, "Copy client update copyout error (%d)", error
);
3833 *retval
= client_update
->update_length
;
3838 FREE(client_update
, M_NECP
);
3839 client_update
= NULL
;
3848 necp_client_copy_parameters_locked(struct necp_client
*client
, struct necp_client_nexus_parameters
*parameters
)
3850 VERIFY(parameters
!= NULL
);
3852 struct necp_client_parsed_parameters parsed_parameters
= {};
3853 int error
= necp_client_parse_parameters(client
->parameters
, (u_int32_t
)client
->parameters_length
, &parsed_parameters
);
3855 parameters
->pid
= client
->proc_pid
;
3856 if (parsed_parameters
.valid_fields
& NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_PID
) {
3857 parameters
->epid
= parsed_parameters
.effective_pid
;
3859 parameters
->epid
= parameters
->pid
;
3861 memcpy(¶meters
->local_addr
, &parsed_parameters
.local_addr
, sizeof(parameters
->local_addr
));
3862 memcpy(¶meters
->remote_addr
, &parsed_parameters
.remote_addr
, sizeof(parameters
->remote_addr
));
3863 parameters
->ip_protocol
= parsed_parameters
.ip_protocol
;
3864 parameters
->traffic_class
= parsed_parameters
.traffic_class
;
3865 uuid_copy(parameters
->euuid
, parsed_parameters
.effective_uuid
);
3866 parameters
->is_listener
= (parsed_parameters
.flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) ? 1 : 0;
3867 parameters
->policy_id
= client
->policy_id
;
3869 // parse client result flag
3870 u_int32_t client_result_flags
= 0;
3871 u_int32_t value_size
= 0;
3872 u_int8_t
*flags_pointer
= NULL
;
3873 flags_pointer
= necp_buffer_get_tlv_value(client
->result
, 0, &value_size
);
3874 if (flags_pointer
&& value_size
== sizeof(client_result_flags
)) {
3875 memcpy(&client_result_flags
, flags_pointer
, value_size
);
3877 parameters
->allow_qos_marking
= (client_result_flags
& NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING
) ? 1 : 0;
3883 necp_client_copy_parameters(uuid_t client_id
, struct necp_client_nexus_parameters
*parameters
)
3886 struct necp_client
*client
= NULL
;
3888 if (parameters
== NULL
) {
3893 NECP_CLIENT_TREE_LOCK_SHARED();
3895 bool found_client
= FALSE
;
3896 struct necp_client find
;
3897 uuid_copy(find
.client_id
, client_id
);
3898 client
= RB_FIND(_necp_client_global_tree
, &necp_client_global_tree
, &find
);
3899 if (client
!= NULL
) {
3900 NECP_CLIENT_LOCK(client
);
3902 // Matched, parse parameters
3903 found_client
= TRUE
;
3904 error
= necp_client_copy_parameters_locked(client
, parameters
);
3906 NECP_CLIENT_UNLOCK(client
);
3910 NECP_CLIENT_TREE_UNLOCK();
3912 // No client found, fail
3913 if (!found_client
) {
3921 necp_client_list(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
3924 struct necp_client
*find_client
= NULL
;
3925 uuid_t
*list
= NULL
;
3926 u_int32_t requested_client_count
= 0;
3927 u_int32_t client_count
= 0;
3928 size_t copy_buffer_size
= 0;
3930 if (uap
->buffer_size
< sizeof(requested_client_count
) || uap
->buffer
== 0) {
3935 if (!(fd_data
->flags
& NECP_OPEN_FLAG_OBSERVER
)) {
3936 NECPLOG0(LOG_ERR
, "Client does not hold necessary entitlement to list other NECP clients");
3941 error
= copyin(uap
->buffer
, &requested_client_count
, sizeof(requested_client_count
));
3946 if (os_mul_overflow(sizeof(uuid_t
), requested_client_count
, ©_buffer_size
)) {
3951 if (uap
->buffer_size
- sizeof(requested_client_count
) != copy_buffer_size
) {
3956 if (copy_buffer_size
> NECP_MAX_CLIENT_LIST_SIZE
) {
3961 if (requested_client_count
> 0) {
3962 if ((list
= _MALLOC(copy_buffer_size
, M_NECP
, M_WAITOK
| M_ZERO
)) == NULL
) {
3969 NECP_CLIENT_TREE_LOCK_SHARED();
3972 RB_FOREACH(find_client
, _necp_client_global_tree
, &necp_client_global_tree
) {
3973 NECP_CLIENT_LOCK(find_client
);
3974 if (!uuid_is_null(find_client
->client_id
)) {
3975 if (client_count
< requested_client_count
) {
3976 uuid_copy(list
[client_count
], find_client
->client_id
);
3980 NECP_CLIENT_UNLOCK(find_client
);
3984 NECP_CLIENT_TREE_UNLOCK();
3986 error
= copyout(&client_count
, uap
->buffer
, sizeof(client_count
));
3988 NECPLOG(LOG_ERR
, "necp_client_list buffer copyout error (%d)", error
);
3992 if (requested_client_count
> 0 &&
3995 error
= copyout(list
, uap
->buffer
+ sizeof(client_count
), copy_buffer_size
);
3997 NECPLOG(LOG_ERR
, "necp_client_list client count copyout error (%d)", error
);
4012 necp_client_add_assertion(struct necp_client
*client
, uuid_t netagent_uuid
)
4014 struct necp_client_assertion
*new_assertion
= NULL
;
4016 MALLOC(new_assertion
, struct necp_client_assertion
*, sizeof(*new_assertion
), M_NECP
, M_WAITOK
);
4017 if (new_assertion
== NULL
) {
4018 NECPLOG0(LOG_ERR
, "Failed to allocate assertion");
4022 uuid_copy(new_assertion
->asserted_netagent
, netagent_uuid
);
4024 LIST_INSERT_HEAD(&client
->assertion_list
, new_assertion
, assertion_chain
);
4028 necp_client_remove_assertion(struct necp_client
*client
, uuid_t netagent_uuid
)
4030 struct necp_client_assertion
*found_assertion
= NULL
;
4031 struct necp_client_assertion
*search_assertion
= NULL
;
4032 LIST_FOREACH(search_assertion
, &client
->assertion_list
, assertion_chain
) {
4033 if (uuid_compare(search_assertion
->asserted_netagent
, netagent_uuid
) == 0) {
4034 found_assertion
= search_assertion
;
4039 if (found_assertion
== NULL
) {
4040 NECPLOG0(LOG_ERR
, "Netagent uuid not previously asserted");
4044 LIST_REMOVE(found_assertion
, assertion_chain
);
4045 FREE(found_assertion
, M_NECP
);
4050 necp_client_agent_action(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
4053 struct necp_client
*client
= NULL
;
4055 bool acted_on_agent
= FALSE
;
4056 u_int8_t
*parameters
= NULL
;
4057 size_t parameters_size
= uap
->buffer_size
;
4059 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
4060 uap
->buffer_size
== 0 || uap
->buffer
== 0) {
4061 NECPLOG0(LOG_ERR
, "necp_client_agent_action invalid parameters");
4066 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
4068 NECPLOG(LOG_ERR
, "necp_client_agent_action copyin client_id error (%d)", error
);
4072 if ((parameters
= _MALLOC(uap
->buffer_size
, M_NECP
, M_WAITOK
| M_ZERO
)) == NULL
) {
4073 NECPLOG0(LOG_ERR
, "necp_client_agent_action malloc failed");
4078 error
= copyin(uap
->buffer
, parameters
, uap
->buffer_size
);
4080 NECPLOG(LOG_ERR
, "necp_client_agent_action parameters copyin error (%d)", error
);
4084 NECP_FD_LOCK(fd_data
);
4085 client
= necp_client_fd_find_client_and_lock(fd_data
, client_id
);
4086 if (client
!= NULL
) {
4088 while ((offset
+ sizeof(struct necp_tlv_header
)) <= parameters_size
) {
4089 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
4090 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
4092 if (length
> (parameters_size
- (offset
+ sizeof(struct necp_tlv_header
)))) {
4093 // If the length is larger than what can fit in the remaining parameters size, bail
4094 NECPLOG(LOG_ERR
, "Invalid TLV length (%u)", length
);
4099 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
4100 if (length
>= sizeof(uuid_t
) &&
4102 (type
== NECP_CLIENT_PARAMETER_TRIGGER_AGENT
||
4103 type
== NECP_CLIENT_PARAMETER_ASSERT_AGENT
||
4104 type
== NECP_CLIENT_PARAMETER_UNASSERT_AGENT
)) {
4107 uuid_copy(agent_uuid
, value
);
4108 u_int8_t netagent_message_type
= 0;
4109 if (type
== NECP_CLIENT_PARAMETER_TRIGGER_AGENT
) {
4110 netagent_message_type
= NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER
;
4111 } else if (type
== NECP_CLIENT_PARAMETER_ASSERT_AGENT
) {
4112 netagent_message_type
= NETAGENT_MESSAGE_TYPE_CLIENT_ASSERT
;
4113 } else if (type
== NECP_CLIENT_PARAMETER_UNASSERT_AGENT
) {
4114 netagent_message_type
= NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT
;
4117 // Before unasserting, verify that the assertion was already taken
4118 if (type
== NECP_CLIENT_PARAMETER_UNASSERT_AGENT
) {
4119 if (!necp_client_remove_assertion(client
, agent_uuid
)) {
4125 struct necp_client_nexus_parameters parsed_parameters
= {};
4126 necp_client_copy_parameters_locked(client
, &parsed_parameters
);
4128 error
= netagent_client_message_with_params(agent_uuid
,
4131 netagent_message_type
,
4135 acted_on_agent
= TRUE
;
4140 // Only save the assertion if the action succeeded
4141 if (type
== NECP_CLIENT_PARAMETER_ASSERT_AGENT
) {
4142 necp_client_add_assertion(client
, agent_uuid
);
4147 offset
+= sizeof(struct necp_tlv_header
) + length
;
4150 NECP_CLIENT_UNLOCK(client
);
4152 NECP_FD_UNLOCK(fd_data
);
4154 if (!acted_on_agent
&&
4160 if (parameters
!= NULL
) {
4161 FREE(parameters
, M_NECP
);
4169 necp_client_copy_agent(__unused
struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
4174 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
4175 uap
->buffer_size
== 0 || uap
->buffer
== 0) {
4176 NECPLOG0(LOG_ERR
, "necp_client_copy_agent bad input");
4181 error
= copyin(uap
->client_id
, agent_uuid
, sizeof(uuid_t
));
4183 NECPLOG(LOG_ERR
, "necp_client_copy_agent copyin agent_uuid error (%d)", error
);
4187 error
= netagent_copyout(agent_uuid
, uap
->buffer
, uap
->buffer_size
);
4189 // netagent_copyout already logs appropriate errors
4199 necp_client_agent_use(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
4202 struct necp_client
*client
= NULL
;
4204 struct necp_agent_use_parameters parameters
;
4206 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
4207 uap
->buffer_size
!= sizeof(parameters
) || uap
->buffer
== 0) {
4212 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
4214 NECPLOG(LOG_ERR
, "Copyin client_id error (%d)", error
);
4218 error
= copyin(uap
->buffer
, ¶meters
, uap
->buffer_size
);
4220 NECPLOG(LOG_ERR
, "Parameters copyin error (%d)", error
);
4224 NECP_FD_LOCK(fd_data
);
4225 client
= necp_client_fd_find_client_and_lock(fd_data
, client_id
);
4226 if (client
!= NULL
) {
4227 error
= netagent_use(parameters
.agent_uuid
, ¶meters
.out_use_count
);
4228 NECP_CLIENT_UNLOCK(client
);
4233 NECP_FD_UNLOCK(fd_data
);
4236 error
= copyout(¶meters
, uap
->buffer
, uap
->buffer_size
);
4238 NECPLOG(LOG_ERR
, "Parameters copyout error (%d)", error
);
4250 necp_client_copy_interface(__unused
struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
4253 u_int32_t interface_index
= 0;
4254 struct necp_interface_details interface_details
;
4256 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(u_int32_t
) ||
4257 uap
->buffer_size
< sizeof(interface_details
) || uap
->buffer
== 0) {
4258 NECPLOG0(LOG_ERR
, "necp_client_copy_interface bad input");
4263 error
= copyin(uap
->client_id
, &interface_index
, sizeof(u_int32_t
));
4265 NECPLOG(LOG_ERR
, "necp_client_copy_interface copyin interface_index error (%d)", error
);
4269 if (interface_index
== 0) {
4271 NECPLOG(LOG_ERR
, "necp_client_copy_interface bad interface_index (%d)", interface_index
);
4275 memset(&interface_details
, 0, sizeof(interface_details
));
4277 ifnet_head_lock_shared();
4278 ifnet_t interface
= NULL
;
4279 if (interface_index
!= IFSCOPE_NONE
&& interface_index
<= (u_int32_t
)if_index
) {
4280 interface
= ifindex2ifnet
[interface_index
];
4283 if (interface
!= NULL
) {
4284 if (interface
->if_xname
!= NULL
) {
4285 strlcpy((char *)&interface_details
.name
, interface
->if_xname
, sizeof(interface_details
.name
));
4287 interface_details
.index
= interface
->if_index
;
4288 interface_details
.generation
= ifnet_get_generation(interface
);
4289 if (interface
->if_delegated
.ifp
!= NULL
) {
4290 interface_details
.delegate_index
= interface
->if_delegated
.ifp
->if_index
;
4292 interface_details
.functional_type
= if_functional_type(interface
, TRUE
);
4293 if (IFNET_IS_EXPENSIVE(interface
)) {
4294 interface_details
.flags
|= NECP_INTERFACE_FLAG_EXPENSIVE
;
4296 if ((interface
->if_eflags
& IFEF_TXSTART
) == IFEF_TXSTART
) {
4297 interface_details
.flags
|= NECP_INTERFACE_FLAG_TXSTART
;
4299 if ((interface
->if_eflags
& IFEF_NOACKPRI
) == IFEF_NOACKPRI
) {
4300 interface_details
.flags
|= NECP_INTERFACE_FLAG_NOACKPRI
;
4302 interface_details
.mtu
= interface
->if_mtu
;
4304 u_int8_t ipv4_signature_len
= sizeof(interface_details
.ipv4_signature
.signature
);
4305 u_int16_t ipv4_signature_flags
;
4306 if (ifnet_get_netsignature(interface
, AF_INET
, &ipv4_signature_len
, &ipv4_signature_flags
,
4307 (u_int8_t
*)&interface_details
.ipv4_signature
) != 0) {
4308 ipv4_signature_len
= 0;
4310 interface_details
.ipv4_signature
.signature_len
= ipv4_signature_len
;
4312 u_int8_t ipv6_signature_len
= sizeof(interface_details
.ipv6_signature
.signature
);
4313 u_int16_t ipv6_signature_flags
;
4314 if (ifnet_get_netsignature(interface
, AF_INET6
, &ipv6_signature_len
, &ipv6_signature_flags
,
4315 (u_int8_t
*)&interface_details
.ipv6_signature
) != 0) {
4316 ipv6_signature_len
= 0;
4318 interface_details
.ipv6_signature
.signature_len
= ipv6_signature_len
;
4323 error
= copyout(&interface_details
, uap
->buffer
, sizeof(interface_details
));
4325 NECPLOG(LOG_ERR
, "necp_client_copy_interface copyout error (%d)", error
);
4336 necp_client_copy_route_statistics(__unused
struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
4339 struct necp_client
*client
= NULL
;
4342 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
4343 uap
->buffer_size
< sizeof(struct necp_stat_counts
) || uap
->buffer
== 0) {
4344 NECPLOG0(LOG_ERR
, "necp_client_copy_route_statistics bad input");
4349 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
4351 NECPLOG(LOG_ERR
, "necp_client_copy_route_statistics copyin client_id error (%d)", error
);
4356 NECP_FD_LOCK(fd_data
);
4357 client
= necp_client_fd_find_client_and_lock(fd_data
, client_id
);
4358 if (client
!= NULL
) {
4359 NECP_CLIENT_ROUTE_LOCK(client
);
4360 struct necp_stat_counts route_stats
= {};
4361 if (client
->current_route
!= NULL
&& client
->current_route
->rt_stats
!= NULL
) {
4362 struct nstat_counts
*rt_stats
= client
->current_route
->rt_stats
;
4363 atomic_get_64(route_stats
.necp_stat_rxpackets
, &rt_stats
->nstat_rxpackets
);
4364 atomic_get_64(route_stats
.necp_stat_rxbytes
, &rt_stats
->nstat_rxbytes
);
4365 atomic_get_64(route_stats
.necp_stat_txpackets
, &rt_stats
->nstat_txpackets
);
4366 atomic_get_64(route_stats
.necp_stat_txbytes
, &rt_stats
->nstat_txbytes
);
4367 route_stats
.necp_stat_rxduplicatebytes
= rt_stats
->nstat_rxduplicatebytes
;
4368 route_stats
.necp_stat_rxoutoforderbytes
= rt_stats
->nstat_rxoutoforderbytes
;
4369 route_stats
.necp_stat_txretransmit
= rt_stats
->nstat_txretransmit
;
4370 route_stats
.necp_stat_connectattempts
= rt_stats
->nstat_connectattempts
;
4371 route_stats
.necp_stat_connectsuccesses
= rt_stats
->nstat_connectsuccesses
;
4372 route_stats
.necp_stat_min_rtt
= rt_stats
->nstat_min_rtt
;
4373 route_stats
.necp_stat_avg_rtt
= rt_stats
->nstat_avg_rtt
;
4374 route_stats
.necp_stat_var_rtt
= rt_stats
->nstat_var_rtt
;
4375 route_stats
.necp_stat_route_flags
= client
->current_route
->rt_flags
;
4378 // Unlock before copying out
4379 NECP_CLIENT_ROUTE_UNLOCK(client
);
4380 NECP_CLIENT_UNLOCK(client
);
4381 NECP_FD_UNLOCK(fd_data
);
4383 error
= copyout(&route_stats
, uap
->buffer
, sizeof(route_stats
));
4385 NECPLOG(LOG_ERR
, "necp_client_copy_route_statistics copyout error (%d)", error
);
4389 NECP_FD_UNLOCK(fd_data
);
4400 necp_client_update_cache(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
4403 struct necp_client
*client
= NULL
;
4406 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
)) {
4411 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
4413 NECPLOG(LOG_ERR
, "necp_client_update_cache copyin client_id error (%d)", error
);
4417 NECP_FD_LOCK(fd_data
);
4418 client
= necp_client_fd_find_client_and_lock(fd_data
, client_id
);
4419 if (client
== NULL
) {
4420 NECP_FD_UNLOCK(fd_data
);
4425 NECP_CLIENT_ROUTE_LOCK(client
);
4426 // This needs to be changed when TFO/ECN is supported by multiple flows
4427 struct necp_client_flow
*flow
= LIST_FIRST(&client
->flow_list
);
4429 (flow
->remote_addr
.sa
.sa_family
!= AF_INET
&&
4430 flow
->remote_addr
.sa
.sa_family
!= AF_INET6
) ||
4431 (flow
->local_addr
.sa
.sa_family
!= AF_INET
&&
4432 flow
->local_addr
.sa
.sa_family
!= AF_INET6
)) {
4434 NECPLOG(LOG_ERR
, "necp_client_update_cache no flow error (%d)", error
);
4438 necp_cache_buffer cache_buffer
;
4439 memset(&cache_buffer
, 0, sizeof(cache_buffer
));
4441 if (uap
->buffer_size
!= sizeof(necp_cache_buffer
) ||
4442 uap
->buffer
== USER_ADDR_NULL
) {
4447 error
= copyin(uap
->buffer
, &cache_buffer
, sizeof(cache_buffer
));
4449 NECPLOG(LOG_ERR
, "necp_client_update_cache copyin cache buffer error (%d)", error
);
4453 if (cache_buffer
.necp_cache_buf_type
== NECP_CLIENT_CACHE_TYPE_ECN
&&
4454 cache_buffer
.necp_cache_buf_ver
== NECP_CLIENT_CACHE_TYPE_ECN_VER_1
) {
4455 if (cache_buffer
.necp_cache_buf_size
!= sizeof(necp_tcp_ecn_cache
) ||
4456 cache_buffer
.necp_cache_buf_addr
== USER_ADDR_NULL
) {
4461 necp_tcp_ecn_cache ecn_cache_buffer
;
4462 memset(&ecn_cache_buffer
, 0, sizeof(ecn_cache_buffer
));
4464 error
= copyin(cache_buffer
.necp_cache_buf_addr
, &ecn_cache_buffer
, sizeof(necp_tcp_ecn_cache
));
4466 NECPLOG(LOG_ERR
, "necp_client_update_cache copyin ecn cache buffer error (%d)", error
);
4470 if (client
->current_route
!= NULL
&& client
->current_route
->rt_ifp
!= NULL
) {
4471 if (!client
->platform_binary
) {
4472 ecn_cache_buffer
.necp_tcp_ecn_heuristics_success
= 0;
4474 tcp_heuristics_ecn_update(&ecn_cache_buffer
, client
->current_route
->rt_ifp
,
4475 (union sockaddr_in_4_6
*)&flow
->local_addr
);
4477 } else if (cache_buffer
.necp_cache_buf_type
== NECP_CLIENT_CACHE_TYPE_TFO
&&
4478 cache_buffer
.necp_cache_buf_ver
== NECP_CLIENT_CACHE_TYPE_TFO_VER_1
) {
4479 if (cache_buffer
.necp_cache_buf_size
!= sizeof(necp_tcp_tfo_cache
) ||
4480 cache_buffer
.necp_cache_buf_addr
== USER_ADDR_NULL
) {
4485 necp_tcp_tfo_cache tfo_cache_buffer
;
4486 memset(&tfo_cache_buffer
, 0, sizeof(tfo_cache_buffer
));
4488 error
= copyin(cache_buffer
.necp_cache_buf_addr
, &tfo_cache_buffer
, sizeof(necp_tcp_tfo_cache
));
4490 NECPLOG(LOG_ERR
, "necp_client_update_cache copyin tfo cache buffer error (%d)", error
);
4494 if (client
->current_route
!= NULL
&& client
->current_route
->rt_ifp
!= NULL
) {
4495 if (!client
->platform_binary
) {
4496 tfo_cache_buffer
.necp_tcp_tfo_heuristics_success
= 0;
4498 tcp_heuristics_tfo_update(&tfo_cache_buffer
, client
->current_route
->rt_ifp
,
4499 (union sockaddr_in_4_6
*)&flow
->local_addr
,
4500 (union sockaddr_in_4_6
*)&flow
->remote_addr
);
4506 NECP_CLIENT_ROUTE_UNLOCK(client
);
4507 NECP_CLIENT_UNLOCK(client
);
4508 NECP_FD_UNLOCK(fd_data
);
4515 necp_client_action(struct proc
*p
, struct necp_client_action_args
*uap
, int *retval
)
4519 int return_value
= 0;
4520 struct necp_fd_data
*fd_data
= NULL
;
4521 error
= necp_find_fd_data(uap
->necp_fd
, &fd_data
);
4523 NECPLOG(LOG_ERR
, "necp_client_action find fd error (%d)", error
);
4527 u_int32_t action
= uap
->action
;
4529 case NECP_CLIENT_ACTION_ADD
: {
4530 return_value
= necp_client_add(p
, fd_data
, uap
, retval
);
4533 case NECP_CLIENT_ACTION_REMOVE
: {
4534 return_value
= necp_client_remove(fd_data
, uap
, retval
);
4537 case NECP_CLIENT_ACTION_COPY_PARAMETERS
:
4538 case NECP_CLIENT_ACTION_COPY_RESULT
:
4539 case NECP_CLIENT_ACTION_COPY_UPDATED_RESULT
: {
4540 return_value
= necp_client_copy(fd_data
, uap
, retval
);
4543 case NECP_CLIENT_ACTION_COPY_LIST
: {
4544 return_value
= necp_client_list(fd_data
, uap
, retval
);
4547 case NECP_CLIENT_ACTION_AGENT
: {
4548 return_value
= necp_client_agent_action(fd_data
, uap
, retval
);
4551 case NECP_CLIENT_ACTION_COPY_AGENT
: {
4552 return_value
= necp_client_copy_agent(fd_data
, uap
, retval
);
4555 case NECP_CLIENT_ACTION_AGENT_USE
: {
4556 return_value
= necp_client_agent_use(fd_data
, uap
, retval
);
4559 case NECP_CLIENT_ACTION_COPY_INTERFACE
: {
4560 return_value
= necp_client_copy_interface(fd_data
, uap
, retval
);
4563 case NECP_CLIENT_ACTION_COPY_ROUTE_STATISTICS
: {
4564 return_value
= necp_client_copy_route_statistics(fd_data
, uap
, retval
);
4567 case NECP_CLIENT_ACTION_UPDATE_CACHE
: {
4568 return_value
= necp_client_update_cache(fd_data
, uap
, retval
);
4571 case NECP_CLIENT_ACTION_COPY_CLIENT_UPDATE
: {
4572 return_value
= necp_client_copy_client_update(fd_data
, uap
, retval
);
4576 NECPLOG(LOG_ERR
, "necp_client_action unknown action (%u)", action
);
4577 return_value
= EINVAL
;
4582 file_drop(uap
->necp_fd
);
4584 return (return_value
);
4587 #define NECP_MAX_MATCH_POLICY_PARAMETER_SIZE 1024
4590 necp_match_policy(struct proc
*p
, struct necp_match_policy_args
*uap
, int32_t *retval
)
4592 #pragma unused(retval)
4593 u_int8_t
*parameters
= NULL
;
4594 struct necp_aggregate_result returned_result
= {};
4602 if (uap
->parameters
== 0 || uap
->parameters_size
== 0 || uap
->parameters_size
> NECP_MAX_MATCH_POLICY_PARAMETER_SIZE
|| uap
->returned_result
== 0) {
4607 MALLOC(parameters
, u_int8_t
*, uap
->parameters_size
, M_NECP
, M_WAITOK
| M_ZERO
);
4608 if (parameters
== NULL
) {
4612 // Copy parameters in
4613 error
= copyin(uap
->parameters
, parameters
, uap
->parameters_size
);
4618 error
= necp_application_find_policy_match_internal(p
, parameters
, uap
->parameters_size
,
4619 &returned_result
, NULL
, 0, NULL
, NULL
, NULL
, false);
4624 // Copy return value back
4625 error
= copyout(&returned_result
, uap
->returned_result
, sizeof(struct necp_aggregate_result
));
4630 if (parameters
!= NULL
) {
4631 FREE(parameters
, M_NECP
);
4636 /// Socket operations
4637 #define NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH 253
4640 necp_set_socket_attribute(u_int8_t
*buffer
, size_t buffer_length
, u_int8_t type
, char **buffer_p
)
4644 size_t string_size
= 0;
4645 char *local_string
= NULL
;
4646 u_int8_t
*value
= NULL
;
4648 cursor
= necp_buffer_find_tlv(buffer
, buffer_length
, 0, type
, 0);
4650 // This will clear out the parameter
4654 string_size
= necp_buffer_get_tlv_length(buffer
, cursor
);
4655 if (string_size
== 0 || string_size
> NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH
) {
4656 // This will clear out the parameter
4660 MALLOC(local_string
, char *, string_size
+ 1, M_NECP
, M_WAITOK
| M_ZERO
);
4661 if (local_string
== NULL
) {
4662 NECPLOG(LOG_ERR
, "Failed to allocate a socket attribute buffer (size %d)", string_size
);
4666 value
= necp_buffer_get_tlv_value(buffer
, cursor
, NULL
);
4667 if (value
== NULL
) {
4668 NECPLOG0(LOG_ERR
, "Failed to get socket attribute");
4672 memcpy(local_string
, value
, string_size
);
4673 local_string
[string_size
] = 0;
4676 if (*buffer_p
!= NULL
) {
4677 FREE(*buffer_p
, M_NECP
);
4681 *buffer_p
= local_string
;
4684 if (local_string
!= NULL
) {
4685 FREE(local_string
, M_NECP
);
4691 necp_set_socket_attributes(struct socket
*so
, struct sockopt
*sopt
)
4694 u_int8_t
*buffer
= NULL
;
4695 struct inpcb
*inp
= NULL
;
4697 if ((SOCK_DOM(so
) != PF_INET
4699 && SOCK_DOM(so
) != PF_INET6
4706 inp
= sotoinpcb(so
);
4708 size_t valsize
= sopt
->sopt_valsize
;
4710 valsize
> ((sizeof(struct necp_tlv_header
) + NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH
) * 2)) {
4714 MALLOC(buffer
, u_int8_t
*, valsize
, M_NECP
, M_WAITOK
| M_ZERO
);
4715 if (buffer
== NULL
) {
4719 error
= sooptcopyin(sopt
, buffer
, valsize
, 0);
4724 error
= necp_set_socket_attribute(buffer
, valsize
, NECP_TLV_ATTRIBUTE_DOMAIN
, &inp
->inp_necp_attributes
.inp_domain
);
4726 NECPLOG0(LOG_ERR
, "Could not set domain TLV for socket attributes");
4730 error
= necp_set_socket_attribute(buffer
, valsize
, NECP_TLV_ATTRIBUTE_ACCOUNT
, &inp
->inp_necp_attributes
.inp_account
);
4732 NECPLOG0(LOG_ERR
, "Could not set account TLV for socket attributes");
4737 NECPLOG(LOG_DEBUG
, "Set on socket: Domain %s, Account %s", inp
->inp_necp_attributes
.inp_domain
, inp
->inp_necp_attributes
.inp_account
);
4740 if (buffer
!= NULL
) {
4741 FREE(buffer
, M_NECP
);
4748 necp_get_socket_attributes(struct socket
*so
, struct sockopt
*sopt
)
4751 u_int8_t
*buffer
= NULL
;
4752 u_int8_t
*cursor
= NULL
;
4754 struct inpcb
*inp
= NULL
;
4756 if ((SOCK_DOM(so
) != PF_INET
4758 && SOCK_DOM(so
) != PF_INET6
4765 inp
= sotoinpcb(so
);
4766 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
4767 valsize
+= sizeof(struct necp_tlv_header
) + strlen(inp
->inp_necp_attributes
.inp_domain
);
4769 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
4770 valsize
+= sizeof(struct necp_tlv_header
) + strlen(inp
->inp_necp_attributes
.inp_account
);
4776 MALLOC(buffer
, u_int8_t
*, valsize
, M_NECP
, M_WAITOK
| M_ZERO
);
4777 if (buffer
== NULL
) {
4782 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
4783 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ATTRIBUTE_DOMAIN
, strlen(inp
->inp_necp_attributes
.inp_domain
), inp
->inp_necp_attributes
.inp_domain
,
4787 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
4788 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ATTRIBUTE_ACCOUNT
, strlen(inp
->inp_necp_attributes
.inp_account
), inp
->inp_necp_attributes
.inp_account
,
4792 error
= sooptcopyout(sopt
, buffer
, valsize
);
4797 if (buffer
!= NULL
) {
4798 FREE(buffer
, M_NECP
);
4805 necp_create_nexus_assign_message(uuid_t nexus_instance
, u_int32_t nexus_port
, void *key
, uint32_t key_length
,
4806 struct necp_client_endpoint
*local_endpoint
, struct necp_client_endpoint
*remote_endpoint
,
4807 u_int32_t flow_adv_index
, size_t *message_length
)
4809 u_int8_t
*buffer
= NULL
;
4810 u_int8_t
*cursor
= NULL
;
4812 bool has_nexus_assignment
= FALSE
;
4815 if (!uuid_is_null(nexus_instance
)) {
4816 has_nexus_assignment
= TRUE
;
4817 valsize
+= sizeof(struct necp_tlv_header
) + sizeof(uuid_t
);
4818 valsize
+= sizeof(struct necp_tlv_header
) + sizeof(u_int32_t
);
4820 if (flow_adv_index
!= NECP_FLOWADV_IDX_INVALID
) {
4821 valsize
+= sizeof(struct necp_tlv_header
) + sizeof(u_int32_t
);
4823 if (key
!= NULL
&& key_length
> 0) {
4824 valsize
+= sizeof(struct necp_tlv_header
) + key_length
;
4826 if (local_endpoint
!= NULL
) {
4827 valsize
+= sizeof(struct necp_tlv_header
) + sizeof(struct necp_client_endpoint
);
4829 if (remote_endpoint
!= NULL
) {
4830 valsize
+= sizeof(struct necp_tlv_header
) + sizeof(struct necp_client_endpoint
);
4836 MALLOC(buffer
, u_int8_t
*, valsize
, M_NETAGENT
, M_WAITOK
| M_ZERO
); // Use M_NETAGENT area, since it is expected upon free
4837 if (buffer
== NULL
) {
4842 if (has_nexus_assignment
) {
4843 cursor
= necp_buffer_write_tlv(cursor
, NECP_CLIENT_RESULT_NEXUS_INSTANCE
, sizeof(uuid_t
), nexus_instance
, buffer
, valsize
);
4844 cursor
= necp_buffer_write_tlv(cursor
, NECP_CLIENT_RESULT_NEXUS_PORT
, sizeof(u_int32_t
), &nexus_port
, buffer
, valsize
);
4846 if (flow_adv_index
!= NECP_FLOWADV_IDX_INVALID
) {
4847 cursor
= necp_buffer_write_tlv(cursor
, NECP_CLIENT_RESULT_NEXUS_PORT_FLOW_INDEX
, sizeof(u_int32_t
), &flow_adv_index
, buffer
, valsize
);
4849 if (key
!= NULL
&& key_length
> 0) {
4850 cursor
= necp_buffer_write_tlv(cursor
, NECP_CLIENT_PARAMETER_NEXUS_KEY
, key_length
, key
, buffer
, valsize
);
4852 if (local_endpoint
!= NULL
) {
4853 cursor
= necp_buffer_write_tlv(cursor
, NECP_CLIENT_RESULT_LOCAL_ENDPOINT
, sizeof(struct necp_client_endpoint
), local_endpoint
, buffer
, valsize
);
4855 if (remote_endpoint
!= NULL
) {
4856 cursor
= necp_buffer_write_tlv(cursor
, NECP_CLIENT_RESULT_REMOTE_ENDPOINT
, sizeof(struct necp_client_endpoint
), remote_endpoint
, buffer
, valsize
);
4859 *message_length
= valsize
;
4865 necp_inpcb_remove_cb(struct inpcb
*inp
)
4867 if (!uuid_is_null(inp
->necp_client_uuid
)) {
4868 necp_client_unregister_socket_flow(inp
->necp_client_uuid
, inp
);
4869 uuid_clear(inp
->necp_client_uuid
);
4874 necp_inpcb_dispose(struct inpcb
*inp
)
4876 necp_inpcb_remove_cb(inp
); // Clear out socket registrations if not yet done
4877 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
4878 FREE(inp
->inp_necp_attributes
.inp_domain
, M_NECP
);
4879 inp
->inp_necp_attributes
.inp_domain
= NULL
;
4881 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
4882 FREE(inp
->inp_necp_attributes
.inp_account
, M_NECP
);
4883 inp
->inp_necp_attributes
.inp_account
= NULL
;
4888 necp_mppcb_dispose(struct mppcb
*mpp
)
4890 if (!uuid_is_null(mpp
->necp_client_uuid
)) {
4891 necp_client_unregister_multipath_cb(mpp
->necp_client_uuid
, mpp
);
4892 uuid_clear(mpp
->necp_client_uuid
);
4899 necp_client_init(void)
4901 necp_fd_grp_attr
= lck_grp_attr_alloc_init();
4902 if (necp_fd_grp_attr
== NULL
) {
4903 panic("lck_grp_attr_alloc_init failed\n");
4907 necp_fd_mtx_grp
= lck_grp_alloc_init("necp_fd", necp_fd_grp_attr
);
4908 if (necp_fd_mtx_grp
== NULL
) {
4909 panic("lck_grp_alloc_init failed\n");
4913 necp_fd_mtx_attr
= lck_attr_alloc_init();
4914 if (necp_fd_mtx_attr
== NULL
) {
4915 panic("lck_attr_alloc_init failed\n");
4919 necp_client_fd_size
= sizeof(struct necp_fd_data
);
4920 necp_client_fd_zone
= zinit(necp_client_fd_size
,
4921 NECP_CLIENT_FD_ZONE_MAX
* necp_client_fd_size
,
4922 0, NECP_CLIENT_FD_ZONE_NAME
);
4923 if (necp_client_fd_zone
== NULL
) {
4924 panic("zinit(necp_client_fd) failed\n");
4928 necp_flow_size
= sizeof(struct necp_client_flow
);
4929 necp_flow_cache
= mcache_create(NECP_FLOW_ZONE_NAME
, necp_flow_size
, sizeof (uint64_t), 0, MCR_SLEEP
);
4930 if (necp_flow_cache
== NULL
) {
4931 panic("mcache_create(necp_flow_cache) failed\n");
4935 necp_client_update_tcall
= thread_call_allocate_with_options(necp_update_all_clients_callout
, NULL
,
4936 THREAD_CALL_PRIORITY_KERNEL
, THREAD_CALL_OPTIONS_ONCE
);
4937 VERIFY(necp_client_update_tcall
!= NULL
);
4939 lck_rw_init(&necp_fd_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
4940 lck_rw_init(&necp_observer_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
4941 lck_rw_init(&necp_client_tree_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
4942 lck_rw_init(&necp_collect_stats_list_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
4944 LIST_INIT(&necp_fd_list
);
4945 LIST_INIT(&necp_fd_observer_list
);
4946 LIST_INIT(&necp_collect_stats_client_list
);
4948 RB_INIT(&necp_client_global_tree
);
4954 necp_client_reap_caches(boolean_t purge
)
4956 mcache_reap_now(necp_flow_cache
, purge
);