]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/necp_client.c
xnu-3789.41.3.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 > 0 && (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length) <= parameters_size) {
660 u_int8_t *value = necp_buffer_get_tlv_value(parameters, offset, NULL);
661 if (value != NULL) {
662 switch (type) {
663 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
664 if (length <= IFXNAMSIZ && length > 0) {
665 ifnet_t bound_interface = NULL;
666 char interface_name[IFXNAMSIZ];
667 memcpy(interface_name, value, length);
668 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
669 if (ifnet_find_by_name(interface_name, &bound_interface) == 0) {
670 parsed_parameters->required_interface_index = bound_interface->if_index;
671 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF;
672 ifnet_release(bound_interface);
673 }
674 }
675 break;
676 }
677 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
678 if (length >= sizeof(struct necp_policy_condition_addr)) {
679 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
680 if ((address_struct->address.sa.sa_family == AF_INET ||
681 address_struct->address.sa.sa_family == AF_INET6) &&
682 address_struct->address.sa.sa_len <= length) {
683 memcpy(&parsed_parameters->local_addr, &address_struct->address, sizeof(address_struct->address));
684 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR;
685 }
686 }
687 break;
688 }
689 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
690 if (length >= sizeof(struct necp_client_endpoint)) {
691 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
692 if ((endpoint->u.endpoint.endpoint_family == AF_INET ||
693 endpoint->u.endpoint.endpoint_family == AF_INET6) &&
694 endpoint->u.endpoint.endpoint_length <= length) {
695 memcpy(&parsed_parameters->local_addr, &endpoint->u.sa, sizeof(union necp_sockaddr_union));
696 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR;
697 }
698 }
699 break;
700 }
701 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
702 if (length >= sizeof(struct necp_policy_condition_addr)) {
703 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
704 if ((address_struct->address.sa.sa_family == AF_INET ||
705 address_struct->address.sa.sa_family == AF_INET6) &&
706 address_struct->address.sa.sa_len <= length) {
707 memcpy(&parsed_parameters->remote_addr, &address_struct->address, sizeof(address_struct->address));
708 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR;
709 }
710 }
711 break;
712 }
713 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
714 if (length >= sizeof(struct necp_client_endpoint)) {
715 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
716 if ((endpoint->u.endpoint.endpoint_family == AF_INET ||
717 endpoint->u.endpoint.endpoint_family == AF_INET6) &&
718 endpoint->u.endpoint.endpoint_length <= length) {
719 memcpy(&parsed_parameters->remote_addr, &endpoint->u.sa, sizeof(union necp_sockaddr_union));
720 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR;
721 }
722 }
723 break;
724 }
725 case NECP_CLIENT_PARAMETER_PROHIBIT_INTERFACE: {
726 if (num_prohibited_interfaces >= NECP_MAX_PARSED_PARAMETERS) {
727 break;
728 }
729 if (length <= IFXNAMSIZ && length > 0) {
730 memcpy(parsed_parameters->prohibited_interfaces[num_prohibited_interfaces], value, length);
731 parsed_parameters->prohibited_interfaces[num_prohibited_interfaces][length - 1] = 0; // Make sure the string is NULL terminated
732 num_prohibited_interfaces++;
733 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF;
734 }
735 break;
736 }
737 case NECP_CLIENT_PARAMETER_REQUIRE_IF_TYPE: {
738 if (num_required_interface_types >= NECP_MAX_PARSED_PARAMETERS) {
739 break;
740 }
741 if (length >= sizeof(u_int8_t)) {
742 memcpy(&parsed_parameters->required_interface_types[num_required_interface_types], value, sizeof(u_int8_t));
743 num_required_interface_types++;
744 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE;
745 }
746 break;
747 }
748 case NECP_CLIENT_PARAMETER_PROHIBIT_IF_TYPE: {
749 if (num_prohibited_interface_types >= NECP_MAX_PARSED_PARAMETERS) {
750 break;
751 }
752 if (length >= sizeof(u_int8_t)) {
753 memcpy(&parsed_parameters->prohibited_interface_types[num_prohibited_interface_types], value, sizeof(u_int8_t));
754 num_prohibited_interface_types++;
755 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE;
756 }
757 break;
758 }
759 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT: {
760 if (num_required_agents >= NECP_MAX_PARSED_PARAMETERS) {
761 break;
762 }
763 if (length >= sizeof(uuid_t)) {
764 memcpy(&parsed_parameters->required_netagents[num_required_agents], value, sizeof(uuid_t));
765 num_required_agents++;
766 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT;
767 }
768 break;
769 }
770 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT: {
771 if (num_prohibited_agents >= NECP_MAX_PARSED_PARAMETERS) {
772 break;
773 }
774 if (length >= sizeof(uuid_t)) {
775 memcpy(&parsed_parameters->prohibited_netagents[num_prohibited_agents], value, sizeof(uuid_t));
776 num_prohibited_agents++;
777 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT;
778 }
779 break;
780 }
781 case NECP_CLIENT_PARAMETER_PREFER_AGENT: {
782 if (num_preferred_agents >= NECP_MAX_PARSED_PARAMETERS) {
783 break;
784 }
785 if (length >= sizeof(uuid_t)) {
786 memcpy(&parsed_parameters->preferred_netagents[num_preferred_agents], value, sizeof(uuid_t));
787 num_preferred_agents++;
788 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT;
789 }
790 break;
791 }
792 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE: {
793 if (num_required_agent_types >= NECP_MAX_PARSED_PARAMETERS) {
794 break;
795 }
796 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
797 memcpy(&parsed_parameters->required_netagent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
798 num_required_agent_types++;
799 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE;
800 }
801 break;
802 }
803 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT_TYPE: {
804 if (num_prohibited_agent_types >= NECP_MAX_PARSED_PARAMETERS) {
805 break;
806 }
807 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
808 memcpy(&parsed_parameters->prohibited_netagent_types[num_prohibited_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
809 num_prohibited_agent_types++;
810 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE;
811 }
812 break;
813 }
814 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
815 if (num_preferred_agent_types >= NECP_MAX_PARSED_PARAMETERS) {
816 break;
817 }
818 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
819 memcpy(&parsed_parameters->preferred_netagent_types[num_preferred_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
820 num_preferred_agent_types++;
821 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE;
822 }
823 break;
824 }
825 default: {
826 break;
827 }
828 }
829 }
830 }
831
832 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
833 }
834
835 return (error);
836 }
837
838 int
839 necp_assign_client_result(uuid_t netagent_uuid, uuid_t client_id,
840 u_int8_t *assigned_results, size_t assigned_results_length)
841 {
842 int error = 0;
843 struct necp_fd_data *client_fd = NULL;
844 bool found_client = FALSE;
845 bool client_updated = FALSE;
846
847 lck_rw_lock_shared(&necp_fd_lock);
848
849 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
850 struct necp_client *client = NULL;
851 lck_mtx_lock(&client_fd->fd_lock);
852 LIST_FOREACH(client, &client_fd->clients, chain) {
853 if (uuid_compare(client->client_id, client_id) == 0) {
854 // Found the right client!
855 found_client = TRUE;
856
857 if (uuid_compare(client->nexus_agent, netagent_uuid) == 0) {
858 // Verify that the client nexus agent matches
859 if (client->assigned_results != NULL) {
860 // Release prior result
861 FREE(client->assigned_results, M_NETAGENT);
862 }
863 client->assigned_results = assigned_results;
864 client->assigned_results_length = assigned_results_length;
865 client->assigned_result_read = FALSE;
866 client_updated = TRUE;
867 }
868 }
869 }
870 if (client_updated) {
871 necp_fd_notify(client_fd, true);
872 }
873 lck_mtx_unlock(&client_fd->fd_lock);
874
875 if (found_client) {
876 break;
877 }
878 }
879
880 lck_rw_done(&necp_fd_lock);
881
882 if (!found_client) {
883 error = ENOENT;
884 } else if (!client_updated) {
885 error = EINVAL;
886 }
887
888 return (error);
889 }
890
891 /// Client updating
892
893 static bool
894 necp_update_client_result(proc_t proc,
895 struct necp_client *client)
896 {
897 struct necp_client_result_netagent netagent;
898 struct necp_aggregate_result result;
899 struct necp_client_parsed_parameters parsed_parameters;
900 u_int32_t flags = 0;
901
902 uuid_clear(client->nexus_agent);
903
904 int error = necp_client_parse_parameters(client->parameters, (u_int32_t)client->parameters_length, &parsed_parameters);
905 if (error != 0) {
906 return (FALSE);
907 }
908
909 // Check parameters to find best interface
910 u_int matching_if_index = 0;
911 if (necp_find_matching_interface_index(&parsed_parameters, &matching_if_index)) {
912 if (matching_if_index != 0) {
913 parsed_parameters.required_interface_index = matching_if_index;
914 }
915 // Interface found or not needed, match policy.
916 error = necp_application_find_policy_match_internal(proc, client->parameters, (u_int32_t)client->parameters_length, &result, &flags, matching_if_index);
917 if (error != 0) {
918 return (FALSE);
919 }
920 } else {
921 // Interface not found. Clear out the whole result, make everything fail.
922 memset(&result, 0, sizeof(result));
923 }
924
925 // If the original request was scoped, and the policy result matches, make sure the result is scoped
926 if ((result.routing_result == NECP_KERNEL_POLICY_RESULT_NONE ||
927 result.routing_result == NECP_KERNEL_POLICY_RESULT_PASS) &&
928 result.routed_interface_index != IFSCOPE_NONE &&
929 parsed_parameters.required_interface_index == result.routed_interface_index) {
930 result.routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
931 result.routing_result_parameter.scoped_interface_index = result.routed_interface_index;
932 }
933
934 bool updated = FALSE;
935 u_int8_t *cursor = client->result;
936 const u_int8_t *max = client->result + NECP_MAX_CLIENT_RESULT_SIZE;
937 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_CLIENT_ID, sizeof(uuid_t), client->client_id, &updated);
938 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_POLICY_RESULT, sizeof(result.routing_result), &result.routing_result, &updated);
939 if (result.routing_result_parameter.tunnel_interface_index != 0) {
940 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_POLICY_RESULT_PARAMETER,
941 sizeof(result.routing_result_parameter), &result.routing_result_parameter, &updated);
942 }
943 if (result.filter_control_unit != 0) {
944 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_FILTER_CONTROL_UNIT,
945 sizeof(result.filter_control_unit), &result.filter_control_unit, &updated);
946 }
947 if (result.routed_interface_index != 0) {
948 u_int routed_interface_index = result.routed_interface_index;
949 if (result.routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
950 parsed_parameters.required_interface_index != IFSCOPE_NONE &&
951 parsed_parameters.required_interface_index != result.routed_interface_index) {
952 routed_interface_index = parsed_parameters.required_interface_index;
953 }
954
955 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_INTERFACE_INDEX,
956 sizeof(routed_interface_index), &routed_interface_index, &updated);
957 }
958 if (flags != 0) {
959 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_FLAGS,
960 sizeof(flags), &flags, &updated);
961 }
962 for (int i = 0; i < NECP_MAX_NETAGENTS; i++) {
963 if (uuid_is_null(result.netagents[i])) {
964 break;
965 }
966 uuid_copy(netagent.netagent_uuid, result.netagents[i]);
967 netagent.generation = netagent_get_generation(netagent.netagent_uuid);
968 if (necp_netagent_applies_to_client(client, &parsed_parameters, netagent.netagent_uuid)) {
969 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_NETAGENT, sizeof(netagent), &netagent, &updated);
970 }
971 }
972
973 ifnet_head_lock_shared();
974 ifnet_t direct_interface = NULL;
975 ifnet_t delegate_interface = NULL;
976 ifnet_t original_scoped_interface = NULL;
977
978 if (result.routed_interface_index != IFSCOPE_NONE && (int)result.routed_interface_index <= if_index) {
979 direct_interface = ifindex2ifnet[result.routed_interface_index];
980 } else if (parsed_parameters.required_interface_index != IFSCOPE_NONE &&
981 (int)parsed_parameters.required_interface_index <= if_index) {
982 // If the request was scoped, but the route didn't match, still grab the agents
983 direct_interface = ifindex2ifnet[parsed_parameters.required_interface_index];
984 } else if (result.routed_interface_index == IFSCOPE_NONE &&
985 result.routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED &&
986 result.routing_result_parameter.scoped_interface_index != IFSCOPE_NONE) {
987 direct_interface = ifindex2ifnet[result.routing_result_parameter.scoped_interface_index];
988 }
989 if (direct_interface != NULL) {
990 delegate_interface = direct_interface->if_delegated.ifp;
991 }
992 if (result.routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
993 parsed_parameters.required_interface_index != IFSCOPE_NONE &&
994 parsed_parameters.required_interface_index != result.routing_result_parameter.tunnel_interface_index &&
995 (int)parsed_parameters.required_interface_index <= if_index) {
996 original_scoped_interface = ifindex2ifnet[parsed_parameters.required_interface_index];
997 }
998 // Add interfaces
999 if (original_scoped_interface != NULL) {
1000 struct necp_client_result_interface interface_struct;
1001 interface_struct.index = original_scoped_interface->if_index;
1002 interface_struct.generation = ifnet_get_generation(original_scoped_interface);
1003 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_INTERFACE, sizeof(interface_struct), &interface_struct, &updated);
1004 }
1005 if (direct_interface != NULL) {
1006 struct necp_client_result_interface interface_struct;
1007 interface_struct.index = direct_interface->if_index;
1008 interface_struct.generation = ifnet_get_generation(direct_interface);
1009 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_INTERFACE, sizeof(interface_struct), &interface_struct, &updated);
1010 }
1011 if (delegate_interface != NULL) {
1012 struct necp_client_result_interface interface_struct;
1013 interface_struct.index = delegate_interface->if_index;
1014 interface_struct.generation = ifnet_get_generation(delegate_interface);
1015 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_INTERFACE, sizeof(interface_struct), &interface_struct, &updated);
1016 }
1017 // Add agents
1018 if (original_scoped_interface != NULL) {
1019 ifnet_lock_shared(original_scoped_interface);
1020 if (original_scoped_interface->if_agentids != NULL) {
1021 for (u_int32_t i = 0; i < original_scoped_interface->if_agentcount; i++) {
1022 if (uuid_is_null(original_scoped_interface->if_agentids[i])) {
1023 continue;
1024 }
1025 uuid_copy(netagent.netagent_uuid, original_scoped_interface->if_agentids[i]);
1026 netagent.generation = netagent_get_generation(netagent.netagent_uuid);
1027 if (necp_netagent_applies_to_client(client, &parsed_parameters, netagent.netagent_uuid)) {
1028 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_NETAGENT, sizeof(netagent), &netagent, &updated);
1029 }
1030 }
1031 }
1032 ifnet_lock_done(original_scoped_interface);
1033 }
1034 if (direct_interface != NULL) {
1035 ifnet_lock_shared(direct_interface);
1036 if (direct_interface->if_agentids != NULL) {
1037 for (u_int32_t i = 0; i < direct_interface->if_agentcount; i++) {
1038 if (uuid_is_null(direct_interface->if_agentids[i])) {
1039 continue;
1040 }
1041 uuid_copy(netagent.netagent_uuid, direct_interface->if_agentids[i]);
1042 netagent.generation = netagent_get_generation(netagent.netagent_uuid);
1043 if (necp_netagent_applies_to_client(client, &parsed_parameters, netagent.netagent_uuid)) {
1044 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_NETAGENT, sizeof(netagent), &netagent, &updated);
1045 }
1046 }
1047 }
1048 ifnet_lock_done(direct_interface);
1049 }
1050 if (delegate_interface != NULL) {
1051 ifnet_lock_shared(delegate_interface);
1052 if (delegate_interface->if_agentids != NULL) {
1053 for (u_int32_t i = 0; i < delegate_interface->if_agentcount; i++) {
1054 if (uuid_is_null(delegate_interface->if_agentids[i])) {
1055 continue;
1056 }
1057 uuid_copy(netagent.netagent_uuid, delegate_interface->if_agentids[i]);
1058 netagent.generation = netagent_get_generation(netagent.netagent_uuid);
1059 if (necp_netagent_applies_to_client(client, &parsed_parameters, netagent.netagent_uuid)) {
1060 cursor = necp_buffer_write_tlv_if_different(cursor, max, NECP_CLIENT_RESULT_NETAGENT, sizeof(netagent), &netagent, &updated);
1061 }
1062 }
1063 }
1064 ifnet_lock_done(delegate_interface);
1065 }
1066 ifnet_head_done();
1067
1068 size_t new_result_length = (cursor - client->result);
1069 if (new_result_length != client->result_length) {
1070 client->result_length = new_result_length;
1071 updated = TRUE;
1072 }
1073 if (updated) {
1074 client->result_read = FALSE;
1075 }
1076
1077 return (updated);
1078 }
1079
1080 static void
1081 necp_update_all_clients_callout(__unused thread_call_param_t dummy,
1082 __unused thread_call_param_t arg)
1083 {
1084 #pragma unused(arg)
1085 struct necp_fd_data *client_fd = NULL;
1086
1087 lck_rw_lock_shared(&necp_fd_lock);
1088
1089 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
1090 bool updated_result = FALSE;
1091 struct necp_client *client = NULL;
1092 proc_t proc = proc_find(client_fd->proc_pid);
1093 if (proc == NULL) {
1094 continue;
1095 }
1096
1097 lck_mtx_lock(&client_fd->fd_lock);
1098 LIST_FOREACH(client, &client_fd->clients, chain) {
1099 if (necp_update_client_result(proc, client)) {
1100 updated_result = TRUE;
1101 }
1102 }
1103 if (updated_result) {
1104 necp_fd_notify(client_fd, true);
1105 }
1106 lck_mtx_unlock(&client_fd->fd_lock);
1107
1108 proc_rele(proc);
1109 }
1110
1111 lck_rw_done(&necp_fd_lock);
1112 }
1113
1114 void
1115 necp_update_all_clients(void)
1116 {
1117 if (necp_client_tcall == NULL) {
1118 // Don't try to update clients if the module is not initialized
1119 return;
1120 }
1121
1122 uint64_t deadline = 0;
1123 uint64_t leeway = 0;
1124 clock_interval_to_deadline(necp_timeout_microseconds, NSEC_PER_USEC, &deadline);
1125 clock_interval_to_absolutetime_interval(necp_timeout_leeway_microseconds, NSEC_PER_USEC, &leeway);
1126
1127 thread_call_enter_delayed_with_leeway(necp_client_tcall, NULL,
1128 deadline, leeway, THREAD_CALL_DELAY_LEEWAY);
1129 }
1130
1131 static void
1132 necp_client_remove_agent_from_result(struct necp_client *client, uuid_t netagent_uuid)
1133 {
1134 size_t offset = 0;
1135
1136 u_int8_t *result_buffer = client->result;
1137 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= client->result_length) {
1138 u_int8_t type = necp_buffer_get_tlv_type(result_buffer, offset);
1139 u_int32_t length = necp_buffer_get_tlv_length(result_buffer, offset);
1140
1141 size_t tlv_total_length = (sizeof(u_int8_t) + sizeof(u_int32_t) + length);
1142 if (type == NECP_CLIENT_RESULT_NETAGENT &&
1143 length == sizeof(struct necp_client_result_netagent) &&
1144 (offset + tlv_total_length) <= client->result_length) {
1145 struct necp_client_result_netagent *value = ((struct necp_client_result_netagent *)(void *)
1146 necp_buffer_get_tlv_value(result_buffer, offset, NULL));
1147 if (uuid_compare(value->netagent_uuid, netagent_uuid) == 0) {
1148 // Found a netagent to remove
1149 // Shift bytes down to remove the tlv, and adjust total length
1150 // Don't adjust the current offset
1151 memmove(result_buffer + offset,
1152 result_buffer + offset + tlv_total_length,
1153 client->result_length - (offset + tlv_total_length));
1154 client->result_length -= tlv_total_length;
1155 memset(result_buffer + client->result_length, 0, NECP_MAX_CLIENT_RESULT_SIZE - client->result_length);
1156 continue;
1157 }
1158 }
1159
1160 offset += tlv_total_length;
1161 }
1162 }
1163
1164 void
1165 necp_force_update_client(uuid_t client_id, uuid_t remove_netagent_uuid)
1166 {
1167 struct necp_fd_data *client_fd = NULL;
1168
1169 lck_rw_lock_shared(&necp_fd_lock);
1170
1171 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
1172 bool updated_result = FALSE;
1173 struct necp_client *client = NULL;
1174 lck_mtx_lock(&client_fd->fd_lock);
1175 LIST_FOREACH(client, &client_fd->clients, chain) {
1176 if (uuid_compare(client->client_id, client_id) == 0) {
1177 if (!uuid_is_null(remove_netagent_uuid)) {
1178 necp_client_remove_agent_from_result(client, remove_netagent_uuid);
1179 }
1180 client->assigned_result_read = FALSE;
1181 updated_result = TRUE;
1182 // Found the client, break
1183 break;
1184 }
1185 }
1186 if (updated_result) {
1187 necp_fd_notify(client_fd, true);
1188 }
1189 lck_mtx_unlock(&client_fd->fd_lock);
1190 if (updated_result) {
1191 // Found the client, break
1192 break;
1193 }
1194 }
1195
1196 lck_rw_done(&necp_fd_lock);
1197 }
1198
1199 /// Interface matching
1200
1201 #define NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
1202 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF | \
1203 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
1204 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE | \
1205 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
1206 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT | \
1207 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
1208 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
1209 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE | \
1210 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
1211
1212 #define NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
1213 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
1214 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
1215 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
1216 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
1217 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
1218
1219 #define NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
1220 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
1221
1222 static bool
1223 necp_ifnet_matches_type(struct ifnet *ifp, u_int8_t interface_type, bool check_delegates)
1224 {
1225 struct ifnet *check_ifp = ifp;
1226 while (check_ifp) {
1227 if (if_functional_type(check_ifp, TRUE) == interface_type) {
1228 return (TRUE);
1229 }
1230 if (!check_delegates) {
1231 break;
1232 }
1233 check_ifp = check_ifp->if_delegated.ifp;
1234
1235 }
1236 return (FALSE);
1237 }
1238
1239 static bool
1240 necp_ifnet_matches_name(struct ifnet *ifp, const char *interface_name, bool check_delegates)
1241 {
1242 struct ifnet *check_ifp = ifp;
1243 while (check_ifp) {
1244 if (strncmp(check_ifp->if_xname, interface_name, IFXNAMSIZ) == 0) {
1245 return (TRUE);
1246 }
1247 if (!check_delegates) {
1248 break;
1249 }
1250 check_ifp = check_ifp->if_delegated.ifp;
1251 }
1252 return (FALSE);
1253 }
1254
1255 static bool
1256 necp_ifnet_matches_agent(struct ifnet *ifp, uuid_t *agent_uuid, bool check_delegates)
1257 {
1258 struct ifnet *check_ifp = ifp;
1259
1260 while (check_ifp != NULL) {
1261 ifnet_lock_shared(check_ifp);
1262 if (check_ifp->if_agentids != NULL) {
1263 for (u_int32_t index = 0; index < check_ifp->if_agentcount; index++) {
1264 if (uuid_compare(check_ifp->if_agentids[index], *agent_uuid) == 0) {
1265 ifnet_lock_done(check_ifp);
1266 return (TRUE);
1267 }
1268 }
1269 }
1270 ifnet_lock_done(check_ifp);
1271
1272 if (!check_delegates) {
1273 break;
1274 }
1275 check_ifp = check_ifp->if_delegated.ifp;
1276 }
1277 return (FALSE);
1278 }
1279
1280 static bool
1281 necp_necp_ifnet_matches_agent_type(struct ifnet *ifp, const char *agent_domain, const char *agent_type, bool check_delegates)
1282 {
1283 struct ifnet *check_ifp = ifp;
1284
1285 while (check_ifp != NULL) {
1286 ifnet_lock_shared(check_ifp);
1287 if (check_ifp->if_agentids != NULL) {
1288 for (u_int32_t index = 0; index < check_ifp->if_agentcount; index++) {
1289 if (uuid_is_null(check_ifp->if_agentids[index])) {
1290 continue;
1291 }
1292
1293 char if_agent_domain[NETAGENT_DOMAINSIZE] = { 0 };
1294 char if_agent_type[NETAGENT_TYPESIZE] = { 0 };
1295
1296 if (netagent_get_agent_domain_and_type(check_ifp->if_agentids[index], if_agent_domain, if_agent_type)) {
1297 if ((strlen(agent_domain) == 0 ||
1298 strncmp(if_agent_domain, agent_domain, NETAGENT_DOMAINSIZE) == 0) &&
1299 (strlen(agent_type) == 0 ||
1300 strncmp(if_agent_type, agent_type, NETAGENT_TYPESIZE) == 0)) {
1301 ifnet_lock_done(check_ifp);
1302 return (TRUE);
1303 }
1304 }
1305 }
1306 }
1307 ifnet_lock_done(check_ifp);
1308
1309 if (!check_delegates) {
1310 break;
1311 }
1312 check_ifp = check_ifp->if_delegated.ifp;
1313 }
1314 return (FALSE);
1315 }
1316
1317 static bool
1318 necp_ifnet_matches_local_address(struct ifnet *ifp, struct sockaddr *sa)
1319 {
1320 struct ifaddr *ifa = NULL;
1321 bool matched_local_address = FALSE;
1322
1323 // Transform sa into the ifaddr form
1324 // IPv6 Scope IDs are always embedded in the ifaddr list
1325 struct sockaddr_storage address;
1326 u_int ifscope = IFSCOPE_NONE;
1327 (void)sa_copy(sa, &address, &ifscope);
1328 SIN(&address)->sin_port = 0;
1329 if (address.ss_family == AF_INET6) {
1330 SIN6(&address)->sin6_scope_id = 0;
1331 }
1332
1333 ifa = ifa_ifwithaddr_scoped_locked((struct sockaddr *)&address, ifp->if_index);
1334 matched_local_address = (ifa != NULL);
1335
1336 if (ifa) {
1337 ifaddr_release(ifa);
1338 }
1339
1340 return (matched_local_address);
1341 }
1342
1343 static bool
1344 necp_ifnet_matches_parameters(struct ifnet *ifp,
1345 struct necp_client_parsed_parameters *parsed_parameters,
1346 u_int32_t *preferred_count)
1347 {
1348 if (preferred_count) {
1349 *preferred_count = 0;
1350 }
1351
1352 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR) {
1353 if (!necp_ifnet_matches_local_address(ifp, &parsed_parameters->local_addr.sa)) {
1354 return (FALSE);
1355 }
1356 }
1357
1358 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE) {
1359 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1360 if (parsed_parameters->required_interface_types[i] == 0) {
1361 break;
1362 }
1363
1364 if (!necp_ifnet_matches_type(ifp, parsed_parameters->required_interface_types[i], FALSE)) {
1365 return (FALSE);
1366 }
1367 }
1368 }
1369
1370 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE) {
1371 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1372 if (parsed_parameters->prohibited_interface_types[i] == 0) {
1373 break;
1374 }
1375
1376 if (necp_ifnet_matches_type(ifp, parsed_parameters->prohibited_interface_types[i], TRUE)) {
1377 return (FALSE);
1378 }
1379 }
1380 }
1381
1382 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF) {
1383 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1384 if (strlen(parsed_parameters->prohibited_interfaces[i]) == 0) {
1385 break;
1386 }
1387
1388 if (necp_ifnet_matches_name(ifp, parsed_parameters->prohibited_interfaces[i], TRUE)) {
1389 return (FALSE);
1390 }
1391 }
1392 }
1393
1394 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT) {
1395 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1396 if (uuid_is_null(parsed_parameters->required_netagents[i])) {
1397 break;
1398 }
1399
1400 if (!necp_ifnet_matches_agent(ifp, &parsed_parameters->required_netagents[i], FALSE)) {
1401 return (FALSE);
1402 }
1403 }
1404 }
1405
1406 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT) {
1407 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1408 if (uuid_is_null(parsed_parameters->prohibited_netagents[i])) {
1409 break;
1410 }
1411
1412 if (necp_ifnet_matches_agent(ifp, &parsed_parameters->prohibited_netagents[i], TRUE)) {
1413 return (FALSE);
1414 }
1415 }
1416 }
1417
1418 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE) {
1419 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1420 if (strlen(parsed_parameters->required_netagent_types[i].netagent_domain) == 0 &&
1421 strlen(parsed_parameters->required_netagent_types[i].netagent_type) == 0) {
1422 break;
1423 }
1424
1425 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)) {
1426 return (FALSE);
1427 }
1428 }
1429 }
1430
1431 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE) {
1432 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1433 if (strlen(parsed_parameters->prohibited_netagent_types[i].netagent_domain) == 0 &&
1434 strlen(parsed_parameters->prohibited_netagent_types[i].netagent_type) == 0) {
1435 break;
1436 }
1437
1438 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)) {
1439 return (FALSE);
1440 }
1441 }
1442 }
1443
1444 // Checked preferred properties
1445 if (preferred_count) {
1446 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT) {
1447 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1448 if (uuid_is_null(parsed_parameters->preferred_netagents[i])) {
1449 break;
1450 }
1451
1452 if (necp_ifnet_matches_agent(ifp, &parsed_parameters->preferred_netagents[i], TRUE)) {
1453 (*preferred_count)++;
1454 }
1455 }
1456 }
1457
1458 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE) {
1459 for (int i = 0; i < NECP_MAX_PARSED_PARAMETERS; i++) {
1460 if (strlen(parsed_parameters->preferred_netagent_types[i].netagent_domain) == 0 &&
1461 strlen(parsed_parameters->preferred_netagent_types[i].netagent_type) == 0) {
1462 break;
1463 }
1464
1465 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)) {
1466 (*preferred_count)++;
1467 }
1468 }
1469 }
1470 }
1471
1472 return (TRUE);
1473 }
1474
1475 static bool
1476 necp_find_matching_interface_index(struct necp_client_parsed_parameters *parsed_parameters, u_int *return_ifindex)
1477 {
1478 struct ifnet *ifp = NULL;
1479 u_int32_t best_preferred_count = 0;
1480 bool has_preferred_fields = FALSE;
1481 *return_ifindex = 0;
1482
1483 if (parsed_parameters->required_interface_index != 0) {
1484 *return_ifindex = parsed_parameters->required_interface_index;
1485 return (TRUE);
1486 }
1487
1488 if (!(parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS)) {
1489 return (TRUE);
1490 }
1491
1492 has_preferred_fields = (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS);
1493
1494 // We have interesting parameters to parse and find a matching interface
1495 ifnet_head_lock_shared();
1496
1497 if (!(parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS)) {
1498 // We do have fields to match, but they are only prohibitory
1499 // If the first interface in the list matches, we don't need to scope
1500 ifp = TAILQ_FIRST(&ifnet_ordered_head);
1501 if (ifp && necp_ifnet_matches_parameters(ifp, parsed_parameters, NULL)) {
1502 // Don't set return_ifindex, so the client doesn't need to scope
1503 ifnet_head_done();
1504 return (TRUE);
1505 }
1506 }
1507
1508 // First check the ordered interface list
1509 TAILQ_FOREACH(ifp, &ifnet_ordered_head, if_ordered_link) {
1510 u_int32_t preferred_count = 0;
1511 if (necp_ifnet_matches_parameters(ifp, parsed_parameters, &preferred_count)) {
1512 if (preferred_count > best_preferred_count ||
1513 *return_ifindex == 0) {
1514
1515 // Everything matched, and is most preferred. Return this interface.
1516 *return_ifindex = ifp->if_index;
1517 best_preferred_count = preferred_count;
1518
1519 if (!has_preferred_fields) {
1520 break;
1521 }
1522 }
1523 }
1524 }
1525
1526 // Then check the remaining interfaces
1527 if ((parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS) &&
1528 !(parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE) &&
1529 *return_ifindex == 0) {
1530 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
1531 u_int32_t preferred_count = 0;
1532 if (ifp->if_ordered_link.tqe_next != NULL ||
1533 ifp->if_ordered_link.tqe_prev != NULL) {
1534 // This interface was in the ordered list, skip
1535 continue;
1536 }
1537 if (necp_ifnet_matches_parameters(ifp, parsed_parameters, &preferred_count)) {
1538 if (preferred_count > best_preferred_count ||
1539 *return_ifindex == 0) {
1540
1541 // Everything matched, and is most preferred. Return this interface.
1542 *return_ifindex = ifp->if_index;
1543 best_preferred_count = preferred_count;
1544
1545 if (!has_preferred_fields) {
1546 break;
1547 }
1548 }
1549 }
1550 }
1551 }
1552
1553 ifnet_head_done();
1554
1555 if ((parsed_parameters->valid_fields == (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS)) &&
1556 best_preferred_count == 0) {
1557 // If only has preferred fields, and nothing was found, clear the interface index and return TRUE
1558 *return_ifindex = 0;
1559 return (TRUE);
1560 }
1561
1562 return (*return_ifindex != 0);
1563 }
1564
1565 static void
1566 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)
1567 {
1568 size_t offset = 0;
1569 u_int8_t *parameters;
1570 u_int32_t parameters_size;
1571
1572 parameters = client->parameters;
1573 parameters_size = (u_int32_t)client->parameters_length;
1574
1575 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
1576 u_int8_t type = necp_buffer_get_tlv_type(parameters, offset);
1577 u_int32_t length = necp_buffer_get_tlv_length(parameters, offset);
1578
1579 if (length > 0 && (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length) <= parameters_size) {
1580 u_int8_t *value = necp_buffer_get_tlv_value(parameters, offset, NULL);
1581 if (value != NULL) {
1582 switch (type) {
1583 case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
1584 if (length >= sizeof(uuid_t)) {
1585 uuid_copy(euuid, value);
1586 }
1587 break;
1588 }
1589 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
1590 if (length >= sizeof(u_int32_t)) {
1591 memcpy(traffic_class, value, sizeof(u_int32_t));
1592 }
1593 break;
1594 }
1595 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
1596 if (length <= IFXNAMSIZ && length > 0) {
1597 ifnet_t bound_interface = NULL;
1598 char interface_name[IFXNAMSIZ];
1599 memcpy(interface_name, value, length);
1600 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
1601 if (ifnet_find_by_name(interface_name, &bound_interface) == 0) {
1602 *ifindex = bound_interface->if_index;
1603 ifnet_release(bound_interface);
1604 }
1605 }
1606 break;
1607 }
1608 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
1609 if (length >= sizeof(struct necp_policy_condition_addr)) {
1610 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
1611 memcpy(local, &address_struct->address, sizeof(address_struct->address));
1612 }
1613 break;
1614 }
1615 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
1616 if (length >= sizeof(struct necp_policy_condition_addr)) {
1617 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
1618 memcpy(remote, &address_struct->address, sizeof(address_struct->address));
1619 }
1620 break;
1621 }
1622 default: {
1623 break;
1624 }
1625 }
1626 }
1627 }
1628 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
1629 }
1630 }
1631
1632 static void
1633 necp_fillout_current_process_details(u_int32_t *pid, u_int64_t *upid, unsigned char *uuid, char *pname, size_t len)
1634 {
1635 *pid = proc_selfpid();
1636 *upid = proc_uniqueid(current_proc());
1637 proc_selfname(pname, (int) len);
1638 proc_getexecutableuuid(current_proc(), uuid, sizeof(uuid_t));
1639 }
1640
1641 // Called from NetworkStatistics when it wishes to collect latest information for a TCP flow.
1642 // It is a responsibility of NetworkStatistics to have previously zeroed any supplied memory.
1643 static bool
1644 necp_request_tcp_netstats(userland_stats_provider_context *ctx,
1645 nstat_counts *countsp,
1646 void *metadatap)
1647 {
1648 if (ctx == NULL) {
1649 return false;
1650 }
1651
1652 struct necp_client *client = (struct necp_client *)ctx;
1653 struct necp_tcp_stats *tcpstats = (struct necp_tcp_stats *)client->stats_area;
1654 if (tcpstats == NULL) {
1655 return false;
1656 }
1657
1658 if (countsp) {
1659 *countsp = *((struct nstat_counts *)&tcpstats->necp_tcp_counts);
1660 }
1661
1662 if (metadatap) {
1663 nstat_tcp_descriptor *desc = (nstat_tcp_descriptor *)metadatap;
1664
1665 // Metadata for the process
1666 necp_fillout_current_process_details(&desc->pid, &desc->upid, desc->uuid, desc->pname, sizeof(desc->pname));
1667
1668 // Metadata that the necp client should have in TLV format.
1669 necp_find_netstat_data(client, (union necp_sockaddr_union *)&desc->local, (union necp_sockaddr_union *)&desc->remote, &desc->ifindex, desc->euuid, &desc->traffic_class);
1670
1671 // Basic metadata
1672 desc->rcvbufsize = tcpstats->necp_tcp_basic.rcvbufsize;
1673 desc->rcvbufused = tcpstats->necp_tcp_basic.rcvbufused;
1674 desc->eupid = tcpstats->necp_tcp_basic.eupid;
1675 desc->epid = tcpstats->necp_tcp_basic.epid;
1676 memcpy(desc->vuuid, tcpstats->necp_tcp_basic.vuuid, sizeof(desc->vuuid));
1677 desc->ifnet_properties = tcpstats->necp_tcp_basic.ifnet_properties;
1678
1679 // Additional TCP specific data
1680 desc->sndbufsize = tcpstats->necp_tcp_extra.sndbufsize;
1681 desc->sndbufused = tcpstats->necp_tcp_extra.sndbufused;
1682 desc->txunacked = tcpstats->necp_tcp_extra.txunacked;
1683 desc->txwindow = tcpstats->necp_tcp_extra.txwindow;
1684 desc->txcwindow = tcpstats->necp_tcp_extra.txcwindow;
1685 desc->traffic_mgt_flags = tcpstats->necp_tcp_extra.traffic_mgt_flags;
1686
1687 if (tcpstats->necp_tcp_extra.cc_alg_index < TCP_CC_ALGO_COUNT) {
1688 strlcpy(desc->cc_algo, tcp_cc_algo_list[tcpstats->necp_tcp_extra.cc_alg_index]->name, sizeof(desc->cc_algo));
1689 } else {
1690 strlcpy(desc->cc_algo, "unknown", sizeof(desc->cc_algo));
1691 }
1692
1693 desc->connstatus.write_probe_failed = tcpstats->necp_tcp_extra.probestatus.write_probe_failed;
1694 desc->connstatus.read_probe_failed = tcpstats->necp_tcp_extra.probestatus.read_probe_failed;
1695 desc->connstatus.conn_probe_failed = tcpstats->necp_tcp_extra.probestatus.conn_probe_failed;
1696 }
1697 return true;
1698 }
1699
1700 // Called from NetworkStatistics when it wishes to collect latest information for a UDP flow.
1701 static bool
1702 necp_request_udp_netstats(userland_stats_provider_context *ctx,
1703 nstat_counts *countsp,
1704 void *metadatap)
1705 {
1706 if (ctx == NULL) {
1707 return false;
1708 }
1709
1710 struct necp_client *client = (struct necp_client *)ctx;
1711 struct necp_udp_stats *udpstats = (struct necp_udp_stats *)client->stats_area;
1712 if (udpstats == NULL) {
1713 return false;
1714 }
1715
1716 if (countsp) {
1717 *countsp = *((struct nstat_counts *)&udpstats->necp_udp_counts);
1718 }
1719
1720 if (metadatap) {
1721 nstat_udp_descriptor *desc = (nstat_udp_descriptor *)metadatap;
1722
1723 // Metadata for the process
1724 necp_fillout_current_process_details(&desc->pid, &desc->upid, desc->uuid, desc->pname, sizeof(desc->pname));
1725
1726 // Metadata that the necp client should have in TLV format.
1727 necp_find_netstat_data(client, (union necp_sockaddr_union *)&desc->local, (union necp_sockaddr_union *)&desc->remote, &desc->ifindex, desc->euuid, &desc->traffic_class);
1728
1729 // Basic metadata is all that is required for UDP
1730 desc->rcvbufsize = udpstats->necp_udp_basic.rcvbufsize;
1731 desc->rcvbufused = udpstats->necp_udp_basic.rcvbufused;
1732 desc->eupid = udpstats->necp_udp_basic.eupid;
1733 desc->epid = udpstats->necp_udp_basic.epid;
1734 memcpy(desc->vuuid, udpstats->necp_udp_basic.vuuid, sizeof(desc->euuid));
1735 desc->ifnet_properties = udpstats->necp_udp_basic.ifnet_properties;
1736 }
1737 return true;
1738 }
1739
1740 static int
1741 necp_skywalk_priv_check_cred(proc_t p, kauth_cred_t cred)
1742 {
1743 #pragma unused(p, cred)
1744 return (0);
1745 }
1746
1747 /// System calls
1748
1749 int
1750 necp_open(struct proc *p, struct necp_open_args *uap, int *retval)
1751 {
1752 #pragma unused(retval)
1753 int error = 0;
1754 struct necp_fd_data *fd_data = NULL;
1755 struct fileproc *fp = NULL;
1756 int fd = -1;
1757
1758 if (uap->flags & NECP_OPEN_FLAG_OBSERVER) {
1759 if (necp_skywalk_priv_check_cred(p, kauth_cred_get()) != 0 &&
1760 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NETWORK_STATISTICS, 0) != 0) {
1761 NECPLOG0(LOG_ERR, "Client does not hold necessary entitlement to observe other NECP clients");
1762 error = EACCES;
1763 goto done;
1764 }
1765 }
1766
1767 error = falloc(p, &fp, &fd, vfs_context_current());
1768 if (error != 0) {
1769 goto done;
1770 }
1771
1772 if ((fd_data = _MALLOC(sizeof(struct necp_fd_data), M_NECP,
1773 M_WAITOK | M_ZERO)) == NULL) {
1774 error = ENOMEM;
1775 goto done;
1776 }
1777
1778 fd_data->flags = uap->flags;
1779 LIST_INIT(&fd_data->clients);
1780 lck_mtx_init(&fd_data->fd_lock, necp_fd_mtx_grp, necp_fd_mtx_attr);
1781 klist_init(&fd_data->si.si_note);
1782 fd_data->proc_pid = proc_pid(p);
1783
1784 fp->f_fglob->fg_flag = FREAD;
1785 fp->f_fglob->fg_ops = &necp_fd_ops;
1786 fp->f_fglob->fg_data = fd_data;
1787
1788 proc_fdlock(p);
1789
1790 *fdflags(p, fd) |= (UF_EXCLOSE | UF_FORKCLOSE);
1791 procfdtbl_releasefd(p, fd, NULL);
1792 fp_drop(p, fd, fp, 1);
1793 proc_fdunlock(p);
1794
1795 *retval = fd;
1796
1797 lck_rw_lock_exclusive(&necp_fd_lock);
1798 LIST_INSERT_HEAD(&necp_fd_list, fd_data, chain);
1799 lck_rw_done(&necp_fd_lock);
1800
1801 done:
1802 if (error != 0) {
1803 if (fp != NULL) {
1804 fp_free(p, fd, fp);
1805 fp = NULL;
1806 }
1807 if (fd_data != NULL) {
1808 FREE(fd_data, M_NECP);
1809 fd_data = NULL;
1810 }
1811 }
1812
1813 return (error);
1814 }
1815
1816 static int
1817 necp_client_add(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
1818 {
1819 int error = 0;
1820 struct necp_client *client = NULL;
1821
1822 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t) ||
1823 uap->buffer_size == 0 || uap->buffer_size > NECP_MAX_CLIENT_PARAMETERS_SIZE || uap->buffer == 0) {
1824 error = EINVAL;
1825 goto done;
1826 }
1827
1828 if ((client = _MALLOC(sizeof(struct necp_client) + uap->buffer_size, M_NECP,
1829 M_WAITOK | M_ZERO)) == NULL) {
1830 error = ENOMEM;
1831 goto done;
1832 }
1833
1834 error = copyin(uap->buffer, client->parameters, uap->buffer_size);
1835 if (error) {
1836 NECPLOG(LOG_ERR, "necp_client_add parameters copyin error (%d)", error);
1837 goto done;
1838 }
1839
1840 client->parameters_length = uap->buffer_size;
1841
1842 uuid_generate_random(client->client_id);
1843 LIST_INIT(&client->assertion_list);
1844
1845 error = copyout(client->client_id, uap->client_id, sizeof(uuid_t));
1846 if (error) {
1847 NECPLOG(LOG_ERR, "necp_client_add client_id copyout error (%d)", error);
1848 goto done;
1849 }
1850
1851 lck_mtx_lock(&fd_data->fd_lock);
1852 LIST_INSERT_HEAD(&fd_data->clients, client, chain);
1853
1854 // Prime the client result
1855 (void)necp_update_client_result(current_proc(), client);
1856 lck_mtx_unlock(&fd_data->fd_lock);
1857 done:
1858 if (error != 0) {
1859 if (client != NULL) {
1860 FREE(client, M_NECP);
1861 client = NULL;
1862 }
1863 }
1864 *retval = error;
1865
1866 return (error);
1867 }
1868
1869 static int
1870 necp_client_remove(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
1871 {
1872 int error = 0;
1873 struct necp_client *client = NULL;
1874 struct necp_client *temp_client = NULL;
1875 uuid_t client_id;
1876
1877 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t)) {
1878 error = EINVAL;
1879 goto done;
1880 }
1881
1882 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
1883 if (error) {
1884 NECPLOG(LOG_ERR, "necp_client_remove copyin client_id error (%d)", error);
1885 goto done;
1886 }
1887
1888 lck_mtx_lock(&fd_data->fd_lock);
1889 LIST_FOREACH_SAFE(client, &fd_data->clients, chain, temp_client) {
1890 if (uuid_compare(client->client_id, client_id) == 0) {
1891 necp_destroy_client(client);
1892 }
1893 }
1894 lck_mtx_unlock(&fd_data->fd_lock);
1895 done:
1896 *retval = error;
1897
1898 return (error);
1899 }
1900
1901 static int
1902 necp_client_copy_internal(struct necp_client *client, bool client_is_observed, struct necp_client_action_args *uap, int *retval)
1903 {
1904 int error = 0;
1905 // Copy results out
1906 if (uap->action == NECP_CLIENT_ACTION_COPY_PARAMETERS) {
1907 if (uap->buffer_size < client->parameters_length) {
1908 error = EINVAL;
1909 goto done;
1910 }
1911 error = copyout(client->parameters, uap->buffer, client->parameters_length);
1912 if (error) {
1913 NECPLOG(LOG_ERR, "necp_client_copy parameters copyout error (%d)", error);
1914 goto done;
1915 }
1916 *retval = client->parameters_length;
1917 } else if (uap->action == NECP_CLIENT_ACTION_COPY_RESULT) {
1918 if (uap->buffer_size < (client->result_length + client->assigned_results_length)) {
1919 error = EINVAL;
1920 goto done;
1921 }
1922 error = copyout(client->result, uap->buffer, client->result_length);
1923 if (error) {
1924 NECPLOG(LOG_ERR, "necp_client_copy result copyout error (%d)", error);
1925 goto done;
1926 }
1927 if (client->assigned_results_length && client->assigned_results) {
1928 error = copyout(client->assigned_results, uap->buffer + client->result_length, client->assigned_results_length);
1929 if (error) {
1930 NECPLOG(LOG_ERR, "necp_client_copy assigned results copyout error (%d)", error);
1931 goto done;
1932 }
1933 *retval = client->result_length + client->assigned_results_length;
1934 } else {
1935 *retval = client->result_length;
1936 }
1937
1938 if (!client_is_observed) {
1939 client->result_read = TRUE;
1940 client->assigned_result_read = TRUE;
1941 }
1942 }
1943
1944 done:
1945 return (error);
1946 }
1947
1948 static int
1949 necp_client_copy(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
1950 {
1951 int error = 0;
1952 struct necp_client *find_client = NULL;
1953 struct necp_client *client = NULL;
1954 uuid_t client_id;
1955 uuid_clear(client_id);
1956
1957 *retval = 0;
1958
1959 if (uap->buffer_size == 0 || uap->buffer == 0) {
1960 error = EINVAL;
1961 goto done;
1962 }
1963
1964 if (uap->action != NECP_CLIENT_ACTION_COPY_PARAMETERS &&
1965 uap->action != NECP_CLIENT_ACTION_COPY_RESULT) {
1966 error = EINVAL;
1967 goto done;
1968 }
1969
1970 if (uap->client_id) {
1971 if (uap->client_id_len != sizeof(uuid_t)) {
1972 NECPLOG(LOG_ERR, "Incorrect length (got %d, expected %d)", uap->client_id_len, sizeof(uuid_t));
1973 error = ERANGE;
1974 goto done;
1975 }
1976
1977 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
1978 if (error) {
1979 NECPLOG(LOG_ERR, "necp_client_copy client_id copyin error (%d)", error);
1980 goto done;
1981 }
1982 }
1983
1984 lck_mtx_lock(&fd_data->fd_lock);
1985 LIST_FOREACH(find_client, &fd_data->clients, chain) {
1986 if (uap->action == NECP_CLIENT_ACTION_COPY_RESULT &&
1987 uuid_is_null(client_id)) {
1988 if (!find_client->result_read || !find_client->assigned_result_read) {
1989 client = find_client;
1990 break;
1991 }
1992 } else if (uuid_compare(find_client->client_id, client_id) == 0) {
1993 client = find_client;
1994 break;
1995 }
1996 }
1997
1998 if (client != NULL) {
1999 error = necp_client_copy_internal(client, FALSE, uap, retval);
2000 }
2001
2002 // Unlock our own client before moving on or returning
2003 lck_mtx_unlock(&fd_data->fd_lock);
2004
2005 if (client == NULL) {
2006 if (fd_data->flags & NECP_OPEN_FLAG_OBSERVER) {
2007 // Observers are allowed to lookup clients on other fds
2008
2009 // Lock list
2010 lck_rw_lock_shared(&necp_fd_lock);
2011 struct necp_fd_data *client_fd = NULL;
2012 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
2013 // Lock client
2014 lck_mtx_lock(&client_fd->fd_lock);
2015 find_client = NULL;
2016 LIST_FOREACH(find_client, &client_fd->clients, chain) {
2017 if (uuid_compare(find_client->client_id, client_id) == 0) {
2018 client = find_client;
2019 break;
2020 }
2021 }
2022
2023 if (client != NULL) {
2024 // Matched, copy out data
2025 error = necp_client_copy_internal(client, TRUE, uap, retval);
2026 }
2027
2028 // Unlock client
2029 lck_mtx_unlock(&client_fd->fd_lock);
2030
2031 if (client != NULL) {
2032 break;
2033 }
2034 }
2035
2036 // Unlock list
2037 lck_rw_done(&necp_fd_lock);
2038
2039 // No client found, fail
2040 if (client == NULL) {
2041 error = ENOENT;
2042 goto done;
2043 }
2044 } else {
2045 // No client found, and not allowed to search other fds, fail
2046 error = ENOENT;
2047 goto done;
2048 }
2049 }
2050
2051 done:
2052 return (error);
2053 }
2054
2055 static int
2056 necp_client_list(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2057 {
2058 int error = 0;
2059 struct necp_client *find_client = NULL;
2060 uuid_t *list = NULL;
2061 u_int32_t requested_client_count = 0;
2062 u_int32_t client_count = 0;
2063
2064 if (uap->buffer_size < sizeof(requested_client_count) || uap->buffer == 0) {
2065 error = EINVAL;
2066 goto done;
2067 }
2068
2069 if (!(fd_data->flags & NECP_OPEN_FLAG_OBSERVER)) {
2070 NECPLOG0(LOG_ERR, "Client does not hold necessary entitlement to list other NECP clients");
2071 error = EACCES;
2072 goto done;
2073 }
2074
2075 error = copyin(uap->buffer, &requested_client_count, sizeof(requested_client_count));
2076 if (error) {
2077 goto done;
2078 }
2079
2080 if (uap->buffer_size != (sizeof(requested_client_count) + requested_client_count * sizeof(uuid_t))) {
2081 error = EINVAL;
2082 goto done;
2083 }
2084
2085 if (requested_client_count > 0) {
2086 if ((list = _MALLOC(requested_client_count * sizeof(uuid_t), M_NECP, M_WAITOK | M_ZERO)) == NULL) {
2087 error = ENOMEM;
2088 goto done;
2089 }
2090 }
2091
2092 // Lock list
2093 lck_rw_lock_shared(&necp_fd_lock);
2094 struct necp_fd_data *client_fd = NULL;
2095 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
2096 // Lock client
2097 lck_mtx_lock(&client_fd->fd_lock);
2098 find_client = NULL;
2099 LIST_FOREACH(find_client, &client_fd->clients, chain) {
2100 if (!uuid_is_null(find_client->client_id)) {
2101 if (client_count < requested_client_count) {
2102 uuid_copy(list[client_count], find_client->client_id);
2103 }
2104 client_count++;
2105 }
2106 }
2107 lck_mtx_unlock(&client_fd->fd_lock);
2108 }
2109
2110 // Unlock list
2111 lck_rw_done(&necp_fd_lock);
2112
2113 error = copyout(&client_count, uap->buffer, sizeof(client_count));
2114 if (error) {
2115 NECPLOG(LOG_ERR, "necp_client_list buffer copyout error (%d)", error);
2116 goto done;
2117 }
2118
2119 if (requested_client_count > 0 &&
2120 client_count > 0 &&
2121 list != NULL) {
2122 error = copyout(list, uap->buffer + sizeof(client_count), requested_client_count * sizeof(uuid_t));
2123 if (error) {
2124 NECPLOG(LOG_ERR, "necp_client_list client count copyout error (%d)", error);
2125 goto done;
2126 }
2127 }
2128 done:
2129 if (list != NULL) {
2130 FREE(list, M_NECP);
2131 }
2132 *retval = error;
2133
2134 return (error);
2135 }
2136
2137 static int
2138 necp_client_request_nexus(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2139 {
2140 int error = 0;
2141 struct necp_client *client = NULL;
2142 uuid_t client_id;
2143 bool requested_nexus = FALSE;
2144
2145 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t)) {
2146 error = EINVAL;
2147 goto done;
2148 }
2149
2150 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
2151 if (error) {
2152 NECPLOG(LOG_ERR, "necp_client_request_nexus copyin client_id error (%d)", error);
2153 goto done;
2154 }
2155
2156 lck_mtx_lock(&fd_data->fd_lock);
2157 LIST_FOREACH(client, &fd_data->clients, chain) {
2158 if (uuid_compare(client->client_id, client_id) == 0) {
2159 // Request from nexus agent
2160 if (!uuid_is_null(client->nexus_agent)) {
2161 error = netagent_client_message(client->nexus_agent, client->client_id,
2162 NETAGENT_MESSAGE_TYPE_REQUEST_NEXUS);
2163 if (error == 0) {
2164 requested_nexus = TRUE;
2165 }
2166 }
2167 break;
2168 }
2169 }
2170 lck_mtx_unlock(&fd_data->fd_lock);
2171
2172 if (!requested_nexus &&
2173 error == 0) {
2174 error = ENOENT;
2175 }
2176 done:
2177 *retval = error;
2178
2179 return (error);
2180 }
2181
2182 static void
2183 necp_client_add_assertion(struct necp_client *client, uuid_t netagent_uuid)
2184 {
2185 struct necp_client_assertion *new_assertion = NULL;
2186
2187 MALLOC(new_assertion, struct necp_client_assertion *, sizeof(*new_assertion), M_NECP, M_WAITOK);
2188 if (new_assertion == NULL) {
2189 NECPLOG0(LOG_ERR, "Failed to allocate assertion");
2190 return;
2191 }
2192
2193 uuid_copy(new_assertion->asserted_netagent, netagent_uuid);
2194
2195 LIST_INSERT_HEAD(&client->assertion_list, new_assertion, assertion_chain);
2196 }
2197
2198 static bool
2199 necp_client_remove_assertion(struct necp_client *client, uuid_t netagent_uuid)
2200 {
2201 struct necp_client_assertion *found_assertion = NULL;
2202 struct necp_client_assertion *search_assertion = NULL;
2203 LIST_FOREACH(search_assertion, &client->assertion_list, assertion_chain) {
2204 if (uuid_compare(search_assertion->asserted_netagent, netagent_uuid) == 0) {
2205 found_assertion = search_assertion;
2206 break;
2207 }
2208 }
2209
2210 if (found_assertion == NULL) {
2211 NECPLOG0(LOG_ERR, "Netagent uuid not previously asserted");
2212 return false;
2213 }
2214
2215 LIST_REMOVE(found_assertion, assertion_chain);
2216 FREE(found_assertion, M_NECP);
2217 return true;
2218 }
2219
2220 static int
2221 necp_client_agent_action(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2222 {
2223 int error = 0;
2224 struct necp_client *matched_client = NULL;
2225 struct necp_client *client = NULL;
2226 uuid_t client_id;
2227 bool acted_on_agent = FALSE;
2228 u_int8_t *parameters = NULL;
2229 size_t parameters_size = uap->buffer_size;
2230
2231 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t) ||
2232 uap->buffer_size == 0 || uap->buffer == 0) {
2233 error = EINVAL;
2234 goto done;
2235 }
2236
2237 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
2238 if (error) {
2239 NECPLOG(LOG_ERR, "necp_client_agent_action copyin client_id error (%d)", error);
2240 goto done;
2241 }
2242
2243 if ((parameters = _MALLOC(uap->buffer_size, M_NECP, M_WAITOK | M_ZERO)) == NULL) {
2244 error = ENOMEM;
2245 goto done;
2246 }
2247
2248 error = copyin(uap->buffer, parameters, uap->buffer_size);
2249 if (error) {
2250 NECPLOG(LOG_ERR, "necp_client_agent_action parameters copyin error (%d)", error);
2251 goto done;
2252 }
2253
2254 lck_mtx_lock(&fd_data->fd_lock);
2255 LIST_FOREACH(client, &fd_data->clients, chain) {
2256 if (uuid_compare(client->client_id, client_id) == 0) {
2257 matched_client = client;
2258 break;
2259 }
2260 }
2261 if (matched_client) {
2262 size_t offset = 0;
2263 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
2264 u_int8_t type = necp_buffer_get_tlv_type(parameters, offset);
2265 u_int32_t length = necp_buffer_get_tlv_length(parameters, offset);
2266
2267 if (length > 0 && (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length) <= parameters_size) {
2268 u_int8_t *value = necp_buffer_get_tlv_value(parameters, offset, NULL);
2269 if (length >= sizeof(uuid_t) &&
2270 value != NULL &&
2271 (type == NECP_CLIENT_PARAMETER_TRIGGER_AGENT ||
2272 type == NECP_CLIENT_PARAMETER_ASSERT_AGENT ||
2273 type == NECP_CLIENT_PARAMETER_UNASSERT_AGENT)) {
2274
2275 uuid_t agent_uuid;
2276 uuid_copy(agent_uuid, value);
2277 u_int8_t netagent_message_type = 0;
2278 if (type == NECP_CLIENT_PARAMETER_TRIGGER_AGENT) {
2279 netagent_message_type = NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER;
2280 } else if (type == NECP_CLIENT_PARAMETER_ASSERT_AGENT) {
2281 netagent_message_type = NETAGENT_MESSAGE_TYPE_CLIENT_ASSERT;
2282 } else if (type == NECP_CLIENT_PARAMETER_UNASSERT_AGENT) {
2283 netagent_message_type = NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT;
2284 }
2285
2286 // Before unasserting, verify that the assertion was already taken
2287 if (type == NECP_CLIENT_PARAMETER_UNASSERT_AGENT) {
2288 if (!necp_client_remove_assertion(client, agent_uuid)) {
2289 error = ENOENT;
2290 break;
2291 }
2292 }
2293
2294 error = netagent_client_message(agent_uuid, client_id,
2295 netagent_message_type);
2296 if (error == 0) {
2297 acted_on_agent = TRUE;
2298 } else {
2299 break;
2300 }
2301
2302 // Only save the assertion if the action succeeded
2303 if (type == NECP_CLIENT_PARAMETER_ASSERT_AGENT) {
2304 necp_client_add_assertion(client, agent_uuid);
2305 }
2306 }
2307 }
2308
2309 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
2310 }
2311 }
2312 lck_mtx_unlock(&fd_data->fd_lock);
2313
2314 if (!acted_on_agent &&
2315 error == 0) {
2316 error = ENOENT;
2317 }
2318 done:
2319 *retval = error;
2320 if (parameters != NULL) {
2321 FREE(parameters, M_NECP);
2322 parameters = NULL;
2323 }
2324
2325 return (error);
2326 }
2327
2328 static int
2329 necp_client_copy_agent(__unused struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2330 {
2331 int error = 0;
2332 uuid_t agent_uuid;
2333
2334 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t) ||
2335 uap->buffer_size == 0 || uap->buffer == 0) {
2336 NECPLOG0(LOG_ERR, "necp_client_copy_agent bad input");
2337 error = EINVAL;
2338 goto done;
2339 }
2340
2341 error = copyin(uap->client_id, agent_uuid, sizeof(uuid_t));
2342 if (error) {
2343 NECPLOG(LOG_ERR, "necp_client_copy_agent copyin agent_uuid error (%d)", error);
2344 goto done;
2345 }
2346
2347 error = netagent_copyout(agent_uuid, uap->buffer, uap->buffer_size);
2348 if (error) {
2349 NECPLOG(LOG_ERR, "necp_client_copy_agent netagent_copyout error (%d)", error);
2350 goto done;
2351 }
2352 done:
2353 *retval = error;
2354
2355 return (error);
2356 }
2357
2358 static int
2359 necp_client_copy_interface(__unused struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2360 {
2361 int error = 0;
2362 u_int32_t interface_index = 0;
2363 struct necp_interface_details interface_details;
2364
2365 if (uap->client_id == 0 || uap->client_id_len != sizeof(u_int32_t) ||
2366 uap->buffer_size < sizeof(interface_details) || uap->buffer == 0) {
2367 NECPLOG0(LOG_ERR, "necp_client_copy_interface bad input");
2368 error = EINVAL;
2369 goto done;
2370 }
2371
2372 error = copyin(uap->client_id, &interface_index, sizeof(u_int32_t));
2373 if (error) {
2374 NECPLOG(LOG_ERR, "necp_client_copy_interface copyin interface_index error (%d)", error);
2375 goto done;
2376 }
2377
2378 if (interface_index == 0) {
2379 error = ENOENT;
2380 NECPLOG(LOG_ERR, "necp_client_copy_interface bad interface_index (%d)", interface_index);
2381 goto done;
2382 }
2383
2384 memset(&interface_details, 0, sizeof(interface_details));
2385
2386 ifnet_head_lock_shared();
2387 ifnet_t interface = NULL;
2388 if (interface_index != IFSCOPE_NONE && (int)interface_index <= if_index) {
2389 interface = ifindex2ifnet[interface_index];
2390 }
2391
2392 if (interface != NULL) {
2393 if (interface->if_xname != NULL) {
2394 strlcpy((char *)&interface_details.name, interface->if_xname, sizeof(interface_details.name));
2395 }
2396 interface_details.index = interface->if_index;
2397 interface_details.generation = ifnet_get_generation(interface);
2398 if (interface->if_delegated.ifp != NULL) {
2399 interface_details.delegate_index = interface->if_delegated.ifp->if_index;
2400 }
2401 interface_details.functional_type = if_functional_type(interface, TRUE);
2402 if (IFNET_IS_EXPENSIVE(interface)) {
2403 interface_details.flags |= NECP_INTERFACE_FLAG_EXPENSIVE;
2404 }
2405 interface_details.mtu = interface->if_mtu;
2406
2407 u_int8_t ipv4_signature_len = sizeof(interface_details.ipv4_signature);
2408 u_int16_t ipv4_signature_flags;
2409 ifnet_get_netsignature(interface, AF_INET, &ipv4_signature_len, &ipv4_signature_flags,
2410 (u_int8_t *)&interface_details.ipv4_signature);
2411
2412 u_int8_t ipv6_signature_len = sizeof(interface_details.ipv6_signature);
2413 u_int16_t ipv6_signature_flags;
2414 ifnet_get_netsignature(interface, AF_INET6, &ipv6_signature_len, &ipv6_signature_flags,
2415 (u_int8_t *)&interface_details.ipv6_signature);
2416 }
2417
2418 ifnet_head_done();
2419
2420 error = copyout(&interface_details, uap->buffer, sizeof(interface_details));
2421 if (error) {
2422 NECPLOG(LOG_ERR, "necp_client_copy_interface copyout error (%d)", error);
2423 goto done;
2424 }
2425 done:
2426 *retval = error;
2427
2428 return (error);
2429 }
2430
2431 static int
2432 necp_client_stats_action(struct necp_client *client, user_addr_t buffer, user_size_t buffer_size)
2433 {
2434 int error = 0;
2435 struct necp_stats_hdr *stats_hdr = NULL;
2436
2437 if (client->stats_area) {
2438 // Close old stats if required.
2439 if ((client->stats_uaddr != buffer) || (client->stats_ulen != buffer_size)) {
2440 necp_destroy_client_stats(client);
2441 }
2442 }
2443
2444 if ((buffer == 0) || (buffer_size == 0)) {
2445 goto done;
2446 }
2447
2448 if (client->stats_area) {
2449 // An update
2450 error = copyin(client->stats_uaddr, client->stats_area, client->stats_ulen);
2451 if (error) {
2452 NECPLOG(LOG_ERR, "necp_client_stats_action copyin error on update (%d)", error);
2453 } else {
2454 // Future use - check
2455 stats_hdr = (necp_stats_hdr *)client->stats_area;
2456 if (stats_hdr->necp_stats_event != 0) {
2457 ntstat_userland_stats_event(client->stats_handler_context, (userland_stats_event_t)stats_hdr->necp_stats_event);
2458 }
2459 }
2460 goto done;
2461 }
2462
2463 // A create
2464 if ((buffer_size > sizeof(necp_all_stats)) || (buffer_size < sizeof(necp_stats_hdr))) {
2465 error = EINVAL;
2466 goto done;
2467 }
2468
2469 if ((stats_hdr = _MALLOC(buffer_size, M_NECP, M_WAITOK | M_ZERO)) == NULL) {
2470 error = ENOMEM;
2471 goto done;
2472 }
2473
2474 client->stats_handler_context = NULL;
2475 client->stats_uaddr = buffer;
2476 client->stats_ulen = buffer_size;
2477 client->stats_area = stats_hdr;
2478 error = copyin(client->stats_uaddr, client->stats_area, client->stats_ulen);
2479 if (error) {
2480 NECPLOG(LOG_ERR, "necp_client_stats_action copyin error on create (%d)", error);
2481 goto done;
2482 }
2483
2484 switch (stats_hdr->necp_stats_type) {
2485 case NECP_CLIENT_STATISTICS_TYPE_TCP: {
2486 if (stats_hdr->necp_stats_ver == NECP_CLIENT_STATISTICS_TYPE_TCP_VER_1) {
2487 client->stats_handler_context = ntstat_userland_stats_open((userland_stats_provider_context *)client,
2488 NSTAT_PROVIDER_TCP_USERLAND, 0, necp_request_tcp_netstats);
2489 if (client->stats_handler_context == NULL) {
2490 error = EIO;
2491 }
2492 } else {
2493 error = ENOTSUP;
2494 }
2495 break;
2496 }
2497 case NECP_CLIENT_STATISTICS_TYPE_UDP: {
2498 if (stats_hdr->necp_stats_ver != NECP_CLIENT_STATISTICS_TYPE_UDP_VER_1) {
2499 client->stats_handler_context = ntstat_userland_stats_open((userland_stats_provider_context *)client,
2500 NSTAT_PROVIDER_UDP_USERLAND, 0, necp_request_udp_netstats);
2501 if (client->stats_handler_context == NULL) {
2502 error = EIO;
2503 }
2504 } else {
2505 error = ENOTSUP;
2506 }
2507 break;
2508 }
2509 default: {
2510 error = ENOTSUP;
2511 break;
2512 }
2513 }
2514 done:
2515 if ((error) && (stats_hdr != NULL)) {
2516 FREE(stats_hdr, M_NECP);
2517 client->stats_area = NULL;
2518 client->stats_handler_context = NULL;
2519 client->stats_uaddr = 0;
2520 client->stats_ulen = 0;
2521 }
2522
2523 return (error);
2524 }
2525
2526 static int
2527 necp_client_set_statistics(__unused struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
2528 {
2529 int error = 0;
2530 struct necp_client *find_client = NULL;
2531 struct necp_client *client = NULL;
2532 uuid_t client_id;
2533
2534 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t)) {
2535 error = EINVAL;
2536 goto done;
2537 }
2538
2539 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
2540 if (error) {
2541 NECPLOG(LOG_ERR, "necp_client_set_statistics copyin client_id error (%d)", error);
2542 goto done;
2543 }
2544
2545 lck_mtx_lock(&fd_data->fd_lock);
2546 LIST_FOREACH(find_client, &fd_data->clients, chain) {
2547 if (uuid_compare(find_client->client_id, client_id) == 0) {
2548 client = find_client;
2549 break;
2550 }
2551 }
2552
2553 if (client) {
2554 error = necp_client_stats_action(client, uap->buffer, uap->buffer_size);
2555 } else {
2556 error = ENOENT;
2557 }
2558 lck_mtx_unlock(&fd_data->fd_lock);
2559 done:
2560 *retval = error;
2561 return (error);
2562 }
2563
2564 int
2565 necp_client_action(struct proc *p, struct necp_client_action_args *uap, int *retval)
2566 {
2567 #pragma unused(p)
2568 int error = 0;
2569 int return_value = 0;
2570 struct necp_fd_data *fd_data = NULL;
2571 error = necp_find_fd_data(uap->necp_fd, &fd_data);
2572 if (error != 0) {
2573 NECPLOG(LOG_ERR, "necp_client_action find fd error (%d)", error);
2574 return (error);
2575 }
2576
2577 u_int32_t action = uap->action;
2578 switch (action) {
2579 case NECP_CLIENT_ACTION_ADD: {
2580 return_value = necp_client_add(fd_data, uap, retval);
2581 break;
2582 }
2583 case NECP_CLIENT_ACTION_REMOVE: {
2584 return_value = necp_client_remove(fd_data, uap, retval);
2585 break;
2586 }
2587 case NECP_CLIENT_ACTION_COPY_PARAMETERS:
2588 case NECP_CLIENT_ACTION_COPY_RESULT: {
2589 return_value = necp_client_copy(fd_data, uap, retval);
2590 break;
2591 }
2592 case NECP_CLIENT_ACTION_COPY_LIST: {
2593 return_value = necp_client_list(fd_data, uap, retval);
2594 break;
2595 }
2596 case NECP_CLIENT_ACTION_REQUEST_NEXUS_INSTANCE: {
2597 return_value = necp_client_request_nexus(fd_data, uap, retval);
2598 break;
2599 }
2600 case NECP_CLIENT_ACTION_AGENT: {
2601 return_value = necp_client_agent_action(fd_data, uap, retval);
2602 break;
2603 }
2604 case NECP_CLIENT_ACTION_COPY_AGENT: {
2605 return_value = necp_client_copy_agent(fd_data, uap, retval);
2606 break;
2607 }
2608 case NECP_CLIENT_ACTION_COPY_INTERFACE: {
2609 return_value = necp_client_copy_interface(fd_data, uap, retval);
2610 break;
2611 }
2612 case NECP_CLIENT_ACTION_SET_STATISTICS: {
2613 return_value = necp_client_set_statistics(fd_data, uap, retval);
2614 break;
2615 }
2616 default: {
2617 NECPLOG(LOG_ERR, "necp_client_action unknown action (%u)", action);
2618 return_value = EINVAL;
2619 break;
2620 }
2621 }
2622
2623 file_drop(uap->necp_fd);
2624
2625 return (return_value);
2626 }
2627
2628 #define NECP_MAX_MATCH_POLICY_PARAMETER_SIZE 1024
2629
2630 int
2631 necp_match_policy(struct proc *p, struct necp_match_policy_args *uap, int32_t *retval)
2632 {
2633 #pragma unused(retval)
2634 u_int8_t *parameters = NULL;
2635 struct necp_aggregate_result returned_result;
2636 int error = 0;
2637
2638 if (uap == NULL) {
2639 error = EINVAL;
2640 goto done;
2641 }
2642
2643 if (uap->parameters == 0 || uap->parameters_size == 0 || uap->parameters_size > NECP_MAX_MATCH_POLICY_PARAMETER_SIZE || uap->returned_result == 0) {
2644 error = EINVAL;
2645 goto done;
2646 }
2647
2648 MALLOC(parameters, u_int8_t *, uap->parameters_size, M_NECP, M_WAITOK | M_ZERO);
2649 if (parameters == NULL) {
2650 error = ENOMEM;
2651 goto done;
2652 }
2653 // Copy parameters in
2654 error = copyin(uap->parameters, parameters, uap->parameters_size);
2655 if (error) {
2656 goto done;
2657 }
2658
2659 error = necp_application_find_policy_match_internal(p, parameters, uap->parameters_size, &returned_result, NULL, 0);
2660 if (error) {
2661 goto done;
2662 }
2663
2664 // Copy return value back
2665 error = copyout(&returned_result, uap->returned_result, sizeof(struct necp_aggregate_result));
2666 if (error) {
2667 goto done;
2668 }
2669 done:
2670 if (parameters != NULL) {
2671 FREE(parameters, M_NECP);
2672 }
2673 return (error);
2674 }
2675
2676 /// Socket operations
2677 #define NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH 253
2678
2679 static bool
2680 necp_set_socket_attribute(u_int8_t *buffer, size_t buffer_length, u_int8_t type, char **buffer_p)
2681 {
2682 int error = 0;
2683 int cursor = 0;
2684 size_t string_size = 0;
2685 char *local_string = NULL;
2686 u_int8_t *value = NULL;
2687
2688 cursor = necp_buffer_find_tlv(buffer, buffer_length, 0, type, 0);
2689 if (cursor < 0) {
2690 // This will clear out the parameter
2691 goto done;
2692 }
2693
2694 string_size = necp_buffer_get_tlv_length(buffer, cursor);
2695 if (string_size == 0 || string_size > NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH) {
2696 // This will clear out the parameter
2697 goto done;
2698 }
2699
2700 MALLOC(local_string, char *, string_size + 1, M_NECP, M_WAITOK | M_ZERO);
2701 if (local_string == NULL) {
2702 NECPLOG(LOG_ERR, "Failed to allocate a socket attribute buffer (size %d)", string_size);
2703 goto fail;
2704 }
2705
2706 value = necp_buffer_get_tlv_value(buffer, cursor, NULL);
2707 if (value == NULL) {
2708 NECPLOG0(LOG_ERR, "Failed to get socket attribute");
2709 goto fail;
2710 }
2711
2712 memcpy(local_string, value, string_size);
2713 local_string[string_size] = 0;
2714
2715 done:
2716 if (*buffer_p != NULL) {
2717 FREE(*buffer_p, M_NECP);
2718 *buffer_p = NULL;
2719 }
2720
2721 *buffer_p = local_string;
2722 return (0);
2723 fail:
2724 if (local_string != NULL) {
2725 FREE(local_string, M_NECP);
2726 }
2727 return (error);
2728 }
2729
2730 errno_t
2731 necp_set_socket_attributes(struct socket *so, struct sockopt *sopt)
2732 {
2733 int error = 0;
2734 u_int8_t *buffer = NULL;
2735 struct inpcb *inp = NULL;
2736
2737 if ((SOCK_DOM(so) != PF_INET
2738 #if INET6
2739 && SOCK_DOM(so) != PF_INET6
2740 #endif
2741 )) {
2742 error = EINVAL;
2743 goto done;
2744 }
2745
2746 inp = sotoinpcb(so);
2747
2748 size_t valsize = sopt->sopt_valsize;
2749 if (valsize == 0 ||
2750 valsize > ((sizeof(u_int8_t) + sizeof(u_int32_t) + NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH) * 2)) {
2751 goto done;
2752 }
2753
2754 MALLOC(buffer, u_int8_t *, valsize, M_NECP, M_WAITOK | M_ZERO);
2755 if (buffer == NULL) {
2756 goto done;
2757 }
2758
2759 error = sooptcopyin(sopt, buffer, valsize, 0);
2760 if (error) {
2761 goto done;
2762 }
2763
2764 error = necp_set_socket_attribute(buffer, valsize, NECP_TLV_ATTRIBUTE_DOMAIN, &inp->inp_necp_attributes.inp_domain);
2765 if (error) {
2766 NECPLOG0(LOG_ERR, "Could not set domain TLV for socket attributes");
2767 goto done;
2768 }
2769
2770 error = necp_set_socket_attribute(buffer, valsize, NECP_TLV_ATTRIBUTE_ACCOUNT, &inp->inp_necp_attributes.inp_account);
2771 if (error) {
2772 NECPLOG0(LOG_ERR, "Could not set account TLV for socket attributes");
2773 goto done;
2774 }
2775
2776 if (necp_debug) {
2777 NECPLOG(LOG_DEBUG, "Set on socket: Domain %s, Account %s", inp->inp_necp_attributes.inp_domain, inp->inp_necp_attributes.inp_account);
2778 }
2779 done:
2780 if (buffer != NULL) {
2781 FREE(buffer, M_NECP);
2782 }
2783
2784 return (error);
2785 }
2786
2787 errno_t
2788 necp_get_socket_attributes(struct socket *so, struct sockopt *sopt)
2789 {
2790 int error = 0;
2791 u_int8_t *buffer = NULL;
2792 u_int8_t *cursor = NULL;
2793 size_t valsize = 0;
2794 struct inpcb *inp = sotoinpcb(so);
2795
2796 if (inp->inp_necp_attributes.inp_domain != NULL) {
2797 valsize += sizeof(u_int8_t) + sizeof(u_int32_t) + strlen(inp->inp_necp_attributes.inp_domain);
2798 }
2799 if (inp->inp_necp_attributes.inp_account != NULL) {
2800 valsize += sizeof(u_int8_t) + sizeof(u_int32_t) + strlen(inp->inp_necp_attributes.inp_account);
2801 }
2802 if (valsize == 0) {
2803 goto done;
2804 }
2805
2806 MALLOC(buffer, u_int8_t *, valsize, M_NECP, M_WAITOK | M_ZERO);
2807 if (buffer == NULL) {
2808 goto done;
2809 }
2810
2811 cursor = buffer;
2812 if (inp->inp_necp_attributes.inp_domain != NULL) {
2813 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ATTRIBUTE_DOMAIN, strlen(inp->inp_necp_attributes.inp_domain), inp->inp_necp_attributes.inp_domain);
2814 }
2815
2816 if (inp->inp_necp_attributes.inp_account != NULL) {
2817 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ATTRIBUTE_ACCOUNT, strlen(inp->inp_necp_attributes.inp_account), inp->inp_necp_attributes.inp_account);
2818 }
2819
2820 error = sooptcopyout(sopt, buffer, valsize);
2821 if (error) {
2822 goto done;
2823 }
2824 done:
2825 if (buffer != NULL) {
2826 FREE(buffer, M_NECP);
2827 }
2828
2829 return (error);
2830 }
2831
2832 void
2833 necp_inpcb_dispose(struct inpcb *inp)
2834 {
2835 if (inp->inp_necp_attributes.inp_domain != NULL) {
2836 FREE(inp->inp_necp_attributes.inp_domain, M_NECP);
2837 inp->inp_necp_attributes.inp_domain = NULL;
2838 }
2839 if (inp->inp_necp_attributes.inp_account != NULL) {
2840 FREE(inp->inp_necp_attributes.inp_account, M_NECP);
2841 inp->inp_necp_attributes.inp_account = NULL;
2842 }
2843 }
2844
2845 /// Module init
2846
2847 errno_t
2848 necp_client_init(void)
2849 {
2850 errno_t result = 0;
2851
2852 necp_fd_grp_attr = lck_grp_attr_alloc_init();
2853 if (necp_fd_grp_attr == NULL) {
2854 NECPLOG0(LOG_ERR, "lck_grp_attr_alloc_init failed");
2855 result = ENOMEM;
2856 goto done;
2857 }
2858
2859 necp_fd_mtx_grp = lck_grp_alloc_init("necp_fd", necp_fd_grp_attr);
2860 if (necp_fd_mtx_grp == NULL) {
2861 NECPLOG0(LOG_ERR, "lck_grp_alloc_init failed");
2862 result = ENOMEM;
2863 goto done;
2864 }
2865
2866 necp_fd_mtx_attr = lck_attr_alloc_init();
2867 if (necp_fd_mtx_attr == NULL) {
2868 NECPLOG0(LOG_ERR, "lck_attr_alloc_init failed");
2869 result = ENOMEM;
2870 goto done;
2871 }
2872
2873 necp_client_tcall = thread_call_allocate(necp_update_all_clients_callout, NULL);
2874 if (necp_client_tcall == NULL) {
2875 NECPLOG0(LOG_ERR, "thread_call_allocate failed");
2876 result = ENOMEM;
2877 goto done;
2878 }
2879
2880 lck_rw_init(&necp_fd_lock, necp_fd_mtx_grp, necp_fd_mtx_attr);
2881
2882 LIST_INIT(&necp_fd_list);
2883
2884 done:
2885 if (result != 0) {
2886 if (necp_fd_mtx_attr != NULL) {
2887 lck_attr_free(necp_fd_mtx_attr);
2888 necp_fd_mtx_attr = NULL;
2889 }
2890 if (necp_fd_mtx_grp != NULL) {
2891 lck_grp_free(necp_fd_mtx_grp);
2892 necp_fd_mtx_grp = NULL;
2893 }
2894 if (necp_fd_grp_attr != NULL) {
2895 lck_grp_attr_free(necp_fd_grp_attr);
2896 necp_fd_grp_attr = NULL;
2897 }
2898 }
2899 return (result);
2900 }