]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/necp_client.c
xnu-3789.70.16.tar.gz
[apple/xnu.git] / bsd / net / necp_client.c
1 /*
2 * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <string.h>
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/queue.h>
33 #include <sys/malloc.h>
34 #include <libkern/OSMalloc.h>
35 #include <sys/kernel.h>
36 #include <net/if.h>
37 #include <sys/domain.h>
38 #include <sys/protosw.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 #include <netinet/ip.h>
42 #include <netinet/ip6.h>
43 #include <netinet/in_pcb.h>
44 #include <net/if_var.h>
45 #include <netinet/tcp_cc.h>
46 #include <net/ntstat.h>
47 #include <sys/kauth.h>
48 #include <sys/sysproto.h>
49 #include <sys/priv.h>
50 #include <net/network_agent.h>
51 #include <net/necp.h>
52 #include <sys/file_internal.h>
53 #include <sys/poll.h>
54 #include <kern/thread_call.h>
55
56 /*
57 * NECP Client Architecture
58 * ------------------------------------------------
59 * See <net/necp.c> for a discussion on NECP database architecture.
60 *
61 * Each client of NECP provides a set of parameters for a connection or network state
62 * evaluation, on which NECP policy evaluation is run. This produces a policy result
63 * which can be accessed by the originating process, along with events for when policies
64 * results have changed.
65 *
66 * ------------------------------------------------
67 * NECP Client FD
68 * ------------------------------------------------
69 * A process opens an NECP file descriptor using necp_open(). This is a very simple
70 * file descriptor, upon which the process may do the following operations:
71 * - necp_client_action(...), to add/remove/query clients
72 * - kqueue, to watch for readable events
73 * - close(), to close the client session and release all clients
74 *
75 * Client objects are allocated structures that hang off of the file descriptor. Each
76 * client contains:
77 * - Client ID, a UUID that references the client across the system
78 * - Parameters, a buffer of TLVs that describe the client's connection parameters,
79 * such as the remote and local endpoints, interface requirements, etc.
80 * - Result, a buffer of TLVs containing the current policy evaluation for the client.
81 * This result will be updated whenever a network change occurs that impacts the
82 * policy result for that client.
83 *
84 * +--------------+
85 * | NECP fd |
86 * +--------------+
87 * ||
88 * ==================================
89 * || || ||
90 * +--------------+ +--------------+ +--------------+
91 * | Client ID | | Client ID | | Client ID |
92 * | ---- | | ---- | | ---- |
93 * | Parameters | | Parameters | | Parameters |
94 * | ---- | | ---- | | ---- |
95 * | Result | | Result | | Result |
96 * +--------------+ +--------------+ +--------------+
97 *
98 * ------------------------------------------------
99 * Client Actions
100 * ------------------------------------------------
101 * - Add. Input parameters as a buffer of TLVs, and output a client ID. Allocates a
102 * new client structure on the file descriptor.
103 * - Remove. Input a client ID. Removes a client structure from the file descriptor.
104 * - Copy Parameters. Input a client ID, and output parameter TLVs.
105 * - Copy Result. Input a client ID, and output result TLVs. Alternatively, input empty
106 * client ID and get next unread client result.
107 * - Copy List. List all client IDs.
108 *
109 * ------------------------------------------------
110 * Client Policy Evaluation
111 * ------------------------------------------------
112 * Policies are evaluated for clients upon client creation, and upon update events,
113 * which are network/agent/policy changes coalesced by a timer.
114 *
115 * The policy evaluation goes through the following steps:
116 * 1. Parse client parameters.
117 * 2. Select a scoped interface if applicable. This involves using require/prohibit
118 * parameters, along with the local address, to select the most appropriate interface
119 * if not explicitly set by the client parameters.
120 * 3. Run NECP application-level policy evalution
121 * 4. Set policy result into client result buffer.
122 *
123 * ------------------------------------------------
124 * Client Observers
125 * ------------------------------------------------
126 * If necp_open() is called with the NECP_OPEN_FLAG_OBSERVER flag, and the process
127 * passes the necessary privilege check, the fd is allowed to use necp_client_action()
128 * to copy client state attached to the file descriptors of other processes, and to
129 * list all client IDs on the system.
130 */
131
132 extern u_int32_t necp_debug;
133
134 static int noop_read(struct fileproc *, struct uio *, int, vfs_context_t);
135 static int noop_write(struct fileproc *, struct uio *, int, vfs_context_t);
136 static int noop_ioctl(struct fileproc *, unsigned long, caddr_t,
137 vfs_context_t);
138 static int necpop_select(struct fileproc *, int, void *, vfs_context_t);
139 static int necpop_close(struct fileglob *, vfs_context_t);
140 static int necpop_kqfilter(struct fileproc *, struct knote *, vfs_context_t);
141
142 // Timer functions
143 static int necp_timeout_microseconds = 1000 * 100; // 100ms
144 static int necp_timeout_leeway_microseconds = 1000 * 500; // 500ms
145 extern int tvtohz(struct timeval *);
146
147 // Parsed parameters
148 #define NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR 0x0001
149 #define NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR 0x0002
150 #define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF 0x0004
151 #define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF 0x0008
152 #define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE 0x0010
153 #define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE 0x0020
154 #define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT 0x0040
155 #define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT 0x0080
156 #define NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT 0x0100
157 #define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE 0x0200
158 #define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE 0x0400
159 #define NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE 0x0800
160
161 #define NECP_MAX_PARSED_PARAMETERS 16
162 struct necp_client_parsed_parameters {
163 u_int32_t valid_fields;
164 union necp_sockaddr_union local_addr;
165 union necp_sockaddr_union remote_addr;
166 u_int32_t required_interface_index;
167 char prohibited_interfaces[IFXNAMSIZ][NECP_MAX_PARSED_PARAMETERS];
168 u_int8_t required_interface_types[NECP_MAX_PARSED_PARAMETERS];
169 u_int8_t prohibited_interface_types[NECP_MAX_PARSED_PARAMETERS];
170 struct necp_client_parameter_netagent_type required_netagent_types[NECP_MAX_PARSED_PARAMETERS];
171 struct necp_client_parameter_netagent_type prohibited_netagent_types[NECP_MAX_PARSED_PARAMETERS];
172 struct necp_client_parameter_netagent_type preferred_netagent_types[NECP_MAX_PARSED_PARAMETERS];
173 uuid_t required_netagents[NECP_MAX_PARSED_PARAMETERS];
174 uuid_t prohibited_netagents[NECP_MAX_PARSED_PARAMETERS];
175 uuid_t preferred_netagents[NECP_MAX_PARSED_PARAMETERS];
176 };
177
178 static bool necp_find_matching_interface_index(struct necp_client_parsed_parameters *parsed_parameters, u_int *return_ifindex);
179
180 static const struct fileops necp_fd_ops = {
181 .fo_type = DTYPE_NETPOLICY,
182 .fo_read = noop_read,
183 .fo_write = noop_write,
184 .fo_ioctl = noop_ioctl,
185 .fo_select = necpop_select,
186 .fo_close = necpop_close,
187 .fo_kqfilter = necpop_kqfilter,
188 .fo_drain = NULL,
189 };
190
191 struct necp_client_assertion {
192 LIST_ENTRY(necp_client_assertion) assertion_chain;
193 uuid_t asserted_netagent;
194 };
195
196 struct necp_client {
197 LIST_ENTRY(necp_client) chain;
198
199 uuid_t client_id;
200 bool result_read;
201 bool assigned_result_read;
202
203 size_t result_length;
204 u_int8_t result[NECP_MAX_CLIENT_RESULT_SIZE];
205
206 uuid_t nexus_agent;
207 size_t assigned_results_length;
208 u_int8_t *assigned_results;
209
210 LIST_HEAD(_necp_client_assertion_list, necp_client_assertion) assertion_list;
211
212 user_addr_t stats_uaddr;
213 user_size_t stats_ulen;
214 nstat_userland_context stats_handler_context;
215 necp_stats_hdr *stats_area;
216
217 size_t parameters_length;
218 u_int8_t parameters[0];
219 };
220
221 struct necp_fd_data {
222 LIST_ENTRY(necp_fd_data) chain;
223 LIST_HEAD(_clients, necp_client) clients;
224 int flags;
225 int proc_pid;
226 decl_lck_mtx_data(, fd_lock);
227 struct selinfo si;
228 };
229
230 static LIST_HEAD(_necp_fd_list, necp_fd_data) necp_fd_list;
231
232 static lck_grp_attr_t *necp_fd_grp_attr = NULL;
233 static lck_attr_t *necp_fd_mtx_attr = NULL;
234 static lck_grp_t *necp_fd_mtx_grp = NULL;
235 decl_lck_rw_data(static, necp_fd_lock);
236
237 static thread_call_t necp_client_tcall;
238
239 /// NECP file descriptor functions
240
241 static int
242 noop_read(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
243 {
244 #pragma unused(fp, uio, flags, ctx)
245 return (ENXIO);
246 }
247
248 static int
249 noop_write(struct fileproc *fp, struct uio *uio, int flags,
250 vfs_context_t ctx)
251 {
252 #pragma unused(fp, uio, flags, ctx)
253 return (ENXIO);
254 }
255
256 static int
257 noop_ioctl(struct fileproc *fp, unsigned long com, caddr_t data,
258 vfs_context_t ctx)
259 {
260 #pragma unused(fp, com, data, ctx)
261 return (ENOTTY);
262 }
263
264 static void
265 necp_fd_notify(struct necp_fd_data *fd_data, bool locked)
266 {
267 struct selinfo *si = &fd_data->si;
268
269 if (!locked) {
270 lck_mtx_lock(&fd_data->fd_lock);
271 }
272
273 selwakeup(si);
274
275 // use a non-zero hint to tell the notification from the
276 // call done in kqueue_scan() which uses 0
277 KNOTE(&si->si_note, 1); // notification
278
279 if (!locked) {
280 lck_mtx_unlock(&fd_data->fd_lock);
281 }
282 }
283
284 static int
285 necp_fd_poll(struct necp_fd_data *fd_data, int events, void *wql, struct proc *p, int is_kevent)
286 {
287 #pragma unused(wql, p, is_kevent)
288 u_int revents = 0;
289 struct necp_client *client = NULL;
290 bool has_unread_clients = FALSE;
291
292 u_int want_rx = events & (POLLIN | POLLRDNORM);
293 if (want_rx) {
294
295 LIST_FOREACH(client, &fd_data->clients, chain) {
296 if (!client->result_read || !client->assigned_result_read) {
297 has_unread_clients = TRUE;
298 break;
299 }
300 }
301
302 if (has_unread_clients) {
303 revents |= want_rx;
304 }
305 }
306
307 return (revents);
308 }
309
310 static int
311 necpop_select(struct fileproc *fp, int which, void *wql, vfs_context_t ctx)
312 {
313 #pragma unused(fp, which, wql, ctx)
314 return (0);
315 struct necp_fd_data *fd_data = NULL;
316 int revents = 0;
317 int events = 0;
318 proc_t procp;
319
320 fd_data = (struct necp_fd_data *)fp->f_fglob->fg_data;
321 if (fd_data == NULL) {
322 return (0);
323 }
324
325 procp = vfs_context_proc(ctx);
326
327 switch (which) {
328 case FREAD: {
329 events = POLLIN;
330 break;
331 }
332
333 default: {
334 return (1);
335 }
336 }
337
338 lck_mtx_lock(&fd_data->fd_lock);
339 revents = necp_fd_poll(fd_data, events, wql, procp, 0);
340 lck_mtx_unlock(&fd_data->fd_lock);
341
342 return ((events & revents) ? 1 : 0);
343 }
344
345 static void
346 necp_fd_knrdetach(struct knote *kn)
347 {
348 struct necp_fd_data *fd_data = (struct necp_fd_data *)kn->kn_hook;
349 struct selinfo *si = &fd_data->si;
350
351 lck_mtx_lock(&fd_data->fd_lock);
352 KNOTE_DETACH(&si->si_note, kn);
353 lck_mtx_unlock(&fd_data->fd_lock);
354 }
355
356 static int
357 necp_fd_knread(struct knote *kn, long hint)
358 {
359 #pragma unused(kn, hint)
360 return 1; /* assume we are ready */
361 }
362
363 static int
364 necp_fd_knrprocess(struct knote *kn, struct filt_process_s *data, struct kevent_internal_s *kev)
365 {
366 #pragma unused(data)
367 struct necp_fd_data *fd_data;
368 int revents;
369 int res;
370
371 fd_data = (struct necp_fd_data *)kn->kn_hook;
372
373 lck_mtx_lock(&fd_data->fd_lock);
374 revents = necp_fd_poll(fd_data, POLLIN, NULL, current_proc(), 1);
375 res = ((revents & POLLIN) != 0);
376 if (res) {
377 *kev = kn->kn_kevent;
378 }
379 lck_mtx_unlock(&fd_data->fd_lock);
380 return (res);
381 }
382
383 static int
384 necp_fd_knrtouch(struct knote *kn, struct kevent_internal_s *kev)
385 {
386 #pragma unused(kev)
387 struct necp_fd_data *fd_data;
388 int revents;
389
390 fd_data = (struct necp_fd_data *)kn->kn_hook;
391
392 lck_mtx_lock(&fd_data->fd_lock);
393 if ((kn->kn_status & KN_UDATA_SPECIFIC) == 0)
394 kn->kn_udata = kev->udata;
395 revents = necp_fd_poll(fd_data, POLLIN, NULL, current_proc(), 1);
396 lck_mtx_unlock(&fd_data->fd_lock);
397
398 return ((revents & POLLIN) != 0);
399 }
400
401 struct filterops necp_fd_rfiltops = {
402 .f_isfd = 1,
403 .f_detach = necp_fd_knrdetach,
404 .f_event = necp_fd_knread,
405 .f_touch = necp_fd_knrtouch,
406 .f_process = necp_fd_knrprocess,
407 };
408
409 static int
410 necpop_kqfilter(struct fileproc *fp, struct knote *kn, vfs_context_t ctx)
411 {
412 #pragma unused(fp, ctx)
413 struct necp_fd_data *fd_data = NULL;
414 int revents;
415
416 if (kn->kn_filter != EVFILT_READ) {
417 NECPLOG(LOG_ERR, "bad filter request %d", kn->kn_filter);
418 kn->kn_flags = EV_ERROR;
419 kn->kn_data = EINVAL;
420 return (0);
421 }
422
423 fd_data = (struct necp_fd_data *)kn->kn_fp->f_fglob->fg_data;
424 if (fd_data == NULL) {
425 NECPLOG0(LOG_ERR, "No channel for kqfilter");
426 kn->kn_flags = EV_ERROR;
427 kn->kn_data = ENOENT;
428 return (0);
429 }
430
431 lck_mtx_lock(&fd_data->fd_lock);
432 kn->kn_filtid = EVFILTID_NECP_FD;
433 kn->kn_hook = fd_data;
434 KNOTE_ATTACH(&fd_data->si.si_note, kn);
435
436 revents = necp_fd_poll(fd_data, POLLIN, NULL, current_proc(), 1);
437
438 lck_mtx_unlock(&fd_data->fd_lock);
439
440 return ((revents & POLLIN) != 0);
441 }
442
443 static void
444 necp_destroy_client_stats(struct necp_client *client)
445 {
446 if ((client->stats_area != NULL) &&
447 (client->stats_handler_context != NULL) &&
448 (client->stats_uaddr != 0)) {
449 // Close old stats if required.
450 int error = copyin(client->stats_uaddr, client->stats_area, client->stats_ulen);
451 if (error) {
452 NECPLOG(LOG_ERR, "necp_destroy_client_stats copyin error on close (%d)", error);
453 // Not much we can for an error on an obsolete address
454 }
455 ntstat_userland_stats_close(client->stats_handler_context);
456 FREE(client->stats_area, M_NECP);
457 client->stats_area = NULL;
458 client->stats_handler_context = NULL;
459 client->stats_uaddr = 0;
460 client->stats_ulen = 0;
461 }
462 }
463
464 static void
465 necp_destroy_client(struct necp_client *client)
466 {
467 // Remove from list
468 LIST_REMOVE(client, chain);
469
470 // Remove nexus assignment
471 if (client->assigned_results != NULL) {
472 if (!uuid_is_null(client->nexus_agent)) {
473 int netagent_error = netagent_client_message(client->nexus_agent, client->client_id,
474 NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS);
475 if (netagent_error != 0) {
476 NECPLOG(LOG_ERR, "necp_client_remove close nexus error (%d)", netagent_error);
477 }
478 }
479 FREE(client->assigned_results, M_NETAGENT);
480 }
481
482 // Remove agent assertions
483 struct necp_client_assertion *search_assertion = NULL;
484 struct necp_client_assertion *temp_assertion = NULL;
485 LIST_FOREACH_SAFE(search_assertion, &client->assertion_list, assertion_chain, temp_assertion) {
486 int netagent_error = netagent_client_message(search_assertion->asserted_netagent, client->client_id, NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT);
487 if (netagent_error != 0) {
488 NECPLOG(LOG_ERR, "necp_client_remove unassert agent error (%d)", netagent_error);
489 }
490 LIST_REMOVE(search_assertion, assertion_chain);
491 FREE(search_assertion, M_NECP);
492 }
493 necp_destroy_client_stats(client);
494
495 FREE(client, M_NECP);
496 }
497
498 static int
499 necpop_close(struct fileglob *fg, vfs_context_t ctx)
500 {
501 #pragma unused(fg, ctx)
502 struct necp_fd_data *fd_data = NULL;
503 int error = 0;
504
505 fd_data = (struct necp_fd_data *)fg->fg_data;
506 fg->fg_data = NULL;
507
508 if (fd_data != NULL) {
509 lck_rw_lock_exclusive(&necp_fd_lock);
510
511 lck_mtx_lock(&fd_data->fd_lock);
512 struct necp_client *client = NULL;
513 struct necp_client *temp_client = NULL;
514 LIST_FOREACH_SAFE(client, &fd_data->clients, chain, temp_client) {
515 necp_destroy_client(client);
516 }
517 lck_mtx_unlock(&fd_data->fd_lock);
518
519 selthreadclear(&fd_data->si);
520
521 lck_mtx_destroy(&fd_data->fd_lock, necp_fd_mtx_grp);
522
523 LIST_REMOVE(fd_data, chain);
524
525 lck_rw_done(&necp_fd_lock);
526
527 FREE(fd_data, M_NECP);
528 fd_data = NULL;
529 }
530
531 return (error);
532 }
533
534 /// NECP client utilities
535
536 static int
537 necp_find_fd_data(int fd, struct necp_fd_data **fd_data)
538 {
539 proc_t p = current_proc();
540 struct fileproc *fp = NULL;
541 int error = 0;
542
543 proc_fdlock_spin(p);
544 if ((error = fp_lookup(p, fd, &fp, 1)) != 0) {
545 goto done;
546 }
547 if (fp->f_fglob->fg_ops->fo_type != DTYPE_NETPOLICY) {
548 fp_drop(p, fd, fp, 1);
549 error = ENODEV;
550 goto done;
551 }
552 *fd_data = (struct necp_fd_data *)fp->f_fglob->fg_data;
553
554 done:
555 proc_fdunlock(p);
556 return (error);
557 }
558
559 static bool
560 necp_netagent_applies_to_client(__unused struct necp_client *client, struct necp_client_parsed_parameters *parameters, uuid_t netagent_uuid)
561 {
562 bool applies = FALSE;
563 u_int32_t flags = netagent_get_flags(netagent_uuid);
564 if (!(flags & NETAGENT_FLAG_REGISTERED)) {
565 // Unregistered agents never apply
566 return (applies);
567 }
568
569 if (flags & NETAGENT_FLAG_SPECIFIC_USE_ONLY) {
570 // Specific use agents only apply when required
571 bool required = FALSE;
572 if (parameters != NULL) {
573 // Check required agent UUIDs
574 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
575 if (uuid_is_null(parameters->required_netagents[i])) {
576 break;
577 }
578 if (uuid_compare(parameters->required_netagents[i], netagent_uuid) == 0) {
579 required = TRUE;
580 break;
581 }
582 }
583
584 if (!required) {
585 // Check required agent types
586 bool fetched_type = FALSE;
587 char netagent_domain[NETAGENT_DOMAINSIZE];
588 char netagent_type[NETAGENT_TYPESIZE];
589 memset(&netagent_domain, 0, NETAGENT_DOMAINSIZE);
590 memset(&netagent_type, 0, NETAGENT_TYPESIZE);
591
592 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
593 if (strlen(parameters->required_netagent_types[i].netagent_domain) == 0 ||
594 strlen(parameters->required_netagent_types[i].netagent_type) == 0) {
595 break;
596 }
597
598 if (!fetched_type) {
599 if (netagent_get_agent_domain_and_type(netagent_uuid, netagent_domain, netagent_type)) {
600 fetched_type = TRUE;
601 } else {
602 break;
603 }
604 }
605
606 if ((strlen(parameters->required_netagent_types[i].netagent_domain) == 0 ||
607 strncmp(netagent_domain, parameters->required_netagent_types[i].netagent_domain, NETAGENT_DOMAINSIZE) == 0) &&
608 (strlen(parameters->required_netagent_types[i].netagent_type) == 0 ||
609 strncmp(netagent_type, parameters->required_netagent_types[i].netagent_type, NETAGENT_TYPESIZE) == 0)) {
610 required = TRUE;
611 break;
612 }
613 }
614 }
615 }
616
617 applies = required;
618 } else {
619 applies = TRUE;
620 }
621
622 if (applies &&
623 (flags & NETAGENT_FLAG_NEXUS_PROVIDER) &&
624 uuid_is_null(client->nexus_agent)) {
625 uuid_copy(client->nexus_agent, netagent_uuid);
626 }
627
628 return (applies);
629 }
630
631 static int
632 necp_client_parse_parameters(u_int8_t *parameters,
633 u_int32_t parameters_size,
634 struct necp_client_parsed_parameters *parsed_parameters)
635 {
636 int error = 0;
637 size_t offset = 0;
638
639 u_int32_t num_prohibited_interfaces = 0;
640 u_int32_t num_required_interface_types = 0;
641 u_int32_t num_prohibited_interface_types = 0;
642 u_int32_t num_required_agents = 0;
643 u_int32_t num_prohibited_agents = 0;
644 u_int32_t num_preferred_agents = 0;
645 u_int32_t num_required_agent_types = 0;
646 u_int32_t num_prohibited_agent_types = 0;
647 u_int32_t num_preferred_agent_types = 0;
648
649 if (parsed_parameters == NULL) {
650 return (EINVAL);
651 }
652
653 memset(parsed_parameters, 0, sizeof(struct necp_client_parsed_parameters));
654
655 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
656 u_int8_t type = necp_buffer_get_tlv_type(parameters, offset);
657 u_int32_t length = necp_buffer_get_tlv_length(parameters, offset);
658
659 if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
660 // If the length is larger than what can fit in the remaining parameters size, bail
661 NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
662 break;
663 }
664
665 if (length > 0) {
666 u_int8_t *value = necp_buffer_get_tlv_value(parameters, offset, NULL);
667 if (value != NULL) {
668 switch (type) {
669 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
670 if (length <= IFXNAMSIZ && length > 0) {
671 ifnet_t bound_interface = NULL;
672 char interface_name[IFXNAMSIZ];
673 memcpy(interface_name, value, length);
674 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
675 if (ifnet_find_by_name(interface_name, &bound_interface) == 0) {
676 parsed_parameters->required_interface_index = bound_interface->if_index;
677 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF;
678 ifnet_release(bound_interface);
679 }
680 }
681 break;
682 }
683 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
684 if (length >= sizeof(struct necp_policy_condition_addr)) {
685 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
686 if ((address_struct->address.sa.sa_family == AF_INET ||
687 address_struct->address.sa.sa_family == AF_INET6) &&
688 address_struct->address.sa.sa_len <= length) {
689 memcpy(&parsed_parameters->local_addr, &address_struct->address, sizeof(address_struct->address));
690 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR;
691 }
692 }
693 break;
694 }
695 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
696 if (length >= sizeof(struct necp_client_endpoint)) {
697 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
698 if ((endpoint->u.endpoint.endpoint_family == AF_INET ||
699 endpoint->u.endpoint.endpoint_family == AF_INET6) &&
700 endpoint->u.endpoint.endpoint_length <= length) {
701 memcpy(&parsed_parameters->local_addr, &endpoint->u.sa, sizeof(union necp_sockaddr_union));
702 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR;
703 }
704 }
705 break;
706 }
707 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
708 if (length >= sizeof(struct necp_policy_condition_addr)) {
709 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
710 if ((address_struct->address.sa.sa_family == AF_INET ||
711 address_struct->address.sa.sa_family == AF_INET6) &&
712 address_struct->address.sa.sa_len <= length) {
713 memcpy(&parsed_parameters->remote_addr, &address_struct->address, sizeof(address_struct->address));
714 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR;
715 }
716 }
717 break;
718 }
719 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
720 if (length >= sizeof(struct necp_client_endpoint)) {
721 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
722 if ((endpoint->u.endpoint.endpoint_family == AF_INET ||
723 endpoint->u.endpoint.endpoint_family == AF_INET6) &&
724 endpoint->u.endpoint.endpoint_length <= length) {
725 memcpy(&parsed_parameters->remote_addr, &endpoint->u.sa, sizeof(union necp_sockaddr_union));
726 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR;
727 }
728 }
729 break;
730 }
731 case NECP_CLIENT_PARAMETER_PROHIBIT_INTERFACE: {
732 if (num_prohibited_interfaces >= NECP_MAX_PARSED_PARAMETERS) {
733 break;
734 }
735 if (length <= IFXNAMSIZ && length > 0) {
736 memcpy(parsed_parameters->prohibited_interfaces[num_prohibited_interfaces], value, length);
737 parsed_parameters->prohibited_interfaces[num_prohibited_interfaces][length - 1] = 0; // Make sure the string is NULL terminated
738 num_prohibited_interfaces++;
739 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF;
740 }
741 break;
742 }
743 case NECP_CLIENT_PARAMETER_REQUIRE_IF_TYPE: {
744 if (num_required_interface_types >= NECP_MAX_PARSED_PARAMETERS) {
745 break;
746 }
747 if (length >= sizeof(u_int8_t)) {
748 memcpy(&parsed_parameters->required_interface_types[num_required_interface_types], value, sizeof(u_int8_t));
749 num_required_interface_types++;
750 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE;
751 }
752 break;
753 }
754 case NECP_CLIENT_PARAMETER_PROHIBIT_IF_TYPE: {
755 if (num_prohibited_interface_types >= NECP_MAX_PARSED_PARAMETERS) {
756 break;
757 }
758 if (length >= sizeof(u_int8_t)) {
759 memcpy(&parsed_parameters->prohibited_interface_types[num_prohibited_interface_types], value, sizeof(u_int8_t));
760 num_prohibited_interface_types++;
761 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE;
762 }
763 break;
764 }
765 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT: {
766 if (num_required_agents >= NECP_MAX_PARSED_PARAMETERS) {
767 break;
768 }
769 if (length >= sizeof(uuid_t)) {
770 memcpy(&parsed_parameters->required_netagents[num_required_agents], value, sizeof(uuid_t));
771 num_required_agents++;
772 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT;
773 }
774 break;
775 }
776 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT: {
777 if (num_prohibited_agents >= NECP_MAX_PARSED_PARAMETERS) {
778 break;
779 }
780 if (length >= sizeof(uuid_t)) {
781 memcpy(&parsed_parameters->prohibited_netagents[num_prohibited_agents], value, sizeof(uuid_t));
782 num_prohibited_agents++;
783 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT;
784 }
785 break;
786 }
787 case NECP_CLIENT_PARAMETER_PREFER_AGENT: {
788 if (num_preferred_agents >= NECP_MAX_PARSED_PARAMETERS) {
789 break;
790 }
791 if (length >= sizeof(uuid_t)) {
792 memcpy(&parsed_parameters->preferred_netagents[num_preferred_agents], value, sizeof(uuid_t));
793 num_preferred_agents++;
794 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT;
795 }
796 break;
797 }
798 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE: {
799 if (num_required_agent_types >= NECP_MAX_PARSED_PARAMETERS) {
800 break;
801 }
802 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
803 memcpy(&parsed_parameters->required_netagent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
804 num_required_agent_types++;
805 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE;
806 }
807 break;
808 }
809 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT_TYPE: {
810 if (num_prohibited_agent_types >= NECP_MAX_PARSED_PARAMETERS) {
811 break;
812 }
813 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
814 memcpy(&parsed_parameters->prohibited_netagent_types[num_prohibited_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
815 num_prohibited_agent_types++;
816 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE;
817 }
818 break;
819 }
820 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
821 if (num_preferred_agent_types >= NECP_MAX_PARSED_PARAMETERS) {
822 break;
823 }
824 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
825 memcpy(&parsed_parameters->preferred_netagent_types[num_preferred_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
826 num_preferred_agent_types++;
827 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE;
828 }
829 break;
830 }
831 default: {
832 break;
833 }
834 }
835 }
836 }
837
838 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
839 }
840
841 return (error);
842 }
843
844 int
845 necp_assign_client_result(uuid_t netagent_uuid, uuid_t client_id,
846 u_int8_t *assigned_results, size_t assigned_results_length)
847 {
848 int error = 0;
849 struct necp_fd_data *client_fd = NULL;
850 bool found_client = FALSE;
851 bool client_updated = FALSE;
852
853 lck_rw_lock_shared(&necp_fd_lock);
854
855 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
856 struct necp_client *client = NULL;
857 lck_mtx_lock(&client_fd->fd_lock);
858 LIST_FOREACH(client, &client_fd->clients, chain) {
859 if (uuid_compare(client->client_id, client_id) == 0) {
860 // Found the right client!
861 found_client = TRUE;
862
863 if (uuid_compare(client->nexus_agent, netagent_uuid) == 0) {
864 // Verify that the client nexus agent matches
865 if (client->assigned_results != NULL) {
866 // Release prior result
867 FREE(client->assigned_results, M_NETAGENT);
868 }
869 client->assigned_results = assigned_results;
870 client->assigned_results_length = assigned_results_length;
871 client->assigned_result_read = FALSE;
872 client_updated = TRUE;
873 }
874 }
875 }
876 if (client_updated) {
877 necp_fd_notify(client_fd, true);
878 }
879 lck_mtx_unlock(&client_fd->fd_lock);
880
881 if (found_client) {
882 break;
883 }
884 }
885
886 lck_rw_done(&necp_fd_lock);
887
888 if (!found_client) {
889 error = ENOENT;
890 } else if (!client_updated) {
891 error = EINVAL;
892 }
893
894 return (error);
895 }
896
897 /// Client updating
898
899 static bool
900 necp_update_client_result(proc_t proc,
901 struct necp_client *client)
902 {
903 struct necp_client_result_netagent netagent;
904 struct necp_aggregate_result result;
905 struct necp_client_parsed_parameters parsed_parameters;
906 u_int32_t flags = 0;
907
908 uuid_clear(client->nexus_agent);
909
910 int error = necp_client_parse_parameters(client->parameters, (u_int32_t)client->parameters_length, &parsed_parameters);
911 if (error != 0) {
912 return (FALSE);
913 }
914
915 // Check parameters to find best interface
916 u_int matching_if_index = 0;
917 if (necp_find_matching_interface_index(&parsed_parameters, &matching_if_index)) {
918 if (matching_if_index != 0) {
919 parsed_parameters.required_interface_index = matching_if_index;
920 }
921 // Interface found or not needed, match policy.
922 error = necp_application_find_policy_match_internal(proc, client->parameters, (u_int32_t)client->parameters_length, &result, &flags, matching_if_index);
923 if (error != 0) {
924 return (FALSE);
925 }
926 } else {
927 // Interface not found. Clear out the whole result, make everything fail.
928 memset(&result, 0, sizeof(result));
929 }
930
931 // If the original request was scoped, and the policy result matches, make sure the result is scoped
932 if ((result.routing_result == NECP_KERNEL_POLICY_RESULT_NONE ||
933 result.routing_result == NECP_KERNEL_POLICY_RESULT_PASS) &&
934 result.routed_interface_index != IFSCOPE_NONE &&
935 parsed_parameters.required_interface_index == result.routed_interface_index) {
936 result.routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
937 result.routing_result_parameter.scoped_interface_index = result.routed_interface_index;
938 }
939
940 bool updated = FALSE;
941 u_int8_t *cursor = client->result;
942 const u_int8_t *max = client->result + NECP_MAX_CLIENT_RESULT_SIZE;
943 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_CLIENT_ID, sizeof(uuid_t), client->client_id, &updated);
944 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_POLICY_RESULT, sizeof(result.routing_result), &result.routing_result, &updated);
945 if (result.routing_result_parameter.tunnel_interface_index != 0) {
946 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_POLICY_RESULT_PARAMETER,
947 sizeof(result.routing_result_parameter), &result.routing_result_parameter, &updated);
948 }
949 if (result.filter_control_unit != 0) {
950 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_FILTER_CONTROL_UNIT,
951 sizeof(result.filter_control_unit), &result.filter_control_unit, &updated);
952 }
953 if (result.routed_interface_index != 0) {
954 u_int routed_interface_index = result.routed_interface_index;
955 if (result.routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
956 parsed_parameters.required_interface_index != IFSCOPE_NONE &&
957 parsed_parameters.required_interface_index != result.routed_interface_index) {
958 routed_interface_index = parsed_parameters.required_interface_index;
959 }
960
961 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_INTERFACE_INDEX,
962 sizeof(routed_interface_index), &routed_interface_index, &updated);
963 }
964 if (flags != 0) {
965 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_FLAGS,
966 sizeof(flags), &flags, &updated);
967 }
968 for (int i = 0; i < NECP_MAX_NETAGENTS; i++) {
969 if (uuid_is_null(result.netagents[i])) {
970 break;
971 }
972 uuid_copy(netagent.netagent_uuid, result.netagents[i]);
973 netagent.generation = netagent_get_generation(netagent.netagent_uuid);
974 if (necp_netagent_applies_to_client(client, &parsed_parameters, netagent.netagent_uuid)) {
975 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_NETAGENT, sizeof(netagent), &netagent, &updated);
976 }
977 }
978
979 ifnet_head_lock_shared();
980 ifnet_t direct_interface = NULL;
981 ifnet_t delegate_interface = NULL;
982 ifnet_t original_scoped_interface = NULL;
983
984 if (result.routed_interface_index != IFSCOPE_NONE && result.routed_interface_index <= (u_int32_t)if_index) {
985 direct_interface = ifindex2ifnet[result.routed_interface_index];
986 } else if (parsed_parameters.required_interface_index != IFSCOPE_NONE &&
987 parsed_parameters.required_interface_index <= (u_int32_t)if_index) {
988 // If the request was scoped, but the route didn't match, still grab the agents
989 direct_interface = ifindex2ifnet[parsed_parameters.required_interface_index];
990 } else if (result.routed_interface_index == IFSCOPE_NONE &&
991 result.routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED &&
992 result.routing_result_parameter.scoped_interface_index != IFSCOPE_NONE) {
993 direct_interface = ifindex2ifnet[result.routing_result_parameter.scoped_interface_index];
994 }
995 if (direct_interface != NULL) {
996 delegate_interface = direct_interface->if_delegated.ifp;
997 }
998 if (result.routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
999 parsed_parameters.required_interface_index != IFSCOPE_NONE &&
1000 parsed_parameters.required_interface_index != result.routing_result_parameter.tunnel_interface_index &&
1001 parsed_parameters.required_interface_index <= (u_int32_t)if_index) {
1002 original_scoped_interface = ifindex2ifnet[parsed_parameters.required_interface_index];
1003 }
1004 // Add interfaces
1005 if (original_scoped_interface != NULL) {
1006 struct necp_client_result_interface interface_struct;
1007 interface_struct.index = original_scoped_interface->if_index;
1008 interface_struct.generation = ifnet_get_generation(original_scoped_interface);
1009 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_INTERFACE, sizeof(interface_struct), &interface_struct, &updated);
1010 }
1011 if (direct_interface != NULL) {
1012 struct necp_client_result_interface interface_struct;
1013 interface_struct.index = direct_interface->if_index;
1014 interface_struct.generation = ifnet_get_generation(direct_interface);
1015 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_INTERFACE, sizeof(interface_struct), &interface_struct, &updated);
1016 }
1017 if (delegate_interface != NULL) {
1018 struct necp_client_result_interface interface_struct;
1019 interface_struct.index = delegate_interface->if_index;
1020 interface_struct.generation = ifnet_get_generation(delegate_interface);
1021 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_INTERFACE, sizeof(interface_struct), &interface_struct, &updated);
1022 }
1023 // Add agents
1024 if (original_scoped_interface != NULL) {
1025 ifnet_lock_shared(original_scoped_interface);
1026 if (original_scoped_interface->if_agentids != NULL) {
1027 for (u_int32_t i = 0; i < original_scoped_interface->if_agentcount; i++) {
1028 if (uuid_is_null(original_scoped_interface->if_agentids[i])) {
1029 continue;
1030 }
1031 uuid_copy(netagent.netagent_uuid, original_scoped_interface->if_agentids[i]);
1032 netagent.generation = netagent_get_generation(netagent.netagent_uuid);
1033 if (necp_netagent_applies_to_client(client, &parsed_parameters, netagent.netagent_uuid)) {
1034 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_NETAGENT, sizeof(netagent), &netagent, &updated);
1035 }
1036 }
1037 }
1038 ifnet_lock_done(original_scoped_interface);
1039 }
1040 if (direct_interface != NULL) {
1041 ifnet_lock_shared(direct_interface);
1042 if (direct_interface->if_agentids != NULL) {
1043 for (u_int32_t i = 0; i < direct_interface->if_agentcount; i++) {
1044 if (uuid_is_null(direct_interface->if_agentids[i])) {
1045 continue;
1046 }
1047 uuid_copy(netagent.netagent_uuid, direct_interface->if_agentids[i]);
1048 netagent.generation = netagent_get_generation(netagent.netagent_uuid);
1049 if (necp_netagent_applies_to_client(client, &parsed_parameters, netagent.netagent_uuid)) {
1050 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_NETAGENT, sizeof(netagent), &netagent, &updated);
1051 }
1052 }
1053 }
1054 ifnet_lock_done(direct_interface);
1055 }
1056 if (delegate_interface != NULL) {
1057 ifnet_lock_shared(delegate_interface);
1058 if (delegate_interface->if_agentids != NULL) {
1059 for (u_int32_t i = 0; i < delegate_interface->if_agentcount; i++) {
1060 if (uuid_is_null(delegate_interface->if_agentids[i])) {
1061 continue;
1062 }
1063 uuid_copy(netagent.netagent_uuid, delegate_interface->if_agentids[i]);
1064 netagent.generation = netagent_get_generation(netagent.netagent_uuid);
1065 if (necp_netagent_applies_to_client(client, &parsed_parameters, netagent.netagent_uuid)) {
1066 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_NETAGENT, sizeof(netagent), &netagent, &updated);
1067 }
1068 }
1069 }
1070 ifnet_lock_done(delegate_interface);
1071 }
1072 ifnet_head_done();
1073
1074 size_t new_result_length = (cursor - client->result);
1075 if (new_result_length != client->result_length) {
1076 client->result_length = new_result_length;
1077 updated = TRUE;
1078 }
1079 if (updated) {
1080 client->result_read = FALSE;
1081 }
1082
1083 return (updated);
1084 }
1085
1086 static void
1087 necp_update_all_clients_callout(__unused thread_call_param_t dummy,
1088 __unused thread_call_param_t arg)
1089 {
1090 #pragma unused(arg)
1091 struct necp_fd_data *client_fd = NULL;
1092
1093 lck_rw_lock_shared(&necp_fd_lock);
1094
1095 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
1096 bool updated_result = FALSE;
1097 struct necp_client *client = NULL;
1098 proc_t proc = proc_find(client_fd->proc_pid);
1099 if (proc == NULL) {
1100 continue;
1101 }
1102
1103 lck_mtx_lock(&client_fd->fd_lock);
1104 LIST_FOREACH(client, &client_fd->clients, chain) {
1105 if (necp_update_client_result(proc, client)) {
1106 updated_result = TRUE;
1107 }
1108 }
1109 if (updated_result) {
1110 necp_fd_notify(client_fd, true);
1111 }
1112 lck_mtx_unlock(&client_fd->fd_lock);
1113
1114 proc_rele(proc);
1115 }
1116
1117 lck_rw_done(&necp_fd_lock);
1118 }
1119
1120 void
1121 necp_update_all_clients(void)
1122 {
1123 if (necp_client_tcall == NULL) {
1124 // Don't try to update clients if the module is not initialized
1125 return;
1126 }
1127
1128 uint64_t deadline = 0;
1129 uint64_t leeway = 0;
1130 clock_interval_to_deadline(necp_timeout_microseconds, NSEC_PER_USEC, &deadline);
1131 clock_interval_to_absolutetime_interval(necp_timeout_leeway_microseconds, NSEC_PER_USEC, &leeway);
1132
1133 thread_call_enter_delayed_with_leeway(necp_client_tcall, NULL,
1134 deadline, leeway, THREAD_CALL_DELAY_LEEWAY);
1135 }
1136
1137 static void
1138 necp_client_remove_agent_from_result(struct necp_client *client, uuid_t netagent_uuid)
1139 {
1140 size_t offset = 0;
1141
1142 u_int8_t *result_buffer = client->result;
1143 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= client->result_length) {
1144 u_int8_t type = necp_buffer_get_tlv_type(result_buffer, offset);
1145 u_int32_t length = necp_buffer_get_tlv_length(result_buffer, offset);
1146
1147 size_t tlv_total_length = (sizeof(u_int8_t) + sizeof(u_int32_t) + length);
1148 if (type == NECP_CLIENT_RESULT_NETAGENT &&
1149 length == sizeof(struct necp_client_result_netagent) &&
1150 (offset + tlv_total_length) <= client->result_length) {
1151 struct necp_client_result_netagent *value = ((struct necp_client_result_netagent *)(void *)
1152 necp_buffer_get_tlv_value(result_buffer, offset, NULL));
1153 if (uuid_compare(value->netagent_uuid, netagent_uuid) == 0) {
1154 // Found a netagent to remove
1155 // Shift bytes down to remove the tlv, and adjust total length
1156 // Don't adjust the current offset
1157 memmove(result_buffer + offset,
1158 result_buffer + offset + tlv_total_length,
1159 client->result_length - (offset + tlv_total_length));
1160 client->result_length -= tlv_total_length;
1161 memset(result_buffer + client->result_length, 0, NECP_MAX_CLIENT_RESULT_SIZE - client->result_length);
1162 continue;
1163 }
1164 }
1165
1166 offset += tlv_total_length;
1167 }
1168 }
1169
1170 void
1171 necp_force_update_client(uuid_t client_id, uuid_t remove_netagent_uuid)
1172 {
1173 struct necp_fd_data *client_fd = NULL;
1174
1175 lck_rw_lock_shared(&necp_fd_lock);
1176
1177 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
1178 bool updated_result = FALSE;
1179 struct necp_client *client = NULL;
1180 lck_mtx_lock(&client_fd->fd_lock);
1181 LIST_FOREACH(client, &client_fd->clients, chain) {
1182 if (uuid_compare(client->client_id, client_id) == 0) {
1183 if (!uuid_is_null(remove_netagent_uuid)) {
1184 necp_client_remove_agent_from_result(client, remove_netagent_uuid);
1185 }
1186 client->assigned_result_read = FALSE;
1187 updated_result = TRUE;
1188 // Found the client, break
1189 break;
1190 }
1191 }
1192 if (updated_result) {
1193 necp_fd_notify(client_fd, true);
1194 }
1195 lck_mtx_unlock(&client_fd->fd_lock);
1196 if (updated_result) {
1197 // Found the client, break
1198 break;
1199 }
1200 }
1201
1202 lck_rw_done(&necp_fd_lock);
1203 }
1204
1205 /// Interface matching
1206
1207 #define NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
1208 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF | \
1209 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
1210 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE | \
1211 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
1212 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT | \
1213 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
1214 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
1215 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE | \
1216 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
1217
1218 #define NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
1219 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
1220 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
1221 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
1222 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
1223 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
1224
1225 #define NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
1226 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
1227
1228 static bool
1229 necp_ifnet_matches_type(struct ifnet *ifp, u_int8_t interface_type, bool check_delegates)
1230 {
1231 struct ifnet *check_ifp = ifp;
1232 while (check_ifp) {
1233 if (if_functional_type(check_ifp, TRUE) == interface_type) {
1234 return (TRUE);
1235 }
1236 if (!check_delegates) {
1237 break;
1238 }
1239 check_ifp = check_ifp->if_delegated.ifp;
1240
1241 }
1242 return (FALSE);
1243 }
1244
1245 static bool
1246 necp_ifnet_matches_name(struct ifnet *ifp, const char *interface_name, bool check_delegates)
1247 {
1248 struct ifnet *check_ifp = ifp;
1249 while (check_ifp) {
1250 if (strncmp(check_ifp->if_xname, interface_name, IFXNAMSIZ) == 0) {
1251 return (TRUE);
1252 }
1253 if (!check_delegates) {
1254 break;
1255 }
1256 check_ifp = check_ifp->if_delegated.ifp;
1257 }
1258 return (FALSE);
1259 }
1260
1261 static bool
1262 necp_ifnet_matches_agent(struct ifnet *ifp, uuid_t *agent_uuid, bool check_delegates)
1263 {
1264 struct ifnet *check_ifp = ifp;
1265
1266 while (check_ifp != NULL) {
1267 ifnet_lock_shared(check_ifp);
1268 if (check_ifp->if_agentids != NULL) {
1269 for (u_int32_t index = 0; index < check_ifp->if_agentcount; index++) {
1270 if (uuid_compare(check_ifp->if_agentids[index], *agent_uuid) == 0) {
1271 ifnet_lock_done(check_ifp);
1272 return (TRUE);
1273 }
1274 }
1275 }
1276 ifnet_lock_done(check_ifp);
1277
1278 if (!check_delegates) {
1279 break;
1280 }
1281 check_ifp = check_ifp->if_delegated.ifp;
1282 }
1283 return (FALSE);
1284 }
1285
1286 static bool
1287 necp_necp_ifnet_matches_agent_type(struct ifnet *ifp, const char *agent_domain, const char *agent_type, bool check_delegates)
1288 {
1289 struct ifnet *check_ifp = ifp;
1290
1291 while (check_ifp != NULL) {
1292 ifnet_lock_shared(check_ifp);
1293 if (check_ifp->if_agentids != NULL) {
1294 for (u_int32_t index = 0; index < check_ifp->if_agentcount; index++) {
1295 if (uuid_is_null(check_ifp->if_agentids[index])) {
1296 continue;
1297 }
1298
1299 char if_agent_domain[NETAGENT_DOMAINSIZE] = { 0 };
1300 char if_agent_type[NETAGENT_TYPESIZE] = { 0 };
1301
1302 if (netagent_get_agent_domain_and_type(check_ifp->if_agentids[index], if_agent_domain, if_agent_type)) {
1303 if ((strlen(agent_domain) == 0 ||
1304 strncmp(if_agent_domain, agent_domain, NETAGENT_DOMAINSIZE) == 0) &&
1305 (strlen(agent_type) == 0 ||
1306 strncmp(if_agent_type, agent_type, NETAGENT_TYPESIZE) == 0)) {
1307 ifnet_lock_done(check_ifp);
1308 return (TRUE);
1309 }
1310 }
1311 }
1312 }
1313 ifnet_lock_done(check_ifp);
1314
1315 if (!check_delegates) {
1316 break;
1317 }
1318 check_ifp = check_ifp->if_delegated.ifp;
1319 }
1320 return (FALSE);
1321 }
1322
1323 static bool
1324 necp_ifnet_matches_local_address(struct ifnet *ifp, struct sockaddr *sa)
1325 {
1326 struct ifaddr *ifa = NULL;
1327 bool matched_local_address = FALSE;
1328
1329 // Transform sa into the ifaddr form
1330 // IPv6 Scope IDs are always embedded in the ifaddr list
1331 struct sockaddr_storage address;
1332 u_int ifscope = IFSCOPE_NONE;
1333 (void)sa_copy(sa, &address, &ifscope);
1334 SIN(&address)->sin_port = 0;
1335 if (address.ss_family == AF_INET6) {
1336 SIN6(&address)->sin6_scope_id = 0;
1337 }
1338
1339 ifa = ifa_ifwithaddr_scoped_locked((struct sockaddr *)&address, ifp->if_index);
1340 matched_local_address = (ifa != NULL);
1341
1342 if (ifa) {
1343 ifaddr_release(ifa);
1344 }
1345
1346 return (matched_local_address);
1347 }
1348
1349 static bool
1350 necp_ifnet_matches_parameters(struct ifnet *ifp,
1351 struct necp_client_parsed_parameters *parsed_parameters,
1352 u_int32_t *preferred_count)
1353 {
1354 if (preferred_count) {
1355 *preferred_count = 0;
1356 }
1357
1358 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR) {
1359 if (!necp_ifnet_matches_local_address(ifp, &parsed_parameters->local_addr.sa)) {
1360 return (FALSE);
1361 }
1362 }
1363
1364 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE) {
1365 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1366 if (parsed_parameters->required_interface_types[i] == 0) {
1367 break;
1368 }
1369
1370 if (!necp_ifnet_matches_type(ifp, parsed_parameters->required_interface_types[i], FALSE)) {
1371 return (FALSE);
1372 }
1373 }
1374 }
1375
1376 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE) {
1377 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1378 if (parsed_parameters->prohibited_interface_types[i] == 0) {
1379 break;
1380 }
1381
1382 if (necp_ifnet_matches_type(ifp, parsed_parameters->prohibited_interface_types[i], TRUE)) {
1383 return (FALSE);
1384 }
1385 }
1386 }
1387
1388 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF) {
1389 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1390 if (strlen(parsed_parameters->prohibited_interfaces[i]) == 0) {
1391 break;
1392 }
1393
1394 if (necp_ifnet_matches_name(ifp, parsed_parameters->prohibited_interfaces[i], TRUE)) {
1395 return (FALSE);
1396 }
1397 }
1398 }
1399
1400 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT) {
1401 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1402 if (uuid_is_null(parsed_parameters->required_netagents[i])) {
1403 break;
1404 }
1405
1406 if (!necp_ifnet_matches_agent(ifp, &parsed_parameters->required_netagents[i], FALSE)) {
1407 return (FALSE);
1408 }
1409 }
1410 }
1411
1412 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT) {
1413 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1414 if (uuid_is_null(parsed_parameters->prohibited_netagents[i])) {
1415 break;
1416 }
1417
1418 if (necp_ifnet_matches_agent(ifp, &parsed_parameters->prohibited_netagents[i], TRUE)) {
1419 return (FALSE);
1420 }
1421 }
1422 }
1423
1424 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE) {
1425 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1426 if (strlen(parsed_parameters->required_netagent_types[i].netagent_domain) == 0 &&
1427 strlen(parsed_parameters->required_netagent_types[i].netagent_type) == 0) {
1428 break;
1429 }
1430
1431 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)) {
1432 return (FALSE);
1433 }
1434 }
1435 }
1436
1437 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE) {
1438 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1439 if (strlen(parsed_parameters->prohibited_netagent_types[i].netagent_domain) == 0 &&
1440 strlen(parsed_parameters->prohibited_netagent_types[i].netagent_type) == 0) {
1441 break;
1442 }
1443
1444 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)) {
1445 return (FALSE);
1446 }
1447 }
1448 }
1449
1450 // Checked preferred properties
1451 if (preferred_count) {
1452 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT) {
1453 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1454 if (uuid_is_null(parsed_parameters->preferred_netagents[i])) {
1455 break;
1456 }
1457
1458 if (necp_ifnet_matches_agent(ifp, &parsed_parameters->preferred_netagents[i], TRUE)) {
1459 (*preferred_count)++;
1460 }
1461 }
1462 }
1463
1464 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE) {
1465 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1466 if (strlen(parsed_parameters->preferred_netagent_types[i].netagent_domain) == 0 &&
1467 strlen(parsed_parameters->preferred_netagent_types[i].netagent_type) == 0) {
1468 break;
1469 }
1470
1471 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)) {
1472 (*preferred_count)++;
1473 }
1474 }
1475 }
1476 }
1477
1478 return (TRUE);
1479 }
1480
1481 static bool
1482 necp_find_matching_interface_index(struct necp_client_parsed_parameters *parsed_parameters, u_int *return_ifindex)
1483 {
1484 struct ifnet *ifp = NULL;
1485 u_int32_t best_preferred_count = 0;
1486 bool has_preferred_fields = FALSE;
1487 *return_ifindex = 0;
1488
1489 if (parsed_parameters->required_interface_index != 0) {
1490 *return_ifindex = parsed_parameters->required_interface_index;
1491 return (TRUE);
1492 }
1493
1494 if (!(parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS)) {
1495 return (TRUE);
1496 }
1497
1498 has_preferred_fields = (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS);
1499
1500 // We have interesting parameters to parse and find a matching interface
1501 ifnet_head_lock_shared();
1502
1503 if (!(parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS)) {
1504 // We do have fields to match, but they are only prohibitory
1505 // If the first interface in the list matches, we don't need to scope
1506 ifp = TAILQ_FIRST(&ifnet_ordered_head);
1507 if (ifp && necp_ifnet_matches_parameters(ifp, parsed_parameters, NULL)) {
1508 // Don't set return_ifindex, so the client doesn't need to scope
1509 ifnet_head_done();
1510 return (TRUE);
1511 }
1512 }
1513
1514 // First check the ordered interface list
1515 TAILQ_FOREACH(ifp, &ifnet_ordered_head, if_ordered_link) {
1516 u_int32_t preferred_count = 0;
1517 if (necp_ifnet_matches_parameters(ifp, parsed_parameters, &preferred_count)) {
1518 if (preferred_count > best_preferred_count ||
1519 *return_ifindex == 0) {
1520
1521 // Everything matched, and is most preferred. Return this interface.
1522 *return_ifindex = ifp->if_index;
1523 best_preferred_count = preferred_count;
1524
1525 if (!has_preferred_fields) {
1526 break;
1527 }
1528 }
1529 }
1530 }
1531
1532 // Then check the remaining interfaces
1533 if ((parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS) &&
1534 !(parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE) &&
1535 *return_ifindex == 0) {
1536 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
1537 u_int32_t preferred_count = 0;
1538 if (ifp->if_ordered_link.tqe_next != NULL ||
1539 ifp->if_ordered_link.tqe_prev != NULL) {
1540 // This interface was in the ordered list, skip
1541 continue;
1542 }
1543 if (necp_ifnet_matches_parameters(ifp, parsed_parameters, &preferred_count)) {
1544 if (preferred_count > best_preferred_count ||
1545 *return_ifindex == 0) {
1546
1547 // Everything matched, and is most preferred. Return this interface.
1548 *return_ifindex = ifp->if_index;
1549 best_preferred_count = preferred_count;
1550
1551 if (!has_preferred_fields) {
1552 break;
1553 }
1554 }
1555 }
1556 }
1557 }
1558
1559 ifnet_head_done();
1560
1561 if ((parsed_parameters->valid_fields == (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS)) &&
1562 best_preferred_count == 0) {
1563 // If only has preferred fields, and nothing was found, clear the interface index and return TRUE
1564 *return_ifindex = 0;
1565 return (TRUE);
1566 }
1567
1568 return (*return_ifindex != 0);
1569 }
1570
1571 static void
1572 necp_find_netstat_data(struct necp_client *client, union necp_sockaddr_union *local, union necp_sockaddr_union *remote, u_int32_t *ifindex, uuid_t euuid, u_int32_t *traffic_class)
1573 {
1574 size_t offset = 0;
1575 u_int8_t *parameters;
1576 u_int32_t parameters_size;
1577
1578 parameters = client->parameters;
1579 parameters_size = (u_int32_t)client->parameters_length;
1580
1581 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
1582 u_int8_t type = necp_buffer_get_tlv_type(parameters, offset);
1583 u_int32_t length = necp_buffer_get_tlv_length(parameters, offset);
1584
1585 if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
1586 // If the length is larger than what can fit in the remaining parameters size, bail
1587 NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
1588 break;
1589 }
1590
1591 if (length > 0) {
1592 u_int8_t *value = necp_buffer_get_tlv_value(parameters, offset, NULL);
1593 if (value != NULL) {
1594 switch (type) {
1595 case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
1596 if (length >= sizeof(uuid_t)) {
1597 uuid_copy(euuid, value);
1598 }
1599 break;
1600 }
1601 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
1602 if (length >= sizeof(u_int32_t)) {
1603 memcpy(traffic_class, value, sizeof(u_int32_t));
1604 }
1605 break;
1606 }
1607 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
1608 if (length <= IFXNAMSIZ && length > 0) {
1609 ifnet_t bound_interface = NULL;
1610 char interface_name[IFXNAMSIZ];
1611 memcpy(interface_name, value, length);
1612 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
1613 if (ifnet_find_by_name(interface_name, &bound_interface) == 0) {
1614 *ifindex = bound_interface->if_index;
1615 ifnet_release(bound_interface);
1616 }
1617 }
1618 break;
1619 }
1620 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
1621 if (length >= sizeof(struct necp_policy_condition_addr)) {
1622 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
1623 memcpy(local, &address_struct->address, sizeof(address_struct->address));
1624 }
1625 break;
1626 }
1627 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
1628 if (length >= sizeof(struct necp_policy_condition_addr)) {
1629 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
1630 memcpy(remote, &address_struct->address, sizeof(address_struct->address));
1631 }
1632 break;
1633 }
1634 default: {
1635 break;
1636 }
1637 }
1638 }
1639 }
1640 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
1641 }
1642 }
1643
1644 static void
1645 necp_fillout_current_process_details(u_int32_t *pid, u_int64_t *upid, unsigned char *uuid, char *pname, size_t len)
1646 {
1647 *pid = proc_selfpid();
1648 *upid = proc_uniqueid(current_proc());
1649 proc_selfname(pname, (int) len);
1650 proc_getexecutableuuid(current_proc(), uuid, sizeof(uuid_t));
1651 }
1652
1653 // Called from NetworkStatistics when it wishes to collect latest information for a TCP flow.
1654 // It is a responsibility of NetworkStatistics to have previously zeroed any supplied memory.
1655 static bool
1656 necp_request_tcp_netstats(userland_stats_provider_context *ctx,
1657 nstat_counts *countsp,
1658 void *metadatap)
1659 {
1660 if (ctx == NULL) {
1661 return false;
1662 }
1663
1664 struct necp_client *client = (struct necp_client *)ctx;
1665 struct necp_tcp_stats *tcpstats = (struct necp_tcp_stats *)client->stats_area;
1666 if (tcpstats == NULL) {
1667 return false;
1668 }
1669
1670 if (countsp) {
1671 *countsp = *((struct nstat_counts *)&tcpstats->necp_tcp_counts);
1672 }
1673
1674 if (metadatap) {
1675 nstat_tcp_descriptor *desc = (nstat_tcp_descriptor *)metadatap;
1676
1677 // Metadata for the process
1678 necp_fillout_current_process_details(&desc->pid, &desc->upid, desc->uuid, desc->pname, sizeof(desc->pname));
1679
1680 // Metadata that the necp client should have in TLV format.
1681 necp_find_netstat_data(client, (union necp_sockaddr_union *)&desc->local, (union necp_sockaddr_union *)&desc->remote, &desc->ifindex, desc->euuid, &desc->traffic_class);
1682
1683 // Basic metadata
1684 desc->rcvbufsize = tcpstats->necp_tcp_basic.rcvbufsize;
1685 desc->rcvbufused = tcpstats->necp_tcp_basic.rcvbufused;
1686 desc->eupid = tcpstats->necp_tcp_basic.eupid;
1687 desc->epid = tcpstats->necp_tcp_basic.epid;
1688 memcpy(desc->vuuid, tcpstats->necp_tcp_basic.vuuid, sizeof(desc->vuuid));
1689 desc->ifnet_properties = tcpstats->necp_tcp_basic.ifnet_properties;
1690
1691 // Additional TCP specific data
1692 desc->sndbufsize = tcpstats->necp_tcp_extra.sndbufsize;
1693 desc->sndbufused = tcpstats->necp_tcp_extra.sndbufused;
1694 desc->txunacked = tcpstats->necp_tcp_extra.txunacked;
1695 desc->txwindow = tcpstats->necp_tcp_extra.txwindow;
1696 desc->txcwindow = tcpstats->necp_tcp_extra.txcwindow;
1697 desc->traffic_mgt_flags = tcpstats->necp_tcp_extra.traffic_mgt_flags;
1698
1699 if (tcpstats->necp_tcp_extra.cc_alg_index < TCP_CC_ALGO_COUNT) {
1700 strlcpy(desc->cc_algo, tcp_cc_algo_list[tcpstats->necp_tcp_extra.cc_alg_index]->name, sizeof(desc->cc_algo));
1701 } else {
1702 strlcpy(desc->cc_algo, "unknown", sizeof(desc->cc_algo));
1703 }
1704
1705 desc->connstatus.write_probe_failed = tcpstats->necp_tcp_extra.probestatus.write_probe_failed;
1706 desc->connstatus.read_probe_failed = tcpstats->necp_tcp_extra.probestatus.read_probe_failed;
1707 desc->connstatus.conn_probe_failed = tcpstats->necp_tcp_extra.probestatus.conn_probe_failed;
1708 }
1709 return true;
1710 }
1711
1712 // Called from NetworkStatistics when it wishes to collect latest information for a UDP flow.
1713 static bool
1714 necp_request_udp_netstats(userland_stats_provider_context *ctx,
1715 nstat_counts *countsp,
1716 void *metadatap)
1717 {
1718 if (ctx == NULL) {
1719 return false;
1720 }
1721
1722 struct necp_client *client = (struct necp_client *)ctx;
1723 struct necp_udp_stats *udpstats = (struct necp_udp_stats *)client->stats_area;
1724 if (udpstats == NULL) {
1725 return false;
1726 }
1727
1728 if (countsp) {
1729 *countsp = *((struct nstat_counts *)&udpstats->necp_udp_counts);
1730 }
1731
1732 if (metadatap) {
1733 nstat_udp_descriptor *desc = (nstat_udp_descriptor *)metadatap;
1734
1735 // Metadata for the process
1736 necp_fillout_current_process_details(&desc->pid, &desc->upid, desc->uuid, desc->pname, sizeof(desc->pname));
1737
1738 // Metadata that the necp client should have in TLV format.
1739 necp_find_netstat_data(client, (union necp_sockaddr_union *)&desc->local, (union necp_sockaddr_union *)&desc->remote, &desc->ifindex, desc->euuid, &desc->traffic_class);
1740
1741 // Basic metadata is all that is required for UDP
1742 desc->rcvbufsize = udpstats->necp_udp_basic.rcvbufsize;
1743 desc->rcvbufused = udpstats->necp_udp_basic.rcvbufused;
1744 desc->eupid = udpstats->necp_udp_basic.eupid;
1745 desc->epid = udpstats->necp_udp_basic.epid;
1746 memcpy(desc->vuuid, udpstats->necp_udp_basic.vuuid, sizeof(desc->euuid));
1747 desc->ifnet_properties = udpstats->necp_udp_basic.ifnet_properties;
1748 }
1749 return true;
1750 }
1751
1752 static int
1753 necp_skywalk_priv_check_cred(proc_t p, kauth_cred_t cred)
1754 {
1755 #pragma unused(p, cred)
1756 return (0);
1757 }
1758
1759 /// System calls
1760
1761 int
1762 necp_open(struct proc *p, struct necp_open_args *uap, int *retval)
1763 {
1764 #pragma unused(retval)
1765 int error = 0;
1766 struct necp_fd_data *fd_data = NULL;
1767 struct fileproc *fp = NULL;
1768 int fd = -1;
1769
1770 if (uap->flags & NECP_OPEN_FLAG_OBSERVER) {
1771 if (necp_skywalk_priv_check_cred(p, kauth_cred_get()) != 0 &&
1772 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NETWORK_STATISTICS, 0) != 0) {
1773 NECPLOG0(LOG_ERR, "Client does not hold necessary entitlement to observe other NECP clients");
1774 error = EACCES;
1775 goto done;
1776 }
1777 }
1778
1779 error = falloc(p, &fp, &fd, vfs_context_current());
1780 if (error != 0) {
1781 goto done;
1782 }
1783
1784 if ((fd_data = _MALLOC(sizeof(struct necp_fd_data), M_NECP,
1785 M_WAITOK | M_ZERO)) == NULL) {
1786 error = ENOMEM;
1787 goto done;
1788 }
1789
1790 fd_data->flags = uap->flags;
1791 LIST_INIT(&fd_data->clients);
1792 lck_mtx_init(&fd_data->fd_lock, necp_fd_mtx_grp, necp_fd_mtx_attr);
1793 klist_init(&fd_data->si.si_note);
1794 fd_data->proc_pid = proc_pid(p);
1795
1796 fp->f_fglob->fg_flag = FREAD;
1797 fp->f_fglob->fg_ops = &necp_fd_ops;
1798 fp->f_fglob->fg_data = fd_data;
1799
1800 proc_fdlock(p);
1801
1802 *fdflags(p, fd) |= (UF_EXCLOSE | UF_FORKCLOSE);
1803 procfdtbl_releasefd(p, fd, NULL);
1804 fp_drop(p, fd, fp, 1);
1805
1806 *retval = fd;
1807
1808 lck_rw_lock_exclusive(&necp_fd_lock);
1809 LIST_INSERT_HEAD(&necp_fd_list, fd_data, chain);
1810 lck_rw_done(&necp_fd_lock);
1811
1812 proc_fdunlock(p);
1813
1814 done:
1815 if (error != 0) {
1816 if (fp != NULL) {
1817 fp_free(p, fd, fp);
1818 fp = NULL;
1819 }
1820 if (fd_data != NULL) {
1821 FREE(fd_data, M_NECP);
1822 fd_data = NULL;
1823 }
1824 }
1825
1826 return (error);
1827 }
1828
1829 static int
1830 necp_client_add(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
1831 {
1832 int error = 0;
1833 struct necp_client *client = NULL;
1834
1835 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t) ||
1836 uap->buffer_size == 0 || uap->buffer_size > NECP_MAX_CLIENT_PARAMETERS_SIZE || uap->buffer == 0) {
1837 error = EINVAL;
1838 goto done;
1839 }
1840
1841 if ((client = _MALLOC(sizeof(struct necp_client) + uap->buffer_size, M_NECP,
1842 M_WAITOK | M_ZERO)) == NULL) {
1843 error = ENOMEM;
1844 goto done;
1845 }
1846
1847 error = copyin(uap->buffer, client->parameters, uap->buffer_size);
1848 if (error) {
1849 NECPLOG(LOG_ERR, "necp_client_add parameters copyin error (%d)", error);
1850 goto done;
1851 }
1852
1853 client->parameters_length = uap->buffer_size;
1854
1855 uuid_generate_random(client->client_id);
1856 LIST_INIT(&client->assertion_list);
1857
1858 error = copyout(client->client_id, uap->client_id, sizeof(uuid_t));
1859 if (error) {
1860 NECPLOG(LOG_ERR, "necp_client_add client_id copyout error (%d)", error);
1861 goto done;
1862 }
1863
1864 lck_mtx_lock(&fd_data->fd_lock);
1865 LIST_INSERT_HEAD(&fd_data->clients, client, chain);
1866
1867 // Prime the client result
1868 (void)necp_update_client_result(current_proc(), client);
1869 lck_mtx_unlock(&fd_data->fd_lock);
1870 done:
1871 if (error != 0) {
1872 if (client != NULL) {
1873 FREE(client, M_NECP);
1874 client = NULL;
1875 }
1876 }
1877 *retval = error;
1878
1879 return (error);
1880 }
1881
1882 static int
1883 necp_client_remove(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
1884 {
1885 int error = 0;
1886 struct necp_client *client = NULL;
1887 struct necp_client *temp_client = NULL;
1888 uuid_t client_id;
1889
1890 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t)) {
1891 error = EINVAL;
1892 goto done;
1893 }
1894
1895 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
1896 if (error) {
1897 NECPLOG(LOG_ERR, "necp_client_remove copyin client_id error (%d)", error);
1898 goto done;
1899 }
1900
1901 lck_mtx_lock(&fd_data->fd_lock);
1902 LIST_FOREACH_SAFE(client, &fd_data->clients, chain, temp_client) {
1903 if (uuid_compare(client->client_id, client_id) == 0) {
1904 necp_destroy_client(client);
1905 }
1906 }
1907 lck_mtx_unlock(&fd_data->fd_lock);
1908 done:
1909 *retval = error;
1910
1911 return (error);
1912 }
1913
1914 static int
1915 necp_client_copy_internal(struct necp_client *client, bool client_is_observed, struct necp_client_action_args *uap, int *retval)
1916 {
1917 int error = 0;
1918 // Copy results out
1919 if (uap->action == NECP_CLIENT_ACTION_COPY_PARAMETERS) {
1920 if (uap->buffer_size < client->parameters_length) {
1921 error = EINVAL;
1922 goto done;
1923 }
1924 error = copyout(client->parameters, uap->buffer, client->parameters_length);
1925 if (error) {
1926 NECPLOG(LOG_ERR, "necp_client_copy parameters copyout error (%d)", error);
1927 goto done;
1928 }
1929 *retval = client->parameters_length;
1930 } else if (uap->action == NECP_CLIENT_ACTION_COPY_RESULT) {
1931 if (uap->buffer_size < (client->result_length + client->assigned_results_length)) {
1932 error = EINVAL;
1933 goto done;
1934 }
1935 error = copyout(client->result, uap->buffer, client->result_length);
1936 if (error) {
1937 NECPLOG(LOG_ERR, "necp_client_copy result copyout error (%d)", error);
1938 goto done;
1939 }
1940 if (client->assigned_results_length && client->assigned_results) {
1941 error = copyout(client->assigned_results, uap->buffer + client->result_length, client->assigned_results_length);
1942 if (error) {
1943 NECPLOG(LOG_ERR, "necp_client_copy assigned results copyout error (%d)", error);
1944 goto done;
1945 }
1946 *retval = client->result_length + client->assigned_results_length;
1947 } else {
1948 *retval = client->result_length;
1949 }
1950
1951 if (!client_is_observed) {
1952 client->result_read = TRUE;
1953 client->assigned_result_read = TRUE;
1954 }
1955 }
1956
1957 done:
1958 return (error);
1959 }
1960
1961 static int
1962 necp_client_copy(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
1963 {
1964 int error = 0;
1965 struct necp_client *find_client = NULL;
1966 struct necp_client *client = NULL;
1967 uuid_t client_id;
1968 uuid_clear(client_id);
1969
1970 *retval = 0;
1971
1972 if (uap->buffer_size == 0 || uap->buffer == 0) {
1973 error = EINVAL;
1974 goto done;
1975 }
1976
1977 if (uap->action != NECP_CLIENT_ACTION_COPY_PARAMETERS &&
1978 uap->action != NECP_CLIENT_ACTION_COPY_RESULT) {
1979 error = EINVAL;
1980 goto done;
1981 }
1982
1983 if (uap->client_id) {
1984 if (uap->client_id_len != sizeof(uuid_t)) {
1985 NECPLOG(LOG_ERR, "Incorrect length (got %d, expected %d)", uap->client_id_len, sizeof(uuid_t));
1986 error = ERANGE;
1987 goto done;
1988 }
1989
1990 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
1991 if (error) {
1992 NECPLOG(LOG_ERR, "necp_client_copy client_id copyin error (%d)", error);
1993 goto done;
1994 }
1995 }
1996
1997 lck_mtx_lock(&fd_data->fd_lock);
1998 LIST_FOREACH(find_client, &fd_data->clients, chain) {
1999 if (uap->action == NECP_CLIENT_ACTION_COPY_RESULT &&
2000 uuid_is_null(client_id)) {
2001 if (!find_client->result_read || !find_client->assigned_result_read) {
2002 client = find_client;
2003 break;
2004 }
2005 } else if (uuid_compare(find_client->client_id, client_id) == 0) {
2006 client = find_client;
2007 break;
2008 }
2009 }
2010
2011 if (client != NULL) {
2012 error = necp_client_copy_internal(client, FALSE, uap, retval);
2013 }
2014
2015 // Unlock our own client before moving on or returning
2016 lck_mtx_unlock(&fd_data->fd_lock);
2017
2018 if (client == NULL) {
2019 if (fd_data->flags & NECP_OPEN_FLAG_OBSERVER) {
2020 // Observers are allowed to lookup clients on other fds
2021
2022 // Lock list
2023 lck_rw_lock_shared(&necp_fd_lock);
2024 struct necp_fd_data *client_fd = NULL;
2025 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
2026 // Lock client
2027 lck_mtx_lock(&client_fd->fd_lock);
2028 find_client = NULL;
2029 LIST_FOREACH(find_client, &client_fd->clients, chain) {
2030 if (uuid_compare(find_client->client_id, client_id) == 0) {
2031 client = find_client;
2032 break;
2033 }
2034 }
2035
2036 if (client != NULL) {
2037 // Matched, copy out data
2038 error = necp_client_copy_internal(client, TRUE, uap, retval);
2039 }
2040
2041 // Unlock client
2042 lck_mtx_unlock(&client_fd->fd_lock);
2043
2044 if (client != NULL) {
2045 break;
2046 }
2047 }
2048
2049 // Unlock list
2050 lck_rw_done(&necp_fd_lock);
2051
2052 // No client found, fail
2053 if (client == NULL) {
2054 error = ENOENT;
2055 goto done;
2056 }
2057 } else {
2058 // No client found, and not allowed to search other fds, fail
2059 error = ENOENT;
2060 goto done;
2061 }
2062 }
2063
2064 done:
2065 return (error);
2066 }
2067
2068 static int
2069 necp_client_list(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2070 {
2071 int error = 0;
2072 struct necp_client *find_client = NULL;
2073 uuid_t *list = NULL;
2074 u_int32_t requested_client_count = 0;
2075 u_int32_t client_count = 0;
2076
2077 if (uap->buffer_size < sizeof(requested_client_count) || uap->buffer == 0) {
2078 error = EINVAL;
2079 goto done;
2080 }
2081
2082 if (!(fd_data->flags & NECP_OPEN_FLAG_OBSERVER)) {
2083 NECPLOG0(LOG_ERR, "Client does not hold necessary entitlement to list other NECP clients");
2084 error = EACCES;
2085 goto done;
2086 }
2087
2088 error = copyin(uap->buffer, &requested_client_count, sizeof(requested_client_count));
2089 if (error) {
2090 goto done;
2091 }
2092
2093 if (uap->buffer_size != (sizeof(requested_client_count) + requested_client_count * sizeof(uuid_t))) {
2094 error = EINVAL;
2095 goto done;
2096 }
2097
2098 if (requested_client_count > 0) {
2099 if ((list = _MALLOC(requested_client_count * sizeof(uuid_t), M_NECP, M_WAITOK | M_ZERO)) == NULL) {
2100 error = ENOMEM;
2101 goto done;
2102 }
2103 }
2104
2105 // Lock list
2106 lck_rw_lock_shared(&necp_fd_lock);
2107 struct necp_fd_data *client_fd = NULL;
2108 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
2109 // Lock client
2110 lck_mtx_lock(&client_fd->fd_lock);
2111 find_client = NULL;
2112 LIST_FOREACH(find_client, &client_fd->clients, chain) {
2113 if (!uuid_is_null(find_client->client_id)) {
2114 if (client_count < requested_client_count) {
2115 uuid_copy(list[client_count], find_client->client_id);
2116 }
2117 client_count++;
2118 }
2119 }
2120 lck_mtx_unlock(&client_fd->fd_lock);
2121 }
2122
2123 // Unlock list
2124 lck_rw_done(&necp_fd_lock);
2125
2126 error = copyout(&client_count, uap->buffer, sizeof(client_count));
2127 if (error) {
2128 NECPLOG(LOG_ERR, "necp_client_list buffer copyout error (%d)", error);
2129 goto done;
2130 }
2131
2132 if (requested_client_count > 0 &&
2133 client_count > 0 &&
2134 list != NULL) {
2135 error = copyout(list, uap->buffer + sizeof(client_count), requested_client_count * sizeof(uuid_t));
2136 if (error) {
2137 NECPLOG(LOG_ERR, "necp_client_list client count copyout error (%d)", error);
2138 goto done;
2139 }
2140 }
2141 done:
2142 if (list != NULL) {
2143 FREE(list, M_NECP);
2144 }
2145 *retval = error;
2146
2147 return (error);
2148 }
2149
2150 static int
2151 necp_client_request_nexus(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2152 {
2153 int error = 0;
2154 struct necp_client *client = NULL;
2155 uuid_t client_id;
2156 bool requested_nexus = FALSE;
2157
2158 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t)) {
2159 error = EINVAL;
2160 goto done;
2161 }
2162
2163 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
2164 if (error) {
2165 NECPLOG(LOG_ERR, "necp_client_request_nexus copyin client_id error (%d)", error);
2166 goto done;
2167 }
2168
2169 lck_mtx_lock(&fd_data->fd_lock);
2170 LIST_FOREACH(client, &fd_data->clients, chain) {
2171 if (uuid_compare(client->client_id, client_id) == 0) {
2172 // Request from nexus agent
2173 if (!uuid_is_null(client->nexus_agent)) {
2174 error = netagent_client_message(client->nexus_agent, client->client_id,
2175 NETAGENT_MESSAGE_TYPE_REQUEST_NEXUS);
2176 if (error == 0) {
2177 requested_nexus = TRUE;
2178 }
2179 }
2180 break;
2181 }
2182 }
2183 lck_mtx_unlock(&fd_data->fd_lock);
2184
2185 if (!requested_nexus &&
2186 error == 0) {
2187 error = ENOENT;
2188 }
2189 done:
2190 *retval = error;
2191
2192 return (error);
2193 }
2194
2195 static void
2196 necp_client_add_assertion(struct necp_client *client, uuid_t netagent_uuid)
2197 {
2198 struct necp_client_assertion *new_assertion = NULL;
2199
2200 MALLOC(new_assertion, struct necp_client_assertion *, sizeof(*new_assertion), M_NECP, M_WAITOK);
2201 if (new_assertion == NULL) {
2202 NECPLOG0(LOG_ERR, "Failed to allocate assertion");
2203 return;
2204 }
2205
2206 uuid_copy(new_assertion->asserted_netagent, netagent_uuid);
2207
2208 LIST_INSERT_HEAD(&client->assertion_list, new_assertion, assertion_chain);
2209 }
2210
2211 static bool
2212 necp_client_remove_assertion(struct necp_client *client, uuid_t netagent_uuid)
2213 {
2214 struct necp_client_assertion *found_assertion = NULL;
2215 struct necp_client_assertion *search_assertion = NULL;
2216 LIST_FOREACH(search_assertion, &client->assertion_list, assertion_chain) {
2217 if (uuid_compare(search_assertion->asserted_netagent, netagent_uuid) == 0) {
2218 found_assertion = search_assertion;
2219 break;
2220 }
2221 }
2222
2223 if (found_assertion == NULL) {
2224 NECPLOG0(LOG_ERR, "Netagent uuid not previously asserted");
2225 return false;
2226 }
2227
2228 LIST_REMOVE(found_assertion, assertion_chain);
2229 FREE(found_assertion, M_NECP);
2230 return true;
2231 }
2232
2233 static int
2234 necp_client_agent_action(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2235 {
2236 int error = 0;
2237 struct necp_client *matched_client = NULL;
2238 struct necp_client *client = NULL;
2239 uuid_t client_id;
2240 bool acted_on_agent = FALSE;
2241 u_int8_t *parameters = NULL;
2242 size_t parameters_size = uap->buffer_size;
2243
2244 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t) ||
2245 uap->buffer_size == 0 || uap->buffer == 0) {
2246 error = EINVAL;
2247 goto done;
2248 }
2249
2250 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
2251 if (error) {
2252 NECPLOG(LOG_ERR, "necp_client_agent_action copyin client_id error (%d)", error);
2253 goto done;
2254 }
2255
2256 if ((parameters = _MALLOC(uap->buffer_size, M_NECP, M_WAITOK | M_ZERO)) == NULL) {
2257 error = ENOMEM;
2258 goto done;
2259 }
2260
2261 error = copyin(uap->buffer, parameters, uap->buffer_size);
2262 if (error) {
2263 NECPLOG(LOG_ERR, "necp_client_agent_action parameters copyin error (%d)", error);
2264 goto done;
2265 }
2266
2267 lck_mtx_lock(&fd_data->fd_lock);
2268 LIST_FOREACH(client, &fd_data->clients, chain) {
2269 if (uuid_compare(client->client_id, client_id) == 0) {
2270 matched_client = client;
2271 break;
2272 }
2273 }
2274 if (matched_client) {
2275 size_t offset = 0;
2276 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
2277 u_int8_t type = necp_buffer_get_tlv_type(parameters, offset);
2278 u_int32_t length = necp_buffer_get_tlv_length(parameters, offset);
2279
2280 if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
2281 // If the length is larger than what can fit in the remaining parameters size, bail
2282 NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
2283 break;
2284 }
2285
2286 if (length > 0) {
2287 u_int8_t *value = necp_buffer_get_tlv_value(parameters, offset, NULL);
2288 if (length >= sizeof(uuid_t) &&
2289 value != NULL &&
2290 (type == NECP_CLIENT_PARAMETER_TRIGGER_AGENT ||
2291 type == NECP_CLIENT_PARAMETER_ASSERT_AGENT ||
2292 type == NECP_CLIENT_PARAMETER_UNASSERT_AGENT)) {
2293
2294 uuid_t agent_uuid;
2295 uuid_copy(agent_uuid, value);
2296 u_int8_t netagent_message_type = 0;
2297 if (type == NECP_CLIENT_PARAMETER_TRIGGER_AGENT) {
2298 netagent_message_type = NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER;
2299 } else if (type == NECP_CLIENT_PARAMETER_ASSERT_AGENT) {
2300 netagent_message_type = NETAGENT_MESSAGE_TYPE_CLIENT_ASSERT;
2301 } else if (type == NECP_CLIENT_PARAMETER_UNASSERT_AGENT) {
2302 netagent_message_type = NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT;
2303 }
2304
2305 // Before unasserting, verify that the assertion was already taken
2306 if (type == NECP_CLIENT_PARAMETER_UNASSERT_AGENT) {
2307 if (!necp_client_remove_assertion(client, agent_uuid)) {
2308 error = ENOENT;
2309 break;
2310 }
2311 }
2312
2313 error = netagent_client_message(agent_uuid, client_id,
2314 netagent_message_type);
2315 if (error == 0) {
2316 acted_on_agent = TRUE;
2317 } else {
2318 break;
2319 }
2320
2321 // Only save the assertion if the action succeeded
2322 if (type == NECP_CLIENT_PARAMETER_ASSERT_AGENT) {
2323 necp_client_add_assertion(client, agent_uuid);
2324 }
2325 }
2326 }
2327
2328 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
2329 }
2330 }
2331 lck_mtx_unlock(&fd_data->fd_lock);
2332
2333 if (!acted_on_agent &&
2334 error == 0) {
2335 error = ENOENT;
2336 }
2337 done:
2338 *retval = error;
2339 if (parameters != NULL) {
2340 FREE(parameters, M_NECP);
2341 parameters = NULL;
2342 }
2343
2344 return (error);
2345 }
2346
2347 static int
2348 necp_client_copy_agent(__unused struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2349 {
2350 int error = 0;
2351 uuid_t agent_uuid;
2352
2353 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t) ||
2354 uap->buffer_size == 0 || uap->buffer == 0) {
2355 NECPLOG0(LOG_ERR, "necp_client_copy_agent bad input");
2356 error = EINVAL;
2357 goto done;
2358 }
2359
2360 error = copyin(uap->client_id, agent_uuid, sizeof(uuid_t));
2361 if (error) {
2362 NECPLOG(LOG_ERR, "necp_client_copy_agent copyin agent_uuid error (%d)", error);
2363 goto done;
2364 }
2365
2366 error = netagent_copyout(agent_uuid, uap->buffer, uap->buffer_size);
2367 if (error) {
2368 NECPLOG(LOG_ERR, "necp_client_copy_agent netagent_copyout error (%d)", error);
2369 goto done;
2370 }
2371 done:
2372 *retval = error;
2373
2374 return (error);
2375 }
2376
2377 static int
2378 necp_client_agent_use(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2379 {
2380 int error = 0;
2381 struct necp_client *matched_client = NULL;
2382 struct necp_client *client = NULL;
2383 uuid_t client_id;
2384 struct necp_agent_use_parameters parameters;
2385
2386 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t) ||
2387 uap->buffer_size != sizeof(parameters) || uap->buffer == 0) {
2388 error = EINVAL;
2389 goto done;
2390 }
2391
2392 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
2393 if (error) {
2394 NECPLOG(LOG_ERR, "Copyin client_id error (%d)", error);
2395 goto done;
2396 }
2397
2398 error = copyin(uap->buffer, &parameters, uap->buffer_size);
2399 if (error) {
2400 NECPLOG(LOG_ERR, "Parameters copyin error (%d)", error);
2401 goto done;
2402 }
2403
2404 lck_mtx_lock(&fd_data->fd_lock);
2405 LIST_FOREACH(client, &fd_data->clients, chain) {
2406 if (uuid_compare(client->client_id, client_id) == 0) {
2407 matched_client = client;
2408 break;
2409 }
2410 }
2411
2412 if (matched_client) {
2413 error = netagent_use(parameters.agent_uuid, &parameters.out_use_count);
2414 } else {
2415 error = ENOENT;
2416 }
2417
2418 lck_mtx_unlock(&fd_data->fd_lock);
2419
2420 if (error == 0) {
2421 error = copyout(&parameters, uap->buffer, uap->buffer_size);
2422 if (error) {
2423 NECPLOG(LOG_ERR, "Parameters copyout error (%d)", error);
2424 goto done;
2425 }
2426 }
2427
2428 done:
2429 *retval = error;
2430
2431 return (error);
2432 }
2433
2434 static int
2435 necp_client_copy_interface(__unused struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2436 {
2437 int error = 0;
2438 u_int32_t interface_index = 0;
2439 struct necp_interface_details interface_details;
2440
2441 if (uap->client_id == 0 || uap->client_id_len != sizeof(u_int32_t) ||
2442 uap->buffer_size < sizeof(interface_details) || uap->buffer == 0) {
2443 NECPLOG0(LOG_ERR, "necp_client_copy_interface bad input");
2444 error = EINVAL;
2445 goto done;
2446 }
2447
2448 error = copyin(uap->client_id, &interface_index, sizeof(u_int32_t));
2449 if (error) {
2450 NECPLOG(LOG_ERR, "necp_client_copy_interface copyin interface_index error (%d)", error);
2451 goto done;
2452 }
2453
2454 if (interface_index == 0) {
2455 error = ENOENT;
2456 NECPLOG(LOG_ERR, "necp_client_copy_interface bad interface_index (%d)", interface_index);
2457 goto done;
2458 }
2459
2460 memset(&interface_details, 0, sizeof(interface_details));
2461
2462 ifnet_head_lock_shared();
2463 ifnet_t interface = NULL;
2464 if (interface_index != IFSCOPE_NONE && interface_index <= (u_int32_t)if_index) {
2465 interface = ifindex2ifnet[interface_index];
2466 }
2467
2468 if (interface != NULL) {
2469 if (interface->if_xname != NULL) {
2470 strlcpy((char *)&interface_details.name, interface->if_xname, sizeof(interface_details.name));
2471 }
2472 interface_details.index = interface->if_index;
2473 interface_details.generation = ifnet_get_generation(interface);
2474 if (interface->if_delegated.ifp != NULL) {
2475 interface_details.delegate_index = interface->if_delegated.ifp->if_index;
2476 }
2477 interface_details.functional_type = if_functional_type(interface, TRUE);
2478 if (IFNET_IS_EXPENSIVE(interface)) {
2479 interface_details.flags |= NECP_INTERFACE_FLAG_EXPENSIVE;
2480 }
2481 interface_details.mtu = interface->if_mtu;
2482
2483 u_int8_t ipv4_signature_len = sizeof(interface_details.ipv4_signature);
2484 u_int16_t ipv4_signature_flags;
2485 ifnet_get_netsignature(interface, AF_INET, &ipv4_signature_len, &ipv4_signature_flags,
2486 (u_int8_t *)&interface_details.ipv4_signature);
2487
2488 u_int8_t ipv6_signature_len = sizeof(interface_details.ipv6_signature);
2489 u_int16_t ipv6_signature_flags;
2490 ifnet_get_netsignature(interface, AF_INET6, &ipv6_signature_len, &ipv6_signature_flags,
2491 (u_int8_t *)&interface_details.ipv6_signature);
2492 }
2493
2494 ifnet_head_done();
2495
2496 error = copyout(&interface_details, uap->buffer, sizeof(interface_details));
2497 if (error) {
2498 NECPLOG(LOG_ERR, "necp_client_copy_interface copyout error (%d)", error);
2499 goto done;
2500 }
2501 done:
2502 *retval = error;
2503
2504 return (error);
2505 }
2506
2507 static int
2508 necp_client_stats_action(struct necp_client *client, user_addr_t buffer, user_size_t buffer_size)
2509 {
2510 int error = 0;
2511 struct necp_stats_hdr *stats_hdr = NULL;
2512
2513 if (client->stats_area) {
2514 // Close old stats if required.
2515 if ((client->stats_uaddr != buffer) || (client->stats_ulen != buffer_size)) {
2516 necp_destroy_client_stats(client);
2517 }
2518 }
2519
2520 if ((buffer == 0) || (buffer_size == 0)) {
2521 goto done;
2522 }
2523
2524 if (client->stats_area) {
2525 // An update
2526 error = copyin(client->stats_uaddr, client->stats_area, client->stats_ulen);
2527 if (error) {
2528 NECPLOG(LOG_ERR, "necp_client_stats_action copyin error on update (%d)", error);
2529 } else {
2530 // Future use - check
2531 stats_hdr = (necp_stats_hdr *)client->stats_area;
2532 if (stats_hdr->necp_stats_event != 0) {
2533 ntstat_userland_stats_event(client->stats_handler_context, (userland_stats_event_t)stats_hdr->necp_stats_event);
2534 }
2535 }
2536 goto done;
2537 }
2538
2539 // A create
2540 if ((buffer_size > sizeof(necp_all_stats)) || (buffer_size < sizeof(necp_stats_hdr))) {
2541 error = EINVAL;
2542 goto done;
2543 }
2544
2545 if ((stats_hdr = _MALLOC(buffer_size, M_NECP, M_WAITOK | M_ZERO)) == NULL) {
2546 error = ENOMEM;
2547 goto done;
2548 }
2549
2550 client->stats_handler_context = NULL;
2551 client->stats_uaddr = buffer;
2552 client->stats_ulen = buffer_size;
2553 client->stats_area = stats_hdr;
2554 error = copyin(client->stats_uaddr, client->stats_area, client->stats_ulen);
2555 if (error) {
2556 NECPLOG(LOG_ERR, "necp_client_stats_action copyin error on create (%d)", error);
2557 goto done;
2558 }
2559
2560 switch (stats_hdr->necp_stats_type) {
2561 case NECP_CLIENT_STATISTICS_TYPE_TCP: {
2562 if (stats_hdr->necp_stats_ver == NECP_CLIENT_STATISTICS_TYPE_TCP_VER_1) {
2563 client->stats_handler_context = ntstat_userland_stats_open((userland_stats_provider_context *)client,
2564 NSTAT_PROVIDER_TCP_USERLAND, 0, necp_request_tcp_netstats);
2565 if (client->stats_handler_context == NULL) {
2566 error = EIO;
2567 }
2568 } else {
2569 error = ENOTSUP;
2570 }
2571 break;
2572 }
2573 case NECP_CLIENT_STATISTICS_TYPE_UDP: {
2574 if (stats_hdr->necp_stats_ver != NECP_CLIENT_STATISTICS_TYPE_UDP_VER_1) {
2575 client->stats_handler_context = ntstat_userland_stats_open((userland_stats_provider_context *)client,
2576 NSTAT_PROVIDER_UDP_USERLAND, 0, necp_request_udp_netstats);
2577 if (client->stats_handler_context == NULL) {
2578 error = EIO;
2579 }
2580 } else {
2581 error = ENOTSUP;
2582 }
2583 break;
2584 }
2585 default: {
2586 error = ENOTSUP;
2587 break;
2588 }
2589 }
2590 done:
2591 if ((error) && (stats_hdr != NULL)) {
2592 FREE(stats_hdr, M_NECP);
2593 client->stats_area = NULL;
2594 client->stats_handler_context = NULL;
2595 client->stats_uaddr = 0;
2596 client->stats_ulen = 0;
2597 }
2598
2599 return (error);
2600 }
2601
2602 static int
2603 necp_client_set_statistics(__unused struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2604 {
2605 int error = 0;
2606 struct necp_client *find_client = NULL;
2607 struct necp_client *client = NULL;
2608 uuid_t client_id;
2609
2610 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t)) {
2611 error = EINVAL;
2612 goto done;
2613 }
2614
2615 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
2616 if (error) {
2617 NECPLOG(LOG_ERR, "necp_client_set_statistics copyin client_id error (%d)", error);
2618 goto done;
2619 }
2620
2621 lck_mtx_lock(&fd_data->fd_lock);
2622 LIST_FOREACH(find_client, &fd_data->clients, chain) {
2623 if (uuid_compare(find_client->client_id, client_id) == 0) {
2624 client = find_client;
2625 break;
2626 }
2627 }
2628
2629 if (client) {
2630 error = necp_client_stats_action(client, uap->buffer, uap->buffer_size);
2631 } else {
2632 error = ENOENT;
2633 }
2634 lck_mtx_unlock(&fd_data->fd_lock);
2635 done:
2636 *retval = error;
2637 return (error);
2638 }
2639
2640 int
2641 necp_client_action(struct proc *p, struct necp_client_action_args *uap, int *retval)
2642 {
2643 #pragma unused(p)
2644 int error = 0;
2645 int return_value = 0;
2646 struct necp_fd_data *fd_data = NULL;
2647 error = necp_find_fd_data(uap->necp_fd, &fd_data);
2648 if (error != 0) {
2649 NECPLOG(LOG_ERR, "necp_client_action find fd error (%d)", error);
2650 return (error);
2651 }
2652
2653 u_int32_t action = uap->action;
2654 switch (action) {
2655 case NECP_CLIENT_ACTION_ADD: {
2656 return_value = necp_client_add(fd_data, uap, retval);
2657 break;
2658 }
2659 case NECP_CLIENT_ACTION_REMOVE: {
2660 return_value = necp_client_remove(fd_data, uap, retval);
2661 break;
2662 }
2663 case NECP_CLIENT_ACTION_COPY_PARAMETERS:
2664 case NECP_CLIENT_ACTION_COPY_RESULT: {
2665 return_value = necp_client_copy(fd_data, uap, retval);
2666 break;
2667 }
2668 case NECP_CLIENT_ACTION_COPY_LIST: {
2669 return_value = necp_client_list(fd_data, uap, retval);
2670 break;
2671 }
2672 case NECP_CLIENT_ACTION_REQUEST_NEXUS_INSTANCE: {
2673 return_value = necp_client_request_nexus(fd_data, uap, retval);
2674 break;
2675 }
2676 case NECP_CLIENT_ACTION_AGENT: {
2677 return_value = necp_client_agent_action(fd_data, uap, retval);
2678 break;
2679 }
2680 case NECP_CLIENT_ACTION_COPY_AGENT: {
2681 return_value = necp_client_copy_agent(fd_data, uap, retval);
2682 break;
2683 }
2684 case NECP_CLIENT_ACTION_AGENT_USE: {
2685 return_value = necp_client_agent_use(fd_data, uap, retval);
2686 break;
2687 }
2688 case NECP_CLIENT_ACTION_COPY_INTERFACE: {
2689 return_value = necp_client_copy_interface(fd_data, uap, retval);
2690 break;
2691 }
2692 case NECP_CLIENT_ACTION_SET_STATISTICS: {
2693 return_value = necp_client_set_statistics(fd_data, uap, retval);
2694 break;
2695 }
2696 default: {
2697 NECPLOG(LOG_ERR, "necp_client_action unknown action (%u)", action);
2698 return_value = EINVAL;
2699 break;
2700 }
2701 }
2702
2703 file_drop(uap->necp_fd);
2704
2705 return (return_value);
2706 }
2707
2708 #define NECP_MAX_MATCH_POLICY_PARAMETER_SIZE 1024
2709
2710 int
2711 necp_match_policy(struct proc *p, struct necp_match_policy_args *uap, int32_t *retval)
2712 {
2713 #pragma unused(retval)
2714 u_int8_t *parameters = NULL;
2715 struct necp_aggregate_result returned_result;
2716 int error = 0;
2717
2718 if (uap == NULL) {
2719 error = EINVAL;
2720 goto done;
2721 }
2722
2723 if (uap->parameters == 0 || uap->parameters_size == 0 || uap->parameters_size > NECP_MAX_MATCH_POLICY_PARAMETER_SIZE || uap->returned_result == 0) {
2724 error = EINVAL;
2725 goto done;
2726 }
2727
2728 MALLOC(parameters, u_int8_t *, uap->parameters_size, M_NECP, M_WAITOK | M_ZERO);
2729 if (parameters == NULL) {
2730 error = ENOMEM;
2731 goto done;
2732 }
2733 // Copy parameters in
2734 error = copyin(uap->parameters, parameters, uap->parameters_size);
2735 if (error) {
2736 goto done;
2737 }
2738
2739 error = necp_application_find_policy_match_internal(p, parameters, uap->parameters_size, &returned_result, NULL, 0);
2740 if (error) {
2741 goto done;
2742 }
2743
2744 // Copy return value back
2745 error = copyout(&returned_result, uap->returned_result, sizeof(struct necp_aggregate_result));
2746 if (error) {
2747 goto done;
2748 }
2749 done:
2750 if (parameters != NULL) {
2751 FREE(parameters, M_NECP);
2752 }
2753 return (error);
2754 }
2755
2756 /// Socket operations
2757 #define NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH 253
2758
2759 static bool
2760 necp_set_socket_attribute(u_int8_t *buffer, size_t buffer_length, u_int8_t type, char **buffer_p)
2761 {
2762 int error = 0;
2763 int cursor = 0;
2764 size_t string_size = 0;
2765 char *local_string = NULL;
2766 u_int8_t *value = NULL;
2767
2768 cursor = necp_buffer_find_tlv(buffer, buffer_length, 0, type, 0);
2769 if (cursor < 0) {
2770 // This will clear out the parameter
2771 goto done;
2772 }
2773
2774 string_size = necp_buffer_get_tlv_length(buffer, cursor);
2775 if (string_size == 0 || string_size > NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH) {
2776 // This will clear out the parameter
2777 goto done;
2778 }
2779
2780 MALLOC(local_string, char *, string_size + 1, M_NECP, M_WAITOK | M_ZERO);
2781 if (local_string == NULL) {
2782 NECPLOG(LOG_ERR, "Failed to allocate a socket attribute buffer (size %d)", string_size);
2783 goto fail;
2784 }
2785
2786 value = necp_buffer_get_tlv_value(buffer, cursor, NULL);
2787 if (value == NULL) {
2788 NECPLOG0(LOG_ERR, "Failed to get socket attribute");
2789 goto fail;
2790 }
2791
2792 memcpy(local_string, value, string_size);
2793 local_string[string_size] = 0;
2794
2795 done:
2796 if (*buffer_p != NULL) {
2797 FREE(*buffer_p, M_NECP);
2798 *buffer_p = NULL;
2799 }
2800
2801 *buffer_p = local_string;
2802 return (0);
2803 fail:
2804 if (local_string != NULL) {
2805 FREE(local_string, M_NECP);
2806 }
2807 return (error);
2808 }
2809
2810 errno_t
2811 necp_set_socket_attributes(struct socket *so, struct sockopt *sopt)
2812 {
2813 int error = 0;
2814 u_int8_t *buffer = NULL;
2815 struct inpcb *inp = NULL;
2816
2817 if ((SOCK_DOM(so) != PF_INET
2818 #if INET6
2819 && SOCK_DOM(so) != PF_INET6
2820 #endif
2821 )) {
2822 error = EINVAL;
2823 goto done;
2824 }
2825
2826 inp = sotoinpcb(so);
2827
2828 size_t valsize = sopt->sopt_valsize;
2829 if (valsize == 0 ||
2830 valsize > ((sizeof(u_int8_t) + sizeof(u_int32_t) + NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH) * 2)) {
2831 goto done;
2832 }
2833
2834 MALLOC(buffer, u_int8_t *, valsize, M_NECP, M_WAITOK | M_ZERO);
2835 if (buffer == NULL) {
2836 goto done;
2837 }
2838
2839 error = sooptcopyin(sopt, buffer, valsize, 0);
2840 if (error) {
2841 goto done;
2842 }
2843
2844 error = necp_set_socket_attribute(buffer, valsize, NECP_TLV_ATTRIBUTE_DOMAIN, &inp->inp_necp_attributes.inp_domain);
2845 if (error) {
2846 NECPLOG0(LOG_ERR, "Could not set domain TLV for socket attributes");
2847 goto done;
2848 }
2849
2850 error = necp_set_socket_attribute(buffer, valsize, NECP_TLV_ATTRIBUTE_ACCOUNT, &inp->inp_necp_attributes.inp_account);
2851 if (error) {
2852 NECPLOG0(LOG_ERR, "Could not set account TLV for socket attributes");
2853 goto done;
2854 }
2855
2856 if (necp_debug) {
2857 NECPLOG(LOG_DEBUG, "Set on socket: Domain %s, Account %s", inp->inp_necp_attributes.inp_domain, inp->inp_necp_attributes.inp_account);
2858 }
2859 done:
2860 if (buffer != NULL) {
2861 FREE(buffer, M_NECP);
2862 }
2863
2864 return (error);
2865 }
2866
2867 errno_t
2868 necp_get_socket_attributes(struct socket *so, struct sockopt *sopt)
2869 {
2870 int error = 0;
2871 u_int8_t *buffer = NULL;
2872 u_int8_t *cursor = NULL;
2873 size_t valsize = 0;
2874 struct inpcb *inp = sotoinpcb(so);
2875
2876 if (inp->inp_necp_attributes.inp_domain != NULL) {
2877 valsize += sizeof(u_int8_t) + sizeof(u_int32_t) + strlen(inp->inp_necp_attributes.inp_domain);
2878 }
2879 if (inp->inp_necp_attributes.inp_account != NULL) {
2880 valsize += sizeof(u_int8_t) + sizeof(u_int32_t) + strlen(inp->inp_necp_attributes.inp_account);
2881 }
2882 if (valsize == 0) {
2883 goto done;
2884 }
2885
2886 MALLOC(buffer, u_int8_t *, valsize, M_NECP, M_WAITOK | M_ZERO);
2887 if (buffer == NULL) {
2888 goto done;
2889 }
2890
2891 cursor = buffer;
2892 if (inp->inp_necp_attributes.inp_domain != NULL) {
2893 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ATTRIBUTE_DOMAIN, strlen(inp->inp_necp_attributes.inp_domain), inp->inp_necp_attributes.inp_domain);
2894 }
2895
2896 if (inp->inp_necp_attributes.inp_account != NULL) {
2897 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ATTRIBUTE_ACCOUNT, strlen(inp->inp_necp_attributes.inp_account), inp->inp_necp_attributes.inp_account);
2898 }
2899
2900 error = sooptcopyout(sopt, buffer, valsize);
2901 if (error) {
2902 goto done;
2903 }
2904 done:
2905 if (buffer != NULL) {
2906 FREE(buffer, M_NECP);
2907 }
2908
2909 return (error);
2910 }
2911
2912 void
2913 necp_inpcb_dispose(struct inpcb *inp)
2914 {
2915 if (inp->inp_necp_attributes.inp_domain != NULL) {
2916 FREE(inp->inp_necp_attributes.inp_domain, M_NECP);
2917 inp->inp_necp_attributes.inp_domain = NULL;
2918 }
2919 if (inp->inp_necp_attributes.inp_account != NULL) {
2920 FREE(inp->inp_necp_attributes.inp_account, M_NECP);
2921 inp->inp_necp_attributes.inp_account = NULL;
2922 }
2923 }
2924
2925 /// Module init
2926
2927 errno_t
2928 necp_client_init(void)
2929 {
2930 errno_t result = 0;
2931
2932 necp_fd_grp_attr = lck_grp_attr_alloc_init();
2933 if (necp_fd_grp_attr == NULL) {
2934 NECPLOG0(LOG_ERR, "lck_grp_attr_alloc_init failed");
2935 result = ENOMEM;
2936 goto done;
2937 }
2938
2939 necp_fd_mtx_grp = lck_grp_alloc_init("necp_fd", necp_fd_grp_attr);
2940 if (necp_fd_mtx_grp == NULL) {
2941 NECPLOG0(LOG_ERR, "lck_grp_alloc_init failed");
2942 result = ENOMEM;
2943 goto done;
2944 }
2945
2946 necp_fd_mtx_attr = lck_attr_alloc_init();
2947 if (necp_fd_mtx_attr == NULL) {
2948 NECPLOG0(LOG_ERR, "lck_attr_alloc_init failed");
2949 result = ENOMEM;
2950 goto done;
2951 }
2952
2953 necp_client_tcall = thread_call_allocate(necp_update_all_clients_callout, NULL);
2954 if (necp_client_tcall == NULL) {
2955 NECPLOG0(LOG_ERR, "thread_call_allocate failed");
2956 result = ENOMEM;
2957 goto done;
2958 }
2959
2960 lck_rw_init(&necp_fd_lock, necp_fd_mtx_grp, necp_fd_mtx_attr);
2961
2962 LIST_INIT(&necp_fd_list);
2963
2964 done:
2965 if (result != 0) {
2966 if (necp_fd_mtx_attr != NULL) {
2967 lck_attr_free(necp_fd_mtx_attr);
2968 necp_fd_mtx_attr = NULL;
2969 }
2970 if (necp_fd_mtx_grp != NULL) {
2971 lck_grp_free(necp_fd_mtx_grp);
2972 necp_fd_mtx_grp = NULL;
2973 }
2974 if (necp_fd_grp_attr != NULL) {
2975 lck_grp_attr_free(necp_fd_grp_attr);
2976 necp_fd_grp_attr = NULL;
2977 }
2978 }
2979 return (result);
2980 }