xnu-2782.30.5.tar.gz
[apple/xnu.git] / bsd / netinet / flow_divert.c
CommitLineData
39236c6e 1/*
fe8ab488 2 * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
39236c6e
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <string.h>
30#include <sys/types.h>
31#include <sys/syslog.h>
32#include <sys/queue.h>
33#include <sys/malloc.h>
34#include <sys/socket.h>
35#include <sys/kpi_mbuf.h>
36#include <sys/mbuf.h>
37#include <sys/domain.h>
38#include <sys/protosw.h>
39#include <sys/socketvar.h>
40#include <sys/kernel.h>
41#include <sys/systm.h>
42#include <sys/kern_control.h>
43#include <sys/ubc.h>
44#include <sys/codesign.h>
45#include <libkern/tree.h>
46#include <kern/locks.h>
47#include <kern/debug.h>
48#include <net/if_var.h>
49#include <net/route.h>
50#include <net/flowhash.h>
51#include <net/ntstat.h>
52#include <netinet/in.h>
53#include <netinet/in_var.h>
54#include <netinet/tcp.h>
55#include <netinet/tcp_var.h>
56#include <netinet/tcp_fsm.h>
57#include <netinet/flow_divert.h>
58#include <netinet/flow_divert_proto.h>
59#if INET6
60#include <netinet6/ip6protosw.h>
61#endif /* INET6 */
62#include <dev/random/randomdev.h>
63#include <libkern/crypto/sha1.h>
64#include <libkern/crypto/crypto_internal.h>
65
66#define FLOW_DIVERT_CONNECT_STARTED 0x00000001
67#define FLOW_DIVERT_READ_CLOSED 0x00000002
68#define FLOW_DIVERT_WRITE_CLOSED 0x00000004
69#define FLOW_DIVERT_TUNNEL_RD_CLOSED 0x00000008
70#define FLOW_DIVERT_TUNNEL_WR_CLOSED 0x00000010
71#define FLOW_DIVERT_TRANSFERRED 0x00000020
72
73#define FDLOG(level, pcb, format, ...) do { \
74 if (level <= (pcb)->log_level) { \
75 log((level > LOG_NOTICE ? LOG_NOTICE : level), "%s (%u): " format "\n", __FUNCTION__, (pcb)->hash, __VA_ARGS__); \
76 } \
77} while (0)
78
79#define FDLOG0(level, pcb, msg) do { \
80 if (level <= (pcb)->log_level) { \
81 log((level > LOG_NOTICE ? LOG_NOTICE : level), "%s (%u): %s\n", __FUNCTION__, (pcb)->hash, msg); \
82 } \
83} while (0)
84
85#define FDRETAIN(pcb) if ((pcb) != NULL) OSIncrementAtomic(&(pcb)->ref_count)
86#define FDRELEASE(pcb) \
87 do { \
88 if ((pcb) != NULL && 1 == OSDecrementAtomic(&(pcb)->ref_count)) { \
89 flow_divert_pcb_destroy(pcb); \
90 } \
91 } while (0)
92
93#define FDLOCK(pcb) lck_mtx_lock(&(pcb)->mtx)
94#define FDUNLOCK(pcb) lck_mtx_unlock(&(pcb)->mtx)
95
96#define FD_CTL_SENDBUFF_SIZE (2 * FLOW_DIVERT_CHUNK_SIZE)
97#define FD_CTL_RCVBUFF_SIZE (128 * 1024)
98
99#define GROUP_BIT_CTL_ENQUEUE_BLOCKED 0
100
101#define GROUP_COUNT_MAX 32
102#define FLOW_DIVERT_MAX_NAME_SIZE 4096
103#define FLOW_DIVERT_MAX_KEY_SIZE 1024
104
105#define DNS_SERVICE_GROUP_UNIT (GROUP_COUNT_MAX + 1)
106
107struct flow_divert_trie_node
108{
109 uint16_t start;
110 uint16_t length;
111 uint16_t child_map;
112 uint32_t group_unit;
113};
114
115struct flow_divert_trie
116{
117 struct flow_divert_trie_node *nodes;
118 uint16_t *child_maps;
119 uint8_t *bytes;
120 void *memory;
121 size_t nodes_count;
122 size_t child_maps_count;
123 size_t bytes_count;
124 size_t nodes_free_next;
125 size_t child_maps_free_next;
126 size_t bytes_free_next;
127 uint16_t root;
128};
129
130#define CHILD_MAP_SIZE 256
131#define NULL_TRIE_IDX 0xffff
132#define TRIE_NODE(t, i) ((t)->nodes[(i)])
133#define TRIE_CHILD(t, i, b) (((t)->child_maps + (CHILD_MAP_SIZE * TRIE_NODE(t, i).child_map))[(b)])
134#define TRIE_BYTE(t, i) ((t)->bytes[(i)])
135
136static struct flow_divert_pcb nil_pcb;
137
138decl_lck_rw_data(static, g_flow_divert_group_lck);
139static struct flow_divert_group **g_flow_divert_groups = NULL;
140static uint32_t g_active_group_count = 0;
141static struct flow_divert_trie g_signing_id_trie;
142
143static lck_grp_attr_t *flow_divert_grp_attr = NULL;
144static lck_attr_t *flow_divert_mtx_attr = NULL;
145static lck_grp_t *flow_divert_mtx_grp = NULL;
146static errno_t g_init_result = 0;
147
148static kern_ctl_ref g_flow_divert_kctl_ref = NULL;
149
150static struct protosw g_flow_divert_in_protosw;
151static struct pr_usrreqs g_flow_divert_in_usrreqs;
152#if INET6
153static struct ip6protosw g_flow_divert_in6_protosw;
154static struct pr_usrreqs g_flow_divert_in6_usrreqs;
155#endif /* INET6 */
156
157static struct protosw *g_tcp_protosw = NULL;
158static struct ip6protosw *g_tcp6_protosw = NULL;
159
160static inline int
161flow_divert_pcb_cmp(const struct flow_divert_pcb *pcb_a, const struct flow_divert_pcb *pcb_b)
162{
163 return memcmp(&pcb_a->hash, &pcb_b->hash, sizeof(pcb_a->hash));
164}
165
166RB_PROTOTYPE(fd_pcb_tree, flow_divert_pcb, rb_link, flow_divert_pcb_cmp);
167RB_GENERATE(fd_pcb_tree, flow_divert_pcb, rb_link, flow_divert_pcb_cmp);
168
169static const char *
170flow_divert_packet_type2str(uint8_t packet_type)
171{
172 switch (packet_type) {
173 case FLOW_DIVERT_PKT_CONNECT:
174 return "connect";
175 case FLOW_DIVERT_PKT_CONNECT_RESULT:
176 return "connect result";
177 case FLOW_DIVERT_PKT_DATA:
178 return "data";
179 case FLOW_DIVERT_PKT_CLOSE:
180 return "close";
181 case FLOW_DIVERT_PKT_READ_NOTIFY:
182 return "read notification";
183 case FLOW_DIVERT_PKT_PROPERTIES_UPDATE:
184 return "properties update";
185 case FLOW_DIVERT_PKT_APP_MAP_UPDATE:
186 return "app map update";
187 case FLOW_DIVERT_PKT_APP_MAP_CREATE:
188 return "app map create";
189 default:
190 return "unknown";
191 }
192}
193
194static struct flow_divert_pcb *
195flow_divert_pcb_lookup(uint32_t hash, struct flow_divert_group *group)
196{
197 struct flow_divert_pcb key_item;
198 struct flow_divert_pcb *fd_cb = NULL;
199
200 key_item.hash = hash;
201
202 lck_rw_lock_shared(&group->lck);
203 fd_cb = RB_FIND(fd_pcb_tree, &group->pcb_tree, &key_item);
204 FDRETAIN(fd_cb);
205 lck_rw_done(&group->lck);
206
207 return fd_cb;
208}
209
210static errno_t
211flow_divert_pcb_insert(struct flow_divert_pcb *fd_cb, uint32_t ctl_unit)
212{
213 int error = 0;
214 struct flow_divert_pcb *exist = NULL;
215 struct flow_divert_group *group;
216 static uint32_t g_nextkey = 1;
217 static uint32_t g_hash_seed = 0;
218 errno_t result = 0;
219 int try_count = 0;
220
221 if (ctl_unit == 0 || ctl_unit >= GROUP_COUNT_MAX) {
222 return EINVAL;
223 }
224
225 socket_unlock(fd_cb->so, 0);
226 lck_rw_lock_shared(&g_flow_divert_group_lck);
227
228 if (g_flow_divert_groups == NULL || g_active_group_count == 0) {
229 FDLOG0(LOG_ERR, &nil_pcb, "No active groups, flow divert cannot be used for this socket");
230 error = ENETUNREACH;
231 goto done;
232 }
233
234 group = g_flow_divert_groups[ctl_unit];
235 if (group == NULL) {
236 FDLOG(LOG_ERR, &nil_pcb, "Group for control unit %u is NULL, flow divert cannot be used for this socket", ctl_unit);
237 error = ENETUNREACH;
238 goto done;
239 }
240
241 socket_lock(fd_cb->so, 0);
242
243 do {
244 uint32_t key[2];
245 uint32_t idx;
246
247 key[0] = g_nextkey++;
248 key[1] = RandomULong();
249
250 if (g_hash_seed == 0) {
251 g_hash_seed = RandomULong();
252 }
253
254 fd_cb->hash = net_flowhash(key, sizeof(key), g_hash_seed);
255
256 for (idx = 1; idx < GROUP_COUNT_MAX; idx++) {
257 struct flow_divert_group *curr_group = g_flow_divert_groups[idx];
258 if (curr_group != NULL && curr_group != group) {
259 lck_rw_lock_shared(&curr_group->lck);
260 exist = RB_FIND(fd_pcb_tree, &curr_group->pcb_tree, fd_cb);
261 lck_rw_done(&curr_group->lck);
262 if (exist != NULL) {
263 break;
264 }
265 }
266 }
267
268 if (exist == NULL) {
269 lck_rw_lock_exclusive(&group->lck);
270 exist = RB_INSERT(fd_pcb_tree, &group->pcb_tree, fd_cb);
271 lck_rw_done(&group->lck);
272 }
273 } while (exist != NULL && try_count++ < 3);
274
275 if (exist == NULL) {
276 fd_cb->group = group;
277 FDRETAIN(fd_cb); /* The group now has a reference */
278 } else {
279 fd_cb->hash = 0;
280 result = EEXIST;
281 }
282
283 socket_unlock(fd_cb->so, 0);
284
285done:
286 lck_rw_done(&g_flow_divert_group_lck);
287 socket_lock(fd_cb->so, 0);
288
289 return result;
290}
291
292static struct flow_divert_pcb *
293flow_divert_pcb_create(socket_t so)
294{
295 struct flow_divert_pcb *new_pcb = NULL;
296
297 MALLOC_ZONE(new_pcb, struct flow_divert_pcb *, sizeof(*new_pcb), M_FLOW_DIVERT_PCB, M_WAITOK);
298 if (new_pcb == NULL) {
299 FDLOG0(LOG_ERR, &nil_pcb, "failed to allocate a pcb");
300 return NULL;
301 }
302
303 memset(new_pcb, 0, sizeof(*new_pcb));
304
305 lck_mtx_init(&new_pcb->mtx, flow_divert_mtx_grp, flow_divert_mtx_attr);
306 new_pcb->so = so;
307 new_pcb->log_level = nil_pcb.log_level;
308
309 FDRETAIN(new_pcb); /* Represents the socket's reference */
310
311 return new_pcb;
312}
313
314static void
315flow_divert_pcb_destroy(struct flow_divert_pcb *fd_cb)
316{
317 FDLOG(LOG_INFO, fd_cb, "Destroying, app tx %u, app rx %u, tunnel tx %u, tunnel rx %u",
318 fd_cb->bytes_written_by_app, fd_cb->bytes_read_by_app, fd_cb->bytes_sent, fd_cb->bytes_received);
319
320 if (fd_cb->local_address != NULL) {
321 FREE(fd_cb->local_address, M_SONAME);
322 }
323 if (fd_cb->remote_address != NULL) {
324 FREE(fd_cb->remote_address, M_SONAME);
325 }
326 if (fd_cb->connect_token != NULL) {
327 mbuf_freem(fd_cb->connect_token);
328 }
329 FREE_ZONE(fd_cb, sizeof(*fd_cb), M_FLOW_DIVERT_PCB);
330}
331
332static void
333flow_divert_pcb_remove(struct flow_divert_pcb *fd_cb)
334{
335 if (fd_cb->group != NULL) {
336 struct flow_divert_group *group = fd_cb->group;
337 lck_rw_lock_exclusive(&group->lck);
338 FDLOG(LOG_INFO, fd_cb, "Removing from group %d, ref count = %d", group->ctl_unit, fd_cb->ref_count);
339 RB_REMOVE(fd_pcb_tree, &group->pcb_tree, fd_cb);
340 fd_cb->group = NULL;
341 FDRELEASE(fd_cb); /* Release the group's reference */
342 lck_rw_done(&group->lck);
343 }
344}
345
346static int
347flow_divert_packet_init(struct flow_divert_pcb *fd_cb, uint8_t packet_type, mbuf_t *packet)
348{
349 struct flow_divert_packet_header hdr;
350 int error = 0;
351
352 error = mbuf_gethdr(MBUF_DONTWAIT, MBUF_TYPE_HEADER, packet);
353 if (error) {
354 FDLOG(LOG_ERR, fd_cb, "failed to allocate the header mbuf: %d", error);
355 return error;
356 }
357
358 hdr.packet_type = packet_type;
359 hdr.conn_id = htonl(fd_cb->hash);
360
361 /* Lay down the header */
362 error = mbuf_copyback(*packet, 0, sizeof(hdr), &hdr, MBUF_DONTWAIT);
363 if (error) {
364 FDLOG(LOG_ERR, fd_cb, "mbuf_copyback(hdr) failed: %d", error);
365 mbuf_freem(*packet);
366 *packet = NULL;
367 return error;
368 }
369
370 return 0;
371}
372
373static int
374flow_divert_packet_append_tlv(mbuf_t packet, uint8_t type, size_t length, const void *value)
375{
376 size_t net_length = htonl(length);
377 int error = 0;
378
379 error = mbuf_copyback(packet, mbuf_pkthdr_len(packet), sizeof(type), &type, MBUF_DONTWAIT);
380 if (error) {
381 FDLOG(LOG_ERR, &nil_pcb, "failed to append the type (%d)", type);
382 return error;
383 }
384
385 error = mbuf_copyback(packet, mbuf_pkthdr_len(packet), sizeof(net_length), &net_length, MBUF_DONTWAIT);
386 if (error) {
387 FDLOG(LOG_ERR, &nil_pcb, "failed to append the length (%lu)", length);
388 return error;
389 }
390
391 error = mbuf_copyback(packet, mbuf_pkthdr_len(packet), length, value, MBUF_DONTWAIT);
392 if (error) {
393 FDLOG0(LOG_ERR, &nil_pcb, "failed to append the value");
394 return error;
395 }
396
397 return error;
398}
399
400static int
401flow_divert_packet_find_tlv(mbuf_t packet, int offset, uint8_t type, int *err, int next)
402{
403 size_t cursor = offset;
404 int error = 0;
405 size_t curr_length;
406 uint8_t curr_type;
407
408 *err = 0;
409
410 do {
411 if (!next) {
412 error = mbuf_copydata(packet, cursor, sizeof(curr_type), &curr_type);
413 if (error) {
414 *err = ENOENT;
415 return -1;
416 }
417 } else {
418 next = 0;
419 curr_type = FLOW_DIVERT_TLV_NIL;
420 }
421
422 if (curr_type != type) {
423 cursor += sizeof(curr_type);
424 error = mbuf_copydata(packet, cursor, sizeof(curr_length), &curr_length);
425 if (error) {
426 *err = error;
427 return -1;
428 }
429
430 cursor += (sizeof(curr_length) + ntohl(curr_length));
431 }
432 } while (curr_type != type);
433
434 return cursor;
435}
436
437static int
438flow_divert_packet_get_tlv(mbuf_t packet, int offset, uint8_t type, size_t buff_len, void *buff, size_t *val_size)
439{
440 int error = 0;
441 size_t length;
442 int tlv_offset;
443
444 tlv_offset = flow_divert_packet_find_tlv(packet, offset, type, &error, 0);
445 if (tlv_offset < 0) {
446 return error;
447 }
448
449 error = mbuf_copydata(packet, tlv_offset + sizeof(type), sizeof(length), &length);
450 if (error) {
451 return error;
452 }
453
454 length = ntohl(length);
455
456 if (val_size != NULL) {
457 *val_size = length;
458 }
459
460 if (buff != NULL && buff_len > 0) {
461 size_t to_copy = (length < buff_len) ? length : buff_len;
462 error = mbuf_copydata(packet, tlv_offset + sizeof(type) + sizeof(length), to_copy, buff);
463 if (error) {
464 return error;
465 }
466 }
467
468 return 0;
469}
470
471static int
472flow_divert_packet_compute_hmac(mbuf_t packet, struct flow_divert_group *group, uint8_t *hmac)
473{
474 mbuf_t curr_mbuf = packet;
475
476 if (g_crypto_funcs == NULL || group->token_key == NULL) {
477 return ENOPROTOOPT;
478 }
479
480 cchmac_di_decl(g_crypto_funcs->ccsha1_di, hmac_ctx);
481 g_crypto_funcs->cchmac_init_fn(g_crypto_funcs->ccsha1_di, hmac_ctx, group->token_key_size, group->token_key);
482
483 while (curr_mbuf != NULL) {
484 g_crypto_funcs->cchmac_update_fn(g_crypto_funcs->ccsha1_di, hmac_ctx, mbuf_len(curr_mbuf), mbuf_data(curr_mbuf));
485 curr_mbuf = mbuf_next(curr_mbuf);
486 }
487
488 g_crypto_funcs->cchmac_final_fn(g_crypto_funcs->ccsha1_di, hmac_ctx, hmac);
489
490 return 0;
491}
492
493static int
494flow_divert_packet_verify_hmac(mbuf_t packet, uint32_t ctl_unit)
495{
496 int error = 0;
497 struct flow_divert_group *group = NULL;
498 int hmac_offset;
499 uint8_t packet_hmac[SHA_DIGEST_LENGTH];
500 uint8_t computed_hmac[SHA_DIGEST_LENGTH];
501 mbuf_t tail;
502
503 lck_rw_lock_shared(&g_flow_divert_group_lck);
504
505 if (g_flow_divert_groups != NULL && g_active_group_count > 0) {
506 group = g_flow_divert_groups[ctl_unit];
507 }
508
509 if (group == NULL) {
510 lck_rw_done(&g_flow_divert_group_lck);
511 return ENOPROTOOPT;
512 }
513
514 lck_rw_lock_shared(&group->lck);
515
516 if (group->token_key == NULL) {
517 error = ENOPROTOOPT;
518 goto done;
519 }
520
521 hmac_offset = flow_divert_packet_find_tlv(packet, 0, FLOW_DIVERT_TLV_HMAC, &error, 0);
522 if (hmac_offset < 0) {
523 goto done;
524 }
525
526 error = flow_divert_packet_get_tlv(packet, hmac_offset, FLOW_DIVERT_TLV_HMAC, sizeof(packet_hmac), packet_hmac, NULL);
527 if (error) {
528 goto done;
529 }
530
531 /* Chop off the HMAC TLV */
532 error = mbuf_split(packet, hmac_offset, MBUF_WAITOK, &tail);
533 if (error) {
534 goto done;
535 }
536
537 mbuf_free(tail);
538
539 error = flow_divert_packet_compute_hmac(packet, group, computed_hmac);
540 if (error) {
541 goto done;
542 }
543
544 if (memcmp(packet_hmac, computed_hmac, sizeof(packet_hmac))) {
545 FDLOG0(LOG_WARNING, &nil_pcb, "HMAC in token does not match computed HMAC");
546 error = EINVAL;
547 goto done;
548 }
549
550done:
551 lck_rw_done(&group->lck);
552 lck_rw_done(&g_flow_divert_group_lck);
553 return error;
554}
555
556static void
557flow_divert_add_data_statistics(struct flow_divert_pcb *fd_cb, int data_len, Boolean send)
558{
559 struct inpcb *inp = NULL;
560 struct ifnet *ifp = NULL;
561 Boolean cell = FALSE;
562 Boolean wifi = FALSE;
fe8ab488 563 Boolean wired = FALSE;
39236c6e
A
564
565 inp = sotoinpcb(fd_cb->so);
566 if (inp == NULL) {
567 return;
568 }
569
570 ifp = inp->inp_last_outifp;
571 if (ifp != NULL) {
572 cell = IFNET_IS_CELLULAR(ifp);
573 wifi = (!cell && IFNET_IS_WIFI(ifp));
fe8ab488 574 wired = (!wifi && IFNET_IS_WIRED(ifp));
39236c6e
A
575 }
576
577 if (send) {
fe8ab488
A
578 INP_ADD_STAT(inp, cell, wifi, wired, txpackets, 1);
579 INP_ADD_STAT(inp, cell, wifi, wired, txbytes, data_len);
39236c6e 580 } else {
fe8ab488
A
581 INP_ADD_STAT(inp, cell, wifi, wired, rxpackets, 1);
582 INP_ADD_STAT(inp, cell, wifi, wired, rxbytes, data_len);
39236c6e
A
583 }
584}
585
586static errno_t
587flow_divert_check_no_cellular(struct flow_divert_pcb *fd_cb)
588{
589 struct inpcb *inp = NULL;
39236c6e
A
590
591 inp = sotoinpcb(fd_cb->so);
fe8ab488
A
592 if (inp && INP_NO_CELLULAR(inp) && inp->inp_last_outifp &&
593 IFNET_IS_CELLULAR(inp->inp_last_outifp))
594 return EHOSTUNREACH;
595
596 return 0;
597}
598
599static errno_t
600flow_divert_check_no_expensive(struct flow_divert_pcb *fd_cb)
601{
602 struct inpcb *inp = NULL;
603
604 inp = sotoinpcb(fd_cb->so);
605 if (inp && INP_NO_EXPENSIVE(inp) && inp->inp_last_outifp &&
606 IFNET_IS_EXPENSIVE(inp->inp_last_outifp))
607 return EHOSTUNREACH;
39236c6e
A
608
609 return 0;
610}
611
612static void
613flow_divert_update_closed_state(struct flow_divert_pcb *fd_cb, int how, Boolean tunnel)
614{
615 if (how != SHUT_RD) {
616 fd_cb->flags |= FLOW_DIVERT_WRITE_CLOSED;
617 if (tunnel || !(fd_cb->flags & FLOW_DIVERT_CONNECT_STARTED)) {
618 fd_cb->flags |= FLOW_DIVERT_TUNNEL_WR_CLOSED;
619 /* If the tunnel is not accepting writes any more, then flush the send buffer */
620 sbflush(&fd_cb->so->so_snd);
621 }
622 }
623 if (how != SHUT_WR) {
624 fd_cb->flags |= FLOW_DIVERT_READ_CLOSED;
625 if (tunnel || !(fd_cb->flags & FLOW_DIVERT_CONNECT_STARTED)) {
626 fd_cb->flags |= FLOW_DIVERT_TUNNEL_RD_CLOSED;
627 }
628 }
629}
630
631static uint16_t
632trie_node_alloc(struct flow_divert_trie *trie)
633{
634 if (trie->nodes_free_next < trie->nodes_count) {
635 uint16_t node_idx = trie->nodes_free_next++;
636 TRIE_NODE(trie, node_idx).child_map = NULL_TRIE_IDX;
637 return node_idx;
638 } else {
639 return NULL_TRIE_IDX;
640 }
641}
642
643static uint16_t
644trie_child_map_alloc(struct flow_divert_trie *trie)
645{
646 if (trie->child_maps_free_next < trie->child_maps_count) {
647 return trie->child_maps_free_next++;
648 } else {
649 return NULL_TRIE_IDX;
650 }
651}
652
653static uint16_t
654trie_bytes_move(struct flow_divert_trie *trie, uint16_t bytes_idx, size_t bytes_size)
655{
656 uint16_t start = trie->bytes_free_next;
657 if (start + bytes_size <= trie->bytes_count) {
658 if (start != bytes_idx) {
659 memmove(&TRIE_BYTE(trie, start), &TRIE_BYTE(trie, bytes_idx), bytes_size);
660 }
661 trie->bytes_free_next += bytes_size;
662 return start;
663 } else {
664 return NULL_TRIE_IDX;
665 }
666}
667
668static uint16_t
669flow_divert_trie_insert(struct flow_divert_trie *trie, uint16_t string_start, size_t string_len)
670{
671 uint16_t current = trie->root;
672 uint16_t child = trie->root;
673 uint16_t string_end = string_start + string_len;
674 uint16_t string_idx = string_start;
675 uint16_t string_remainder = string_len;
676
677 while (child != NULL_TRIE_IDX) {
678 uint16_t parent = current;
679 uint16_t node_idx;
680 uint16_t current_end;
681
682 current = child;
683 child = NULL_TRIE_IDX;
684
685 current_end = TRIE_NODE(trie, current).start + TRIE_NODE(trie, current).length;
686
687 for (node_idx = TRIE_NODE(trie, current).start;
688 node_idx < current_end &&
689 string_idx < string_end &&
690 TRIE_BYTE(trie, node_idx) == TRIE_BYTE(trie, string_idx);
691 node_idx++, string_idx++);
692
693 string_remainder = string_end - string_idx;
694
695 if (node_idx < (TRIE_NODE(trie, current).start + TRIE_NODE(trie, current).length)) {
696 /*
697 * We did not reach the end of the current node's string.
698 * We need to split the current node into two:
699 * 1. A new node that contains the prefix of the node that matches
700 * the prefix of the string being inserted.
701 * 2. The current node modified to point to the remainder
702 * of the current node's string.
703 */
704 uint16_t prefix = trie_node_alloc(trie);
705 if (prefix == NULL_TRIE_IDX) {
706 FDLOG0(LOG_ERR, &nil_pcb, "Ran out of trie nodes while splitting an existing node");
707 return NULL_TRIE_IDX;
708 }
709
710 /*
711 * Prefix points to the portion of the current nodes's string that has matched
712 * the input string thus far.
713 */
714 TRIE_NODE(trie, prefix).start = TRIE_NODE(trie, current).start;
715 TRIE_NODE(trie, prefix).length = (node_idx - TRIE_NODE(trie, current).start);
716
717 /*
718 * Prefix has the current node as the child corresponding to the first byte
719 * after the split.
720 */
721 TRIE_NODE(trie, prefix).child_map = trie_child_map_alloc(trie);
722 if (TRIE_NODE(trie, prefix).child_map == NULL_TRIE_IDX) {
723 FDLOG0(LOG_ERR, &nil_pcb, "Ran out of child maps while splitting an existing node");
724 return NULL_TRIE_IDX;
725 }
726 TRIE_CHILD(trie, prefix, TRIE_BYTE(trie, node_idx)) = current;
727
728 /* Parent has the prefix as the child correspoding to the first byte in the prefix */
729 TRIE_CHILD(trie, parent, TRIE_BYTE(trie, TRIE_NODE(trie, prefix).start)) = prefix;
730
731 /* Current node is adjusted to point to the remainder */
732 TRIE_NODE(trie, current).start = node_idx;
733 TRIE_NODE(trie, current).length -= TRIE_NODE(trie, prefix).length;
734
735 /* We want to insert the new leaf (if any) as a child of the prefix */
736 current = prefix;
737 }
738
739 if (string_remainder > 0) {
740 /*
741 * We still have bytes in the string that have not been matched yet.
742 * If the current node has children, iterate to the child corresponding
743 * to the next byte in the string.
744 */
745 if (TRIE_NODE(trie, current).child_map != NULL_TRIE_IDX) {
746 child = TRIE_CHILD(trie, current, TRIE_BYTE(trie, string_idx));
747 }
748 }
749 } /* while (child != NULL_TRIE_IDX) */
750
751 if (string_remainder > 0) {
752 /* Add a new leaf containing the remainder of the string */
753 uint16_t leaf = trie_node_alloc(trie);
754 if (leaf == NULL_TRIE_IDX) {
755 FDLOG0(LOG_ERR, &nil_pcb, "Ran out of trie nodes while inserting a new leaf");
756 return NULL_TRIE_IDX;
757 }
758
759 TRIE_NODE(trie, leaf).start = trie_bytes_move(trie, string_idx, string_remainder);
760 if (TRIE_NODE(trie, leaf).start == NULL_TRIE_IDX) {
761 FDLOG0(LOG_ERR, &nil_pcb, "Ran out of bytes while inserting a new leaf");
762 return NULL_TRIE_IDX;
763 }
764 TRIE_NODE(trie, leaf).length = string_remainder;
765
766 /* Set the new leaf as the child of the current node */
767 if (TRIE_NODE(trie, current).child_map == NULL_TRIE_IDX) {
768 TRIE_NODE(trie, current).child_map = trie_child_map_alloc(trie);
769 if (TRIE_NODE(trie, current).child_map == NULL_TRIE_IDX) {
770 FDLOG0(LOG_ERR, &nil_pcb, "Ran out of child maps while inserting a new leaf");
771 return NULL_TRIE_IDX;
772 }
773 }
774 TRIE_CHILD(trie, current, TRIE_BYTE(trie, TRIE_NODE(trie, leaf).start)) = leaf;
775 current = leaf;
776 } /* else duplicate or this string is a prefix of one of the existing strings */
777
778 return current;
779}
780
781static uint16_t
782flow_divert_trie_search(struct flow_divert_trie *trie, const uint8_t *string_bytes)
783{
784 uint16_t current = trie->root;
785 uint16_t string_idx = 0;
786
787 while (current != NULL_TRIE_IDX) {
788 uint16_t next = NULL_TRIE_IDX;
789 uint16_t node_end = TRIE_NODE(trie, current).start + TRIE_NODE(trie, current).length;
790 uint16_t node_idx;
791
792 for (node_idx = TRIE_NODE(trie, current).start;
793 node_idx < node_end && string_bytes[string_idx] != '\0' && string_bytes[string_idx] == TRIE_BYTE(trie, node_idx);
794 node_idx++, string_idx++);
795
796 if (node_idx == node_end) {
797 if (string_bytes[string_idx] == '\0') {
798 return current; /* Got an exact match */
799 } else if (TRIE_NODE(trie, current).child_map != NULL_TRIE_IDX) {
800 next = TRIE_CHILD(trie, current, string_bytes[string_idx]);
801 }
802 }
803 current = next;
804 }
805
806 return NULL_TRIE_IDX;
807}
808
809static int
810flow_divert_get_src_proc(struct socket *so, proc_t *proc, boolean_t match_delegate)
811{
812 int release = 0;
813
814 if (!match_delegate &&
815 (so->so_flags & SOF_DELEGATED) &&
816 (*proc == PROC_NULL || (*proc)->p_pid != so->e_pid))
817 {
818 *proc = proc_find(so->e_pid);
819 release = 1;
820 } else if (*proc == PROC_NULL) {
821 *proc = current_proc();
822 }
823
824 if (*proc != PROC_NULL) {
825 if ((*proc)->p_pid == 0) {
826 if (release) {
827 proc_rele(*proc);
828 }
829 release = 0;
830 *proc = PROC_NULL;
831 }
832 }
833
834 return release;
835}
836
837static int
838flow_divert_send_packet(struct flow_divert_pcb *fd_cb, mbuf_t packet, Boolean enqueue)
839{
840 int error;
841
842 if (fd_cb->group == NULL) {
843 fd_cb->so->so_error = ECONNABORTED;
844 soisdisconnected(fd_cb->so);
845 return ECONNABORTED;
846 }
847
848 lck_rw_lock_shared(&fd_cb->group->lck);
849
850 if (MBUFQ_EMPTY(&fd_cb->group->send_queue)) {
851 error = ctl_enqueuembuf(g_flow_divert_kctl_ref, fd_cb->group->ctl_unit, packet, CTL_DATA_EOR);
852 } else {
853 error = ENOBUFS;
854 }
855
856 if (error == ENOBUFS) {
857 if (enqueue) {
858 if (!lck_rw_lock_shared_to_exclusive(&fd_cb->group->lck)) {
859 lck_rw_lock_exclusive(&fd_cb->group->lck);
860 }
861 MBUFQ_ENQUEUE(&fd_cb->group->send_queue, packet);
862 error = 0;
863 }
864 OSTestAndSet(GROUP_BIT_CTL_ENQUEUE_BLOCKED, &fd_cb->group->atomic_bits);
865 }
866
867 lck_rw_done(&fd_cb->group->lck);
868
869 return error;
870}
871
872static int
fe8ab488 873flow_divert_send_connect(struct flow_divert_pcb *fd_cb, struct sockaddr *to, mbuf_t connect_packet)
39236c6e 874{
39236c6e
A
875 int error = 0;
876
39236c6e
A
877 error = flow_divert_packet_append_tlv(connect_packet,
878 FLOW_DIVERT_TLV_TRAFFIC_CLASS,
879 sizeof(fd_cb->so->so_traffic_class),
880 &fd_cb->so->so_traffic_class);
881 if (error) {
882 goto done;
883 }
884
885 if (fd_cb->so->so_flags & SOF_DELEGATED) {
886 error = flow_divert_packet_append_tlv(connect_packet,
887 FLOW_DIVERT_TLV_PID,
888 sizeof(fd_cb->so->e_pid),
889 &fd_cb->so->e_pid);
890 if (error) {
891 goto done;
892 }
893
894 error = flow_divert_packet_append_tlv(connect_packet,
895 FLOW_DIVERT_TLV_UUID,
896 sizeof(fd_cb->so->e_uuid),
897 &fd_cb->so->e_uuid);
898 if (error) {
899 goto done;
900 }
901 } else {
902 error = flow_divert_packet_append_tlv(connect_packet,
903 FLOW_DIVERT_TLV_PID,
904 sizeof(fd_cb->so->e_pid),
905 &fd_cb->so->last_pid);
906 if (error) {
907 goto done;
908 }
909
910 error = flow_divert_packet_append_tlv(connect_packet,
911 FLOW_DIVERT_TLV_UUID,
912 sizeof(fd_cb->so->e_uuid),
913 &fd_cb->so->last_uuid);
914 if (error) {
915 goto done;
916 }
917 }
918
919 if (fd_cb->connect_token != NULL) {
920 unsigned int token_len = m_length(fd_cb->connect_token);
921 mbuf_concatenate(connect_packet, fd_cb->connect_token);
922 mbuf_pkthdr_adjustlen(connect_packet, token_len);
923 fd_cb->connect_token = NULL;
924 } else {
925 uint32_t ctl_unit = htonl(fd_cb->control_group_unit);
926 int port;
39236c6e
A
927
928 error = flow_divert_packet_append_tlv(connect_packet, FLOW_DIVERT_TLV_CTL_UNIT, sizeof(ctl_unit), &ctl_unit);
929 if (error) {
930 goto done;
931 }
932
933 error = flow_divert_packet_append_tlv(connect_packet, FLOW_DIVERT_TLV_TARGET_ADDRESS, to->sa_len, to);
934 if (error) {
935 goto done;
936 }
937
938 if (to->sa_family == AF_INET) {
939 port = ntohs((satosin(to))->sin_port);
940 }
941#if INET6
942 else {
943 port = ntohs((satosin6(to))->sin6_port);
944 }
945#endif
946
947 error = flow_divert_packet_append_tlv(connect_packet, FLOW_DIVERT_TLV_TARGET_PORT, sizeof(port), &port);
948 if (error) {
949 goto done;
950 }
39236c6e
A
951 }
952
953 error = flow_divert_send_packet(fd_cb, connect_packet, TRUE);
954 if (error) {
955 goto done;
956 }
957
958done:
39236c6e
A
959 return error;
960}
961
962static int
963flow_divert_send_connect_result(struct flow_divert_pcb *fd_cb)
964{
965 int error = 0;
966 mbuf_t packet = NULL;
967 int rbuff_space = 0;
968
969 error = flow_divert_packet_init(fd_cb, FLOW_DIVERT_PKT_CONNECT_RESULT, &packet);
970 if (error) {
971 FDLOG(LOG_ERR, fd_cb, "failed to create a connect result packet: %d", error);
972 goto done;
973 }
974
975 rbuff_space = sbspace(&fd_cb->so->so_rcv);
976 if (rbuff_space < 0) {
977 rbuff_space = 0;
978 }
979 rbuff_space = htonl(rbuff_space);
980 error = flow_divert_packet_append_tlv(packet,
981 FLOW_DIVERT_TLV_SPACE_AVAILABLE,
982 sizeof(rbuff_space),
983 &rbuff_space);
984 if (error) {
985 goto done;
986 }
987
988 error = flow_divert_send_packet(fd_cb, packet, TRUE);
989 if (error) {
990 goto done;
991 }
992
993done:
994 if (error && packet != NULL) {
995 mbuf_free(packet);
996 }
997
998 return error;
999}
1000
1001static int
1002flow_divert_send_close(struct flow_divert_pcb *fd_cb, int how)
1003{
1004 int error = 0;
1005 mbuf_t packet = NULL;
1006 uint32_t zero = 0;
1007
1008 error = flow_divert_packet_init(fd_cb, FLOW_DIVERT_PKT_CLOSE, &packet);
1009 if (error) {
1010 FDLOG(LOG_ERR, fd_cb, "failed to create a close packet: %d", error);
1011 goto done;
1012 }
1013
1014 error = flow_divert_packet_append_tlv(packet, FLOW_DIVERT_TLV_ERROR_CODE, sizeof(zero), &zero);
1015 if (error) {
1016 FDLOG(LOG_ERR, fd_cb, "failed to add the error code TLV: %d", error);
1017 goto done;
1018 }
1019
1020 how = htonl(how);
1021 error = flow_divert_packet_append_tlv(packet, FLOW_DIVERT_TLV_HOW, sizeof(how), &how);
1022 if (error) {
1023 FDLOG(LOG_ERR, fd_cb, "failed to add the how flag: %d", error);
1024 goto done;
1025 }
1026
1027 error = flow_divert_send_packet(fd_cb, packet, TRUE);
1028 if (error) {
1029 goto done;
1030 }
1031
1032done:
1033 if (error && packet != NULL) {
1034 mbuf_free(packet);
1035 }
1036
1037 return error;
1038}
1039
1040static int
1041flow_divert_tunnel_how_closed(struct flow_divert_pcb *fd_cb)
1042{
1043 if ((fd_cb->flags & (FLOW_DIVERT_TUNNEL_RD_CLOSED|FLOW_DIVERT_TUNNEL_WR_CLOSED)) ==
1044 (FLOW_DIVERT_TUNNEL_RD_CLOSED|FLOW_DIVERT_TUNNEL_WR_CLOSED))
1045 {
1046 return SHUT_RDWR;
1047 } else if (fd_cb->flags & FLOW_DIVERT_TUNNEL_RD_CLOSED) {
1048 return SHUT_RD;
1049 } else if (fd_cb->flags & FLOW_DIVERT_TUNNEL_WR_CLOSED) {
1050 return SHUT_WR;
1051 }
1052
1053 return -1;
1054}
1055
1056/*
1057 * Determine what close messages if any need to be sent to the tunnel. Returns TRUE if the tunnel is closed for both reads and
1058 * writes. Returns FALSE otherwise.
1059 */
1060static void
1061flow_divert_send_close_if_needed(struct flow_divert_pcb *fd_cb)
1062{
1063 int how = -1;
1064
1065 /* Do not send any close messages if there is still data in the send buffer */
1066 if (fd_cb->so->so_snd.sb_cc == 0) {
1067 if ((fd_cb->flags & (FLOW_DIVERT_READ_CLOSED|FLOW_DIVERT_TUNNEL_RD_CLOSED)) == FLOW_DIVERT_READ_CLOSED) {
1068 /* Socket closed reads, but tunnel did not. Tell tunnel to close reads */
1069 how = SHUT_RD;
1070 }
1071 if ((fd_cb->flags & (FLOW_DIVERT_WRITE_CLOSED|FLOW_DIVERT_TUNNEL_WR_CLOSED)) == FLOW_DIVERT_WRITE_CLOSED) {
1072 /* Socket closed writes, but tunnel did not. Tell tunnel to close writes */
1073 if (how == SHUT_RD) {
1074 how = SHUT_RDWR;
1075 } else {
1076 how = SHUT_WR;
1077 }
1078 }
1079 }
1080
1081 if (how != -1) {
1082 FDLOG(LOG_INFO, fd_cb, "sending close, how = %d", how);
1083 if (flow_divert_send_close(fd_cb, how) != ENOBUFS) {
1084 /* Successfully sent the close packet. Record the ways in which the tunnel has been closed */
1085 if (how != SHUT_RD) {
1086 fd_cb->flags |= FLOW_DIVERT_TUNNEL_WR_CLOSED;
1087 }
1088 if (how != SHUT_WR) {
1089 fd_cb->flags |= FLOW_DIVERT_TUNNEL_RD_CLOSED;
1090 }
1091 }
1092 }
1093
1094 if (flow_divert_tunnel_how_closed(fd_cb) == SHUT_RDWR) {
1095 soisdisconnected(fd_cb->so);
1096 }
1097}
1098
1099static errno_t
1100flow_divert_send_data_packet(struct flow_divert_pcb *fd_cb, mbuf_t data, size_t data_len, Boolean force)
1101{
1102 mbuf_t packet;
1103 mbuf_t last;
1104 int error = 0;
1105
1106 error = flow_divert_packet_init(fd_cb, FLOW_DIVERT_PKT_DATA, &packet);
1107 if (error) {
1108 FDLOG(LOG_ERR, fd_cb, "flow_divert_packet_init failed: %d", error);
1109 return error;
1110 }
1111
1112 last = m_last(packet);
1113 mbuf_setnext(last, data);
1114 mbuf_pkthdr_adjustlen(packet, data_len);
1115
1116 error = flow_divert_send_packet(fd_cb, packet, force);
1117
1118 if (error) {
1119 mbuf_setnext(last, NULL);
1120 mbuf_free(packet);
1121 } else {
1122 fd_cb->bytes_sent += data_len;
1123 flow_divert_add_data_statistics(fd_cb, data_len, TRUE);
1124 }
1125
1126 return error;
1127}
1128
1129static void
1130flow_divert_send_buffered_data(struct flow_divert_pcb *fd_cb, Boolean force)
1131{
1132 size_t to_send;
1133 size_t sent = 0;
1134 int error = 0;
1135 mbuf_t buffer;
1136
1137 to_send = fd_cb->so->so_snd.sb_cc;
1138 buffer = fd_cb->so->so_snd.sb_mb;
1139
1140 if (buffer == NULL && to_send > 0) {
1141 FDLOG(LOG_ERR, fd_cb, "Send buffer is NULL, but size is supposed to be %lu", to_send);
1142 return;
1143 }
1144
1145 /* Ignore the send window if force is enabled */
1146 if (!force && (to_send > fd_cb->send_window)) {
1147 to_send = fd_cb->send_window;
1148 }
1149
1150 while (sent < to_send) {
1151 mbuf_t data;
1152 size_t data_len;
1153
1154 data_len = to_send - sent;
1155 if (data_len > FLOW_DIVERT_CHUNK_SIZE) {
1156 data_len = FLOW_DIVERT_CHUNK_SIZE;
1157 }
1158
1159 error = mbuf_copym(buffer, sent, data_len, MBUF_DONTWAIT, &data);
1160 if (error) {
1161 FDLOG(LOG_ERR, fd_cb, "mbuf_copym failed: %d", error);
1162 break;
1163 }
1164
1165 error = flow_divert_send_data_packet(fd_cb, data, data_len, force);
1166 if (error) {
1167 mbuf_free(data);
1168 break;
1169 }
1170
1171 sent += data_len;
1172 }
1173
1174 if (sent > 0) {
1175 FDLOG(LOG_DEBUG, fd_cb, "sent %lu bytes of buffered data", sent);
1176 if (fd_cb->send_window >= sent) {
1177 fd_cb->send_window -= sent;
1178 } else {
1179 fd_cb->send_window = 0;
1180 }
1181 sbdrop(&fd_cb->so->so_snd, sent);
1182 sowwakeup(fd_cb->so);
1183 }
1184}
1185
1186static int
1187flow_divert_send_app_data(struct flow_divert_pcb *fd_cb, mbuf_t data)
1188{
1189 size_t to_send = mbuf_pkthdr_len(data);
1190 size_t sent = 0;
1191 int error = 0;
1192 mbuf_t remaining_data = data;
1193 mbuf_t pkt_data = NULL;
1194
1195 if (to_send > fd_cb->send_window) {
1196 to_send = fd_cb->send_window;
1197 }
1198
1199 if (fd_cb->so->so_snd.sb_cc > 0) {
1200 to_send = 0; /* If the send buffer is non-empty, then we can't send anything */
1201 }
1202
1203 while (sent < to_send) {
1204 size_t pkt_data_len;
1205
1206 pkt_data = remaining_data;
1207
1208 if ((to_send - sent) > FLOW_DIVERT_CHUNK_SIZE) {
1209 pkt_data_len = FLOW_DIVERT_CHUNK_SIZE;
1210 error = mbuf_split(pkt_data, pkt_data_len, MBUF_DONTWAIT, &remaining_data);
1211 if (error) {
1212 FDLOG(LOG_ERR, fd_cb, "mbuf_split failed: %d", error);
1213 pkt_data = NULL;
1214 break;
1215 }
1216 } else {
1217 pkt_data_len = to_send - sent;
1218 remaining_data = NULL;
1219 }
1220
1221 error = flow_divert_send_data_packet(fd_cb, pkt_data, pkt_data_len, FALSE);
1222
1223 if (error) {
1224 break;
1225 }
1226
1227 pkt_data = NULL;
1228 sent += pkt_data_len;
1229 }
1230
1231 fd_cb->send_window -= sent;
1232
1233 error = 0;
1234
1235 if (pkt_data != NULL) {
1236 if (sbspace(&fd_cb->so->so_snd) > 0) {
1237 if (!sbappendstream(&fd_cb->so->so_snd, pkt_data)) {
1238 FDLOG(LOG_ERR, fd_cb, "sbappendstream failed with pkt_data, send buffer size = %u, send_window = %u\n",
1239 fd_cb->so->so_snd.sb_cc, fd_cb->send_window);
1240 }
1241 } else {
1242 error = ENOBUFS;
1243 }
1244 }
1245
1246 if (remaining_data != NULL) {
1247 if (sbspace(&fd_cb->so->so_snd) > 0) {
1248 if (!sbappendstream(&fd_cb->so->so_snd, remaining_data)) {
1249 FDLOG(LOG_ERR, fd_cb, "sbappendstream failed with remaining_data, send buffer size = %u, send_window = %u\n",
1250 fd_cb->so->so_snd.sb_cc, fd_cb->send_window);
1251 }
1252 } else {
1253 error = ENOBUFS;
1254 }
1255 }
1256
1257 return error;
1258}
1259
1260static int
1261flow_divert_send_read_notification(struct flow_divert_pcb *fd_cb, uint32_t read_count)
1262{
1263 int error = 0;
1264 mbuf_t packet = NULL;
1265 uint32_t net_read_count = htonl(read_count);
1266
1267 error = flow_divert_packet_init(fd_cb, FLOW_DIVERT_PKT_READ_NOTIFY, &packet);
1268 if (error) {
1269 FDLOG(LOG_ERR, fd_cb, "failed to create a read notification packet: %d", error);
1270 goto done;
1271 }
1272
1273 error = flow_divert_packet_append_tlv(packet, FLOW_DIVERT_TLV_READ_COUNT, sizeof(net_read_count), &net_read_count);
1274 if (error) {
1275 FDLOG(LOG_ERR, fd_cb, "failed to add the read count: %d", error);
1276 goto done;
1277 }
1278
1279 error = flow_divert_send_packet(fd_cb, packet, TRUE);
1280 if (error) {
1281 goto done;
1282 }
1283
1284done:
1285 if (error && packet != NULL) {
1286 mbuf_free(packet);
1287 }
1288
1289 return error;
1290}
1291
1292static int
1293flow_divert_send_traffic_class_update(struct flow_divert_pcb *fd_cb, int traffic_class)
1294{
1295 int error = 0;
1296 mbuf_t packet = NULL;
1297
1298 error = flow_divert_packet_init(fd_cb, FLOW_DIVERT_PKT_PROPERTIES_UPDATE, &packet);
1299 if (error) {
1300 FDLOG(LOG_ERR, fd_cb, "failed to create a properties update packet: %d", error);
1301 goto done;
1302 }
1303
1304 error = flow_divert_packet_append_tlv(packet, FLOW_DIVERT_TLV_TRAFFIC_CLASS, sizeof(traffic_class), &traffic_class);
1305 if (error) {
1306 FDLOG(LOG_ERR, fd_cb, "failed to add the traffic class: %d", error);
1307 goto done;
1308 }
1309
1310 error = flow_divert_send_packet(fd_cb, packet, TRUE);
1311 if (error) {
1312 goto done;
1313 }
1314
1315done:
1316 if (error && packet != NULL) {
1317 mbuf_free(packet);
1318 }
1319
1320 return error;
1321}
1322
1323static void
1324flow_divert_handle_connect_result(struct flow_divert_pcb *fd_cb, mbuf_t packet, int offset)
1325{
1326 uint32_t connect_error;
1327 uint32_t ctl_unit = 0;
1328 int error = 0;
1329 struct flow_divert_group *grp = NULL;
1330 struct sockaddr_storage local_address;
1331 int out_if_index = 0;
1332 struct sockaddr_storage remote_address;
1333 uint32_t send_window;
1334
1335 memset(&local_address, 0, sizeof(local_address));
1336 memset(&remote_address, 0, sizeof(remote_address));
1337
1338 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_ERROR_CODE, sizeof(connect_error), &connect_error, NULL);
1339 if (error) {
1340 FDLOG(LOG_ERR, fd_cb, "failed to get the connect result: %d", error);
1341 return;
1342 }
1343
1344 FDLOG(LOG_INFO, fd_cb, "received connect result %u", connect_error);
1345
1346 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_SPACE_AVAILABLE, sizeof(send_window), &send_window, NULL);
1347 if (error) {
1348 FDLOG(LOG_ERR, fd_cb, "failed to get the send window: %d", error);
1349 return;
1350 }
1351
1352 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_CTL_UNIT, sizeof(ctl_unit), &ctl_unit, NULL);
1353 if (error) {
1354 FDLOG(LOG_ERR, fd_cb, "failed to get the control unit: %d", error);
1355 return;
1356 }
1357
1358 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_LOCAL_ADDR, sizeof(local_address), &local_address, NULL);
1359 if (error) {
1360 FDLOG0(LOG_NOTICE, fd_cb, "No local address provided");
1361 }
1362
1363 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_REMOTE_ADDR, sizeof(remote_address), &remote_address, NULL);
1364 if (error) {
1365 FDLOG0(LOG_NOTICE, fd_cb, "No remote address provided");
1366 }
1367
1368 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_OUT_IF_INDEX, sizeof(out_if_index), &out_if_index, NULL);
1369 if (error) {
1370 FDLOG0(LOG_NOTICE, fd_cb, "No output if index provided");
1371 }
1372
1373 connect_error = ntohl(connect_error);
1374 ctl_unit = ntohl(ctl_unit);
1375
1376 lck_rw_lock_shared(&g_flow_divert_group_lck);
1377
1378 if (connect_error == 0) {
1379 if (ctl_unit == 0 || ctl_unit >= GROUP_COUNT_MAX) {
1380 FDLOG(LOG_ERR, fd_cb, "Connect result contains an invalid control unit: %u", ctl_unit);
1381 error = EINVAL;
1382 } else if (g_flow_divert_groups == NULL || g_active_group_count == 0) {
1383 FDLOG0(LOG_ERR, fd_cb, "No active groups, dropping connection");
1384 error = EINVAL;
1385 } else {
1386 grp = g_flow_divert_groups[ctl_unit];
1387 if (grp == NULL) {
1388 error = ECONNRESET;
1389 }
1390 }
1391 }
1392
1393 FDLOCK(fd_cb);
1394 if (fd_cb->so != NULL) {
1395 struct inpcb *inp = NULL;
1396 struct ifnet *ifp = NULL;
1397 struct flow_divert_group *old_group;
1398
1399 socket_lock(fd_cb->so, 0);
1400
1401 if (!(fd_cb->so->so_state & SS_ISCONNECTING)) {
1402 goto done;
1403 }
1404
1405 inp = sotoinpcb(fd_cb->so);
1406
1407 if (connect_error || error) {
1408 goto set_socket_state;
1409 }
1410
1411 if (local_address.ss_family != 0) {
1412 if (local_address.ss_len > sizeof(local_address)) {
1413 local_address.ss_len = sizeof(local_address);
1414 }
1415 fd_cb->local_address = dup_sockaddr((struct sockaddr *)&local_address, 1);
1416 } else {
1417 error = EINVAL;
1418 goto set_socket_state;
1419 }
1420
1421 if (remote_address.ss_family != 0) {
1422 if (remote_address.ss_len > sizeof(remote_address)) {
1423 remote_address.ss_len = sizeof(remote_address);
1424 }
1425 fd_cb->remote_address = dup_sockaddr((struct sockaddr *)&remote_address, 1);
1426 } else {
1427 error = EINVAL;
1428 goto set_socket_state;
1429 }
1430
1431 ifnet_head_lock_shared();
1432 if (out_if_index > 0 && out_if_index <= if_index) {
1433 ifp = ifindex2ifnet[out_if_index];
1434 }
1435
1436 if (ifp != NULL) {
1437 inp->inp_last_outifp = ifp;
1438 } else {
1439 error = EINVAL;
1440 }
1441 ifnet_head_done();
1442
1443 if (error) {
1444 goto set_socket_state;
1445 }
1446
1447 if (fd_cb->group == NULL) {
1448 error = EINVAL;
1449 goto set_socket_state;
1450 }
1451
1452 old_group = fd_cb->group;
1453
1454 lck_rw_lock_exclusive(&old_group->lck);
1455 lck_rw_lock_exclusive(&grp->lck);
1456
1457 RB_REMOVE(fd_pcb_tree, &old_group->pcb_tree, fd_cb);
1458 if (RB_INSERT(fd_pcb_tree, &grp->pcb_tree, fd_cb) != NULL) {
1459 panic("group with unit %u already contains a connection with hash %u", grp->ctl_unit, fd_cb->hash);
1460 }
1461
1462 fd_cb->group = grp;
1463
1464 lck_rw_done(&grp->lck);
1465 lck_rw_done(&old_group->lck);
1466
1467 fd_cb->send_window = ntohl(send_window);
1468 flow_divert_send_buffered_data(fd_cb, FALSE);
1469
1470set_socket_state:
1471 if (!connect_error && !error) {
1472 FDLOG0(LOG_INFO, fd_cb, "sending connect result");
1473 error = flow_divert_send_connect_result(fd_cb);
1474 }
1475
1476 if (connect_error || error) {
1477 if (!connect_error) {
1478 flow_divert_update_closed_state(fd_cb, SHUT_RDWR, FALSE);
1479 fd_cb->so->so_error = error;
1480 flow_divert_send_close_if_needed(fd_cb);
1481 } else {
1482 flow_divert_update_closed_state(fd_cb, SHUT_RDWR, TRUE);
1483 fd_cb->so->so_error = connect_error;
1484 }
1485 soisdisconnected(fd_cb->so);
1486 } else {
1487 soisconnected(fd_cb->so);
1488 }
1489
1490done:
1491 socket_unlock(fd_cb->so, 0);
1492 }
1493 FDUNLOCK(fd_cb);
1494
1495 lck_rw_done(&g_flow_divert_group_lck);
1496}
1497
1498static void
1499flow_divert_handle_close(struct flow_divert_pcb *fd_cb, mbuf_t packet, int offset)
1500{
1501 uint32_t close_error;
1502 int error = 0;
1503 int how;
1504
1505 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_ERROR_CODE, sizeof(close_error), &close_error, NULL);
1506 if (error) {
1507 FDLOG(LOG_ERR, fd_cb, "failed to get the close error: %d", error);
1508 return;
1509 }
1510
1511 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_HOW, sizeof(how), &how, NULL);
1512 if (error) {
1513 FDLOG(LOG_ERR, fd_cb, "failed to get the close how flag: %d", error);
1514 return;
1515 }
1516
1517 how = ntohl(how);
1518
1519 FDLOG(LOG_INFO, fd_cb, "close received, how = %d", how);
1520
1521 FDLOCK(fd_cb);
1522 if (fd_cb->so != NULL) {
1523 socket_lock(fd_cb->so, 0);
1524
1525 fd_cb->so->so_error = ntohl(close_error);
1526
1527 flow_divert_update_closed_state(fd_cb, how, TRUE);
1528
1529 how = flow_divert_tunnel_how_closed(fd_cb);
1530 if (how == SHUT_RDWR) {
1531 soisdisconnected(fd_cb->so);
1532 } else if (how == SHUT_RD) {
1533 socantrcvmore(fd_cb->so);
1534 } else if (how == SHUT_WR) {
1535 socantsendmore(fd_cb->so);
1536 }
1537
1538 socket_unlock(fd_cb->so, 0);
1539 }
1540 FDUNLOCK(fd_cb);
1541}
1542
1543static void
1544flow_divert_handle_data(struct flow_divert_pcb *fd_cb, mbuf_t packet, size_t offset)
1545{
1546 int error = 0;
1547 mbuf_t data = NULL;
1548 size_t data_size;
1549
1550 data_size = (mbuf_pkthdr_len(packet) - offset);
1551
1552 FDLOG(LOG_DEBUG, fd_cb, "received %lu bytes of data", data_size);
1553
1554 error = mbuf_split(packet, offset, MBUF_DONTWAIT, &data);
1555 if (error || data == NULL) {
1556 FDLOG(LOG_ERR, fd_cb, "mbuf_split failed: %d", error);
1557 return;
1558 }
1559
1560 FDLOCK(fd_cb);
1561 if (fd_cb->so != NULL) {
1562 socket_lock(fd_cb->so, 0);
fe8ab488
A
1563 if (flow_divert_check_no_cellular(fd_cb) ||
1564 flow_divert_check_no_expensive(fd_cb)) {
39236c6e
A
1565 flow_divert_update_closed_state(fd_cb, SHUT_RDWR, TRUE);
1566 flow_divert_send_close(fd_cb, SHUT_RDWR);
1567 soisdisconnected(fd_cb->so);
1568 } else if (!(fd_cb->so->so_state & SS_CANTRCVMORE)) {
1569 if (sbappendstream(&fd_cb->so->so_rcv, data)) {
1570 fd_cb->bytes_received += data_size;
1571 flow_divert_add_data_statistics(fd_cb, data_size, FALSE);
1572 fd_cb->sb_size = fd_cb->so->so_rcv.sb_cc;
1573 sorwakeup(fd_cb->so);
1574 data = NULL;
1575 } else {
1576 FDLOG0(LOG_ERR, fd_cb, "received data, but appendstream failed");
1577 }
1578 }
1579 socket_unlock(fd_cb->so, 0);
1580 }
1581 FDUNLOCK(fd_cb);
1582
1583 if (data != NULL) {
1584 mbuf_free(data);
1585 }
1586}
1587
1588static void
1589flow_divert_handle_read_notification(struct flow_divert_pcb *fd_cb, mbuf_t packet, int offset)
1590{
1591 uint32_t read_count;
1592 int error = 0;
1593
1594 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_READ_COUNT, sizeof(read_count), &read_count, NULL);
1595 if (error) {
1596 FDLOG(LOG_ERR, fd_cb, "failed to get the read count: %d", error);
1597 return;
1598 }
1599
1600 FDLOG(LOG_DEBUG, fd_cb, "received a read notification for %u bytes", read_count);
1601
1602 FDLOCK(fd_cb);
1603 if (fd_cb->so != NULL) {
1604 socket_lock(fd_cb->so, 0);
1605 fd_cb->send_window += ntohl(read_count);
1606 flow_divert_send_buffered_data(fd_cb, FALSE);
1607 socket_unlock(fd_cb->so, 0);
1608 }
1609 FDUNLOCK(fd_cb);
1610}
1611
1612static void
1613flow_divert_handle_group_init(struct flow_divert_group *group, mbuf_t packet, int offset)
1614{
1615 int error = 0;
1616 size_t key_size = 0;
1617 int log_level;
1618
1619 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_TOKEN_KEY, 0, NULL, &key_size);
1620 if (error) {
1621 FDLOG(LOG_ERR, &nil_pcb, "failed to get the key size: %d", error);
1622 return;
1623 }
1624
1625 if (key_size == 0 || key_size > FLOW_DIVERT_MAX_KEY_SIZE) {
1626 FDLOG(LOG_ERR, &nil_pcb, "Invalid key size: %lu", key_size);
1627 return;
1628 }
1629
1630 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_LOG_LEVEL, sizeof(log_level), &log_level, NULL);
1631 if (!error) {
1632 nil_pcb.log_level = log_level;
1633 }
1634
1635 lck_rw_lock_exclusive(&group->lck);
1636
1637 MALLOC(group->token_key, uint8_t *, key_size, M_TEMP, M_WAITOK);
1638 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_TOKEN_KEY, key_size, group->token_key, NULL);
1639 if (error) {
1640 FDLOG(LOG_ERR, &nil_pcb, "failed to get the token key: %d", error);
1641 FREE(group->token_key, M_TEMP);
1642 group->token_key = NULL;
1643 lck_rw_done(&group->lck);
1644 return;
1645 }
1646
1647 group->token_key_size = key_size;
1648
1649 lck_rw_done(&group->lck);
1650}
1651
1652static void
1653flow_divert_handle_properties_update(struct flow_divert_pcb *fd_cb, mbuf_t packet, int offset)
1654{
1655 int error = 0;
1656 struct sockaddr_storage local_address;
1657 int out_if_index = 0;
1658 struct sockaddr_storage remote_address;
1659
1660 FDLOG0(LOG_INFO, fd_cb, "received a properties update");
1661
1662 memset(&local_address, 0, sizeof(local_address));
1663 memset(&remote_address, 0, sizeof(remote_address));
1664
1665 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_LOCAL_ADDR, sizeof(local_address), &local_address, NULL);
1666 if (error) {
1667 FDLOG0(LOG_INFO, fd_cb, "No local address provided");
1668 }
1669
1670 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_REMOTE_ADDR, sizeof(remote_address), &remote_address, NULL);
1671 if (error) {
1672 FDLOG0(LOG_INFO, fd_cb, "No remote address provided");
1673 }
1674
1675 error = flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_OUT_IF_INDEX, sizeof(out_if_index), &out_if_index, NULL);
1676 if (error) {
1677 FDLOG0(LOG_INFO, fd_cb, "No output if index provided");
1678 }
1679
1680 FDLOCK(fd_cb);
1681 if (fd_cb->so != NULL) {
1682 struct inpcb *inp = NULL;
1683 struct ifnet *ifp = NULL;
1684
1685 socket_lock(fd_cb->so, 0);
1686
1687 inp = sotoinpcb(fd_cb->so);
1688
1689 if (local_address.ss_family != 0) {
1690 if (local_address.ss_len > sizeof(local_address)) {
1691 local_address.ss_len = sizeof(local_address);
1692 }
1693 fd_cb->local_address = dup_sockaddr((struct sockaddr *)&local_address, 1);
1694 }
1695
1696 if (remote_address.ss_family != 0) {
1697 if (remote_address.ss_len > sizeof(remote_address)) {
1698 remote_address.ss_len = sizeof(remote_address);
1699 }
1700 fd_cb->remote_address = dup_sockaddr((struct sockaddr *)&remote_address, 1);
1701 }
1702
1703 ifnet_head_lock_shared();
1704 if (out_if_index > 0 && out_if_index <= if_index) {
1705 ifp = ifindex2ifnet[out_if_index];
1706 }
1707
1708 if (ifp != NULL) {
1709 inp->inp_last_outifp = ifp;
1710 }
1711 ifnet_head_done();
1712
1713 socket_unlock(fd_cb->so, 0);
1714 }
1715 FDUNLOCK(fd_cb);
1716}
1717
1718static void
1719flow_divert_handle_app_map_create(mbuf_t packet, int offset)
1720{
1721 size_t bytes_mem_size;
1722 size_t child_maps_mem_size;
1723 int cursor;
1724 int error = 0;
1725 struct flow_divert_trie new_trie;
1726 int insert_error = 0;
1727 size_t nodes_mem_size;
1728 int prefix_count = 0;
1729 int signing_id_count = 0;
1730
1731 lck_rw_lock_exclusive(&g_flow_divert_group_lck);
1732
1733 /* Re-set the current trie */
1734 if (g_signing_id_trie.memory != NULL) {
1735 FREE(g_signing_id_trie.memory, M_TEMP);
1736 }
1737 memset(&g_signing_id_trie, 0, sizeof(g_signing_id_trie));
1738 g_signing_id_trie.root = NULL_TRIE_IDX;
1739
1740 memset(&new_trie, 0, sizeof(new_trie));
1741
1742 /* Get the number of shared prefixes in the new set of signing ID strings */
1743 flow_divert_packet_get_tlv(packet, offset, FLOW_DIVERT_TLV_PREFIX_COUNT, sizeof(prefix_count), &prefix_count, NULL);
1744
1745 /* Compute the number of signing IDs and the total amount of bytes needed to store them */
1746 for (cursor = flow_divert_packet_find_tlv(packet, offset, FLOW_DIVERT_TLV_SIGNING_ID, &error, 0);
1747 cursor >= 0;
1748 cursor = flow_divert_packet_find_tlv(packet, cursor, FLOW_DIVERT_TLV_SIGNING_ID, &error, 1))
1749 {
1750 size_t sid_size = 0;
1751 flow_divert_packet_get_tlv(packet, cursor, FLOW_DIVERT_TLV_SIGNING_ID, 0, NULL, &sid_size);
1752 new_trie.bytes_count += sid_size;
1753 signing_id_count++;
1754 }
1755
1756 if (signing_id_count == 0) {
1757 lck_rw_done(&g_flow_divert_group_lck);
1758 return;
1759 }
1760
1761 new_trie.nodes_count = (prefix_count + signing_id_count + 1); /* + 1 for the root node */
1762 new_trie.child_maps_count = (prefix_count + 1); /* + 1 for the root node */
1763
1764 FDLOG(LOG_INFO, &nil_pcb, "Nodes count = %lu, child maps count = %lu, bytes_count = %lu",
1765 new_trie.nodes_count, new_trie.child_maps_count, new_trie.bytes_count);
1766
1767 nodes_mem_size = (sizeof(*new_trie.nodes) * new_trie.nodes_count);
1768 child_maps_mem_size = (sizeof(*new_trie.child_maps) * CHILD_MAP_SIZE * new_trie.child_maps_count);
1769 bytes_mem_size = (sizeof(*new_trie.bytes) * new_trie.bytes_count);
1770
1771 MALLOC(new_trie.memory, void *, nodes_mem_size + child_maps_mem_size + bytes_mem_size, M_TEMP, M_WAITOK);
1772 if (new_trie.memory == NULL) {
1773 FDLOG(LOG_ERR, &nil_pcb, "Failed to allocate %lu bytes of memory for the signing ID trie",
1774 nodes_mem_size + child_maps_mem_size + bytes_mem_size);
1775 return;
1776 }
1777
1778 /* Initialize the free lists */
1779 new_trie.nodes = (struct flow_divert_trie_node *)new_trie.memory;
1780 new_trie.nodes_free_next = 0;
1781 memset(new_trie.nodes, 0, nodes_mem_size);
1782
1783 new_trie.child_maps = (uint16_t *)(void *)((uint8_t *)new_trie.memory + nodes_mem_size);
1784 new_trie.child_maps_free_next = 0;
1785 memset(new_trie.child_maps, 0xff, child_maps_mem_size);
1786
1787 new_trie.bytes = (uint8_t *)(void *)((uint8_t *)new_trie.memory + nodes_mem_size + child_maps_mem_size);
1788 new_trie.bytes_free_next = 0;
1789
1790 /* The root is an empty node */
1791 new_trie.root = trie_node_alloc(&new_trie);
1792
1793 /* Add each signing ID to the trie */
1794 for (cursor = flow_divert_packet_find_tlv(packet, offset, FLOW_DIVERT_TLV_SIGNING_ID, &error, 0);
1795 cursor >= 0;
1796 cursor = flow_divert_packet_find_tlv(packet, cursor, FLOW_DIVERT_TLV_SIGNING_ID, &error, 1))
1797 {
1798 size_t sid_size = 0;
1799 flow_divert_packet_get_tlv(packet, cursor, FLOW_DIVERT_TLV_SIGNING_ID, 0, NULL, &sid_size);
1800 if (new_trie.bytes_free_next + sid_size <= new_trie.bytes_count) {
1801 boolean_t is_dns;
1802 uint16_t new_node_idx;
1803 flow_divert_packet_get_tlv(packet, cursor, FLOW_DIVERT_TLV_SIGNING_ID, sid_size, &TRIE_BYTE(&new_trie, new_trie.bytes_free_next), NULL);
1804 is_dns = (sid_size == sizeof(FLOW_DIVERT_DNS_SERVICE_SIGNING_ID) - 1 &&
1805 !memcmp(&TRIE_BYTE(&new_trie, new_trie.bytes_free_next),
1806 FLOW_DIVERT_DNS_SERVICE_SIGNING_ID,
1807 sid_size));
1808 new_node_idx = flow_divert_trie_insert(&new_trie, new_trie.bytes_free_next, sid_size);
1809 if (new_node_idx != NULL_TRIE_IDX) {
1810 if (is_dns) {
fe8ab488 1811 FDLOG(LOG_INFO, &nil_pcb, "Setting group unit for %s to %d", FLOW_DIVERT_DNS_SERVICE_SIGNING_ID, DNS_SERVICE_GROUP_UNIT);
39236c6e
A
1812 TRIE_NODE(&new_trie, new_node_idx).group_unit = DNS_SERVICE_GROUP_UNIT;
1813 }
1814 } else {
1815 insert_error = EINVAL;
1816 break;
1817 }
1818 } else {
1819 FDLOG0(LOG_ERR, &nil_pcb, "No place to put signing ID for insertion");
1820 insert_error = ENOBUFS;
1821 break;
1822 }
1823 }
1824
1825 if (!insert_error) {
1826 g_signing_id_trie = new_trie;
1827 } else {
1828 FREE(new_trie.memory, M_TEMP);
1829 }
1830
1831 lck_rw_done(&g_flow_divert_group_lck);
1832}
1833
1834static void
1835flow_divert_handle_app_map_update(struct flow_divert_group *group, mbuf_t packet, int offset)
1836{
1837 int error = 0;
1838 int cursor;
1839 size_t max_size = 0;
1840 uint8_t *signing_id;
1841 uint32_t ctl_unit;
1842
1843 lck_rw_lock_shared(&group->lck);
1844 ctl_unit = group->ctl_unit;
1845 lck_rw_done(&group->lck);
1846
1847 for (cursor = flow_divert_packet_find_tlv(packet, offset, FLOW_DIVERT_TLV_SIGNING_ID, &error, 0);
1848 cursor >= 0;
1849 cursor = flow_divert_packet_find_tlv(packet, cursor, FLOW_DIVERT_TLV_SIGNING_ID, &error, 1))
1850 {
1851 size_t sid_size = 0;
1852 flow_divert_packet_get_tlv(packet, cursor, FLOW_DIVERT_TLV_SIGNING_ID, 0, NULL, &sid_size);
1853 if (sid_size > max_size) {
1854 max_size = sid_size;
1855 }
1856 }
1857
1858 MALLOC(signing_id, uint8_t *, max_size + 1, M_TEMP, M_WAITOK);
1859 if (signing_id == NULL) {
1860 FDLOG(LOG_ERR, &nil_pcb, "Failed to allocate a string to hold the signing ID (size %lu)", max_size);
1861 return;
1862 }
1863
1864 for (cursor = flow_divert_packet_find_tlv(packet, offset, FLOW_DIVERT_TLV_SIGNING_ID, &error, 0);
1865 cursor >= 0;
1866 cursor = flow_divert_packet_find_tlv(packet, cursor, FLOW_DIVERT_TLV_SIGNING_ID, &error, 1))
1867 {
1868 size_t signing_id_len = 0;
1869 uint16_t node;
1870
1871 flow_divert_packet_get_tlv(packet,
1872 cursor, FLOW_DIVERT_TLV_SIGNING_ID, max_size, signing_id, &signing_id_len);
1873
1874 signing_id[signing_id_len] = '\0';
1875
1876 lck_rw_lock_exclusive(&g_flow_divert_group_lck);
1877
1878 node = flow_divert_trie_search(&g_signing_id_trie, signing_id);
1879 if (node != NULL_TRIE_IDX) {
1880 if (TRIE_NODE(&g_signing_id_trie, node).group_unit != DNS_SERVICE_GROUP_UNIT) {
1881 FDLOG(LOG_INFO, &nil_pcb, "Setting %s to ctl unit %u", signing_id, group->ctl_unit);
1882 TRIE_NODE(&g_signing_id_trie, node).group_unit = ctl_unit;
1883 }
1884 } else {
1885 FDLOG(LOG_ERR, &nil_pcb, "Failed to find signing ID %s", signing_id);
1886 }
1887
1888 lck_rw_done(&g_flow_divert_group_lck);
1889 }
1890
1891 FREE(signing_id, M_TEMP);
1892}
1893
1894static int
1895flow_divert_input(mbuf_t packet, struct flow_divert_group *group)
1896{
1897 struct flow_divert_packet_header hdr;
1898 int error = 0;
1899 struct flow_divert_pcb *fd_cb;
1900
1901 if (mbuf_pkthdr_len(packet) < sizeof(hdr)) {
1902 FDLOG(LOG_ERR, &nil_pcb, "got a bad packet, length (%lu) < sizeof hdr (%lu)", mbuf_pkthdr_len(packet), sizeof(hdr));
1903 error = EINVAL;
1904 goto done;
1905 }
1906
1907 error = mbuf_copydata(packet, 0, sizeof(hdr), &hdr);
1908 if (error) {
1909 FDLOG(LOG_ERR, &nil_pcb, "mbuf_copydata failed for the header: %d", error);
1910 error = ENOBUFS;
1911 goto done;
1912 }
1913
1914 hdr.conn_id = ntohl(hdr.conn_id);
1915
1916 if (hdr.conn_id == 0) {
1917 switch (hdr.packet_type) {
1918 case FLOW_DIVERT_PKT_GROUP_INIT:
1919 flow_divert_handle_group_init(group, packet, sizeof(hdr));
1920 break;
1921 case FLOW_DIVERT_PKT_APP_MAP_CREATE:
1922 flow_divert_handle_app_map_create(packet, sizeof(hdr));
1923 break;
1924 case FLOW_DIVERT_PKT_APP_MAP_UPDATE:
1925 flow_divert_handle_app_map_update(group, packet, sizeof(hdr));
1926 break;
1927 default:
1928 FDLOG(LOG_WARNING, &nil_pcb, "got an unknown message type: %d", hdr.packet_type);
1929 break;
1930 }
1931 goto done;
1932 }
1933
1934 fd_cb = flow_divert_pcb_lookup(hdr.conn_id, group); /* This retains the PCB */
1935 if (fd_cb == NULL) {
1936 if (hdr.packet_type != FLOW_DIVERT_PKT_CLOSE && hdr.packet_type != FLOW_DIVERT_PKT_READ_NOTIFY) {
1937 FDLOG(LOG_NOTICE, &nil_pcb, "got a %s message from group %d for an unknown pcb: %u", flow_divert_packet_type2str(hdr.packet_type), group->ctl_unit, hdr.conn_id);
1938 }
1939 goto done;
1940 }
1941
1942 switch (hdr.packet_type) {
1943 case FLOW_DIVERT_PKT_CONNECT_RESULT:
1944 flow_divert_handle_connect_result(fd_cb, packet, sizeof(hdr));
1945 break;
1946 case FLOW_DIVERT_PKT_CLOSE:
1947 flow_divert_handle_close(fd_cb, packet, sizeof(hdr));
1948 break;
1949 case FLOW_DIVERT_PKT_DATA:
1950 flow_divert_handle_data(fd_cb, packet, sizeof(hdr));
1951 break;
1952 case FLOW_DIVERT_PKT_READ_NOTIFY:
1953 flow_divert_handle_read_notification(fd_cb, packet, sizeof(hdr));
1954 break;
1955 case FLOW_DIVERT_PKT_PROPERTIES_UPDATE:
1956 flow_divert_handle_properties_update(fd_cb, packet, sizeof(hdr));
1957 break;
1958 default:
1959 FDLOG(LOG_WARNING, fd_cb, "got an unknown message type: %d", hdr.packet_type);
1960 break;
1961 }
1962
1963 FDRELEASE(fd_cb);
1964
1965done:
1966 mbuf_free(packet);
1967 return error;
1968}
1969
1970static void
1971flow_divert_close_all(struct flow_divert_group *group)
1972{
1973 struct flow_divert_pcb *fd_cb;
1974 SLIST_HEAD(, flow_divert_pcb) tmp_list;
1975
1976 SLIST_INIT(&tmp_list);
1977
1978 lck_rw_lock_exclusive(&group->lck);
1979
1980 MBUFQ_DRAIN(&group->send_queue);
1981
1982 RB_FOREACH(fd_cb, fd_pcb_tree, &group->pcb_tree) {
1983 FDRETAIN(fd_cb);
1984 SLIST_INSERT_HEAD(&tmp_list, fd_cb, tmp_list_entry);
1985 }
1986
1987 lck_rw_done(&group->lck);
1988
1989 while (!SLIST_EMPTY(&tmp_list)) {
1990 fd_cb = SLIST_FIRST(&tmp_list);
1991 FDLOCK(fd_cb);
1992 SLIST_REMOVE_HEAD(&tmp_list, tmp_list_entry);
1993 if (fd_cb->so != NULL) {
1994 socket_lock(fd_cb->so, 0);
1995 flow_divert_pcb_remove(fd_cb);
1996 flow_divert_update_closed_state(fd_cb, SHUT_RDWR, TRUE);
1997 fd_cb->so->so_error = ECONNABORTED;
1998 socket_unlock(fd_cb->so, 0);
1999 }
2000 FDUNLOCK(fd_cb);
2001 FDRELEASE(fd_cb);
2002 }
2003}
2004
2005void
2006flow_divert_detach(struct socket *so)
2007{
2008 struct flow_divert_pcb *fd_cb = so->so_fd_pcb;
2009
2010 VERIFY((so->so_flags & SOF_FLOW_DIVERT) && so->so_fd_pcb != NULL);
2011
2012 so->so_flags &= ~SOF_FLOW_DIVERT;
2013 so->so_fd_pcb = NULL;
2014
2015 FDLOG(LOG_INFO, fd_cb, "Detaching, ref count = %d", fd_cb->ref_count);
2016
2017 if (fd_cb->group != NULL) {
2018 /* Last-ditch effort to send any buffered data */
2019 flow_divert_send_buffered_data(fd_cb, TRUE);
2020
2021 /* Remove from the group */
2022 flow_divert_pcb_remove(fd_cb);
2023 }
2024
2025 socket_unlock(so, 0);
2026 FDLOCK(fd_cb);
2027 fd_cb->so = NULL;
2028 FDUNLOCK(fd_cb);
2029 socket_lock(so, 0);
2030
2031 FDRELEASE(fd_cb); /* Release the socket's reference */
2032}
2033
2034static int
2035flow_divert_close(struct socket *so)
2036{
2037 struct flow_divert_pcb *fd_cb = so->so_fd_pcb;
2038
2039 VERIFY((so->so_flags & SOF_FLOW_DIVERT) && so->so_fd_pcb != NULL);
2040
2041 FDLOG0(LOG_INFO, fd_cb, "Closing");
2042
2043 soisdisconnecting(so);
2044 sbflush(&so->so_rcv);
2045
2046 flow_divert_send_buffered_data(fd_cb, TRUE);
2047 flow_divert_update_closed_state(fd_cb, SHUT_RDWR, FALSE);
2048 flow_divert_send_close_if_needed(fd_cb);
2049
2050 /* Remove from the group */
2051 flow_divert_pcb_remove(fd_cb);
2052
2053 return 0;
2054}
2055
2056static int
2057flow_divert_disconnectx(struct socket *so, associd_t aid, connid_t cid __unused)
2058{
2059 if (aid != ASSOCID_ANY && aid != ASSOCID_ALL) {
2060 return (EINVAL);
2061 }
2062
2063 return (flow_divert_close(so));
2064}
2065
2066static int
2067flow_divert_shutdown(struct socket *so)
2068{
2069 struct flow_divert_pcb *fd_cb = so->so_fd_pcb;
2070
2071 VERIFY((so->so_flags & SOF_FLOW_DIVERT) && so->so_fd_pcb != NULL);
2072
2073 FDLOG0(LOG_INFO, fd_cb, "Can't send more");
2074
2075 socantsendmore(so);
2076
2077 flow_divert_update_closed_state(fd_cb, SHUT_WR, FALSE);
2078 flow_divert_send_close_if_needed(fd_cb);
2079
2080 return 0;
2081}
2082
2083static int
2084flow_divert_rcvd(struct socket *so, int flags __unused)
2085{
2086 struct flow_divert_pcb *fd_cb = so->so_fd_pcb;
2087 uint32_t latest_sb_size;
2088 uint32_t read_count;
2089
2090 VERIFY((so->so_flags & SOF_FLOW_DIVERT) && so->so_fd_pcb != NULL);
2091
2092 latest_sb_size = fd_cb->so->so_rcv.sb_cc;
2093
2094 if (fd_cb->sb_size < latest_sb_size) {
2095 panic("flow divert rcvd event handler (%u): saved rcv buffer size (%u) is less than latest rcv buffer size (%u)",
2096 fd_cb->hash, fd_cb->sb_size, latest_sb_size);
2097 }
2098
2099 read_count = fd_cb->sb_size - latest_sb_size;
2100
2101 FDLOG(LOG_DEBUG, fd_cb, "app read %u bytes", read_count);
2102
2103 if (read_count > 0 && flow_divert_send_read_notification(fd_cb, read_count) == 0) {
2104 fd_cb->bytes_read_by_app += read_count;
2105 fd_cb->sb_size = latest_sb_size;
2106 }
2107
2108 return 0;
2109}
2110
2111static errno_t
2112flow_divert_dup_addr(sa_family_t family, struct sockaddr *addr,
2113 struct sockaddr **dup)
2114{
2115 int error = 0;
2116 struct sockaddr *result;
2117 struct sockaddr_storage ss;
2118
2119 if (addr != NULL) {
2120 result = addr;
2121 } else {
2122 memset(&ss, 0, sizeof(ss));
2123 ss.ss_family = family;
2124 if (ss.ss_family == AF_INET) {
2125 ss.ss_len = sizeof(struct sockaddr_in);
2126 }
2127#if INET6
2128 else if (ss.ss_family == AF_INET6) {
2129 ss.ss_len = sizeof(struct sockaddr_in6);
2130 }
2131#endif /* INET6 */
2132 else {
2133 error = EINVAL;
2134 }
2135 result = (struct sockaddr *)&ss;
2136 }
2137
2138 if (!error) {
2139 *dup = dup_sockaddr(result, 1);
2140 if (*dup == NULL) {
2141 error = ENOBUFS;
2142 }
2143 }
2144
2145 return error;
2146}
2147
2148static errno_t
2149flow_divert_getpeername(struct socket *so, struct sockaddr **sa)
2150{
2151 struct flow_divert_pcb *fd_cb = so->so_fd_pcb;
2152
2153 VERIFY((so->so_flags & SOF_FLOW_DIVERT) && so->so_fd_pcb != NULL);
2154
2155 return flow_divert_dup_addr(so->so_proto->pr_domain->dom_family,
2156 fd_cb->remote_address,
2157 sa);
2158}
2159
2160static errno_t
2161flow_divert_getsockaddr(struct socket *so, struct sockaddr **sa)
2162{
2163 struct flow_divert_pcb *fd_cb = so->so_fd_pcb;
2164
2165 VERIFY((so->so_flags & SOF_FLOW_DIVERT) && so->so_fd_pcb != NULL);
2166
2167 return flow_divert_dup_addr(so->so_proto->pr_domain->dom_family,
2168 fd_cb->local_address,
2169 sa);
2170}
2171
2172static errno_t
2173flow_divert_ctloutput(struct socket *so, struct sockopt *sopt)
2174{
2175 struct flow_divert_pcb *fd_cb = so->so_fd_pcb;
2176
2177 VERIFY((so->so_flags & SOF_FLOW_DIVERT) && so->so_fd_pcb != NULL);
2178
2179 if (sopt->sopt_name == SO_TRAFFIC_CLASS) {
2180 if (sopt->sopt_dir == SOPT_SET && fd_cb->flags & FLOW_DIVERT_CONNECT_STARTED) {
2181 flow_divert_send_traffic_class_update(fd_cb, so->so_traffic_class);
2182 }
2183 }
2184
2185 if (SOCK_DOM(so) == PF_INET) {
2186 return g_tcp_protosw->pr_ctloutput(so, sopt);
2187 }
2188#if INET6
2189 else if (SOCK_DOM(so) == PF_INET6) {
2190 return g_tcp6_protosw->pr_ctloutput(so, sopt);
2191 }
2192#endif
2193 return 0;
2194}
2195
2196errno_t
2197flow_divert_connect_out(struct socket *so, struct sockaddr *to, proc_t p)
2198{
2199 struct flow_divert_pcb *fd_cb = so->so_fd_pcb;
2200 int error = 0;
2201 struct inpcb *inp = sotoinpcb(so);
2202 struct sockaddr_in *sinp;
fe8ab488
A
2203 mbuf_t connect_packet = NULL;
2204 char *signing_id = NULL;
2205 int free_signing_id = 0;
39236c6e
A
2206
2207 VERIFY((so->so_flags & SOF_FLOW_DIVERT) && so->so_fd_pcb != NULL);
2208
2209 if (fd_cb->group == NULL) {
2210 error = ENETUNREACH;
2211 goto done;
2212 }
2213
2214 if (inp == NULL) {
2215 error = EINVAL;
2216 goto done;
2217 } else if (inp->inp_state == INPCB_STATE_DEAD) {
2218 if (so->so_error) {
2219 error = so->so_error;
2220 so->so_error = 0;
2221 } else {
2222 error = EINVAL;
2223 }
2224 goto done;
2225 }
2226
2227 sinp = (struct sockaddr_in *)(void *)to;
2228 if (sinp->sin_family == AF_INET && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
2229 error = EAFNOSUPPORT;
2230 goto done;
2231 }
2232
2233 if ((fd_cb->flags & FLOW_DIVERT_CONNECT_STARTED) && !(fd_cb->flags & FLOW_DIVERT_TRANSFERRED)) {
2234 error = EALREADY;
2235 goto done;
2236 }
2237
2238 if (fd_cb->flags & FLOW_DIVERT_TRANSFERRED) {
2239 FDLOG0(LOG_INFO, fd_cb, "fully transferred");
2240 fd_cb->flags &= ~FLOW_DIVERT_TRANSFERRED;
2241 if (fd_cb->remote_address != NULL) {
2242 soisconnected(fd_cb->so);
2243 goto done;
2244 }
2245 }
2246
fe8ab488
A
2247 error = flow_divert_packet_init(fd_cb, FLOW_DIVERT_PKT_CONNECT, &connect_packet);
2248 if (error) {
2249 goto done;
2250 }
2251
2252 error = EPERM;
2253
2254 if (fd_cb->connect_token != NULL) {
2255 size_t sid_size = 0;
2256 int find_error = flow_divert_packet_get_tlv(fd_cb->connect_token, 0, FLOW_DIVERT_TLV_SIGNING_ID, 0, NULL, &sid_size);
2257 if (find_error == 0 && sid_size > 0) {
2258 MALLOC(signing_id, char *, sid_size + 1, M_TEMP, M_WAITOK | M_ZERO);
2259 if (signing_id != NULL) {
2260 flow_divert_packet_get_tlv(fd_cb->connect_token, 0, FLOW_DIVERT_TLV_SIGNING_ID, sid_size, signing_id, NULL);
2261 FDLOG(LOG_INFO, fd_cb, "Got %s from token", signing_id);
2262 free_signing_id = 1;
2263 }
2264 }
2265 }
2266
2267 socket_unlock(so, 0);
2268 if (g_signing_id_trie.root != NULL_TRIE_IDX) {
2269 proc_t src_proc = p;
2270 int release_proc = 0;
2271
2272 if (signing_id == NULL) {
2273 release_proc = flow_divert_get_src_proc(so, &src_proc, FALSE);
2274 if (src_proc != PROC_NULL) {
2275 proc_lock(src_proc);
2276 if (src_proc->p_csflags & CS_VALID) {
2277 signing_id = (char *)cs_identity_get(src_proc);
2278 } else {
2279 FDLOG0(LOG_WARNING, fd_cb, "Signature is invalid");
2280 }
2281 } else {
2282 FDLOG0(LOG_WARNING, fd_cb, "Failed to determine the current proc");
2283 }
2284 } else {
2285 src_proc = PROC_NULL;
2286 }
2287
2288 if (signing_id != NULL) {
2289 uint16_t result = NULL_TRIE_IDX;
2290 lck_rw_lock_shared(&g_flow_divert_group_lck);
2291 result = flow_divert_trie_search(&g_signing_id_trie, (const uint8_t *)signing_id);
2292 lck_rw_done(&g_flow_divert_group_lck);
2293 if (result != NULL_TRIE_IDX) {
2294 error = 0;
2295 FDLOG(LOG_INFO, fd_cb, "%s matched", signing_id);
2296
2297 error = flow_divert_packet_append_tlv(connect_packet, FLOW_DIVERT_TLV_SIGNING_ID, strlen(signing_id), signing_id);
2298 if (error == 0) {
2299 if (src_proc != PROC_NULL) {
2300 unsigned char cdhash[SHA1_RESULTLEN];
2301 error = proc_getcdhash(src_proc, cdhash);
2302 if (error == 0) {
2303 error = flow_divert_packet_append_tlv(connect_packet, FLOW_DIVERT_TLV_CDHASH, sizeof(cdhash), cdhash);
2304 if (error) {
2305 FDLOG(LOG_ERR, fd_cb, "failed to append the cdhash: %d", error);
2306 }
2307 } else {
2308 FDLOG(LOG_ERR, fd_cb, "failed to get the cdhash: %d", error);
2309 }
2310 }
2311 } else {
2312 FDLOG(LOG_ERR, fd_cb, "failed to append the signing ID: %d", error);
2313 }
2314 } else {
2315 FDLOG(LOG_WARNING, fd_cb, "%s did not match", signing_id);
2316 }
2317 } else {
2318 FDLOG0(LOG_WARNING, fd_cb, "Failed to get the code signing identity");
2319 }
2320
2321 if (src_proc != PROC_NULL) {
2322 proc_unlock(src_proc);
2323 if (release_proc) {
2324 proc_rele(src_proc);
2325 }
2326 }
2327 } else {
2328 FDLOG0(LOG_WARNING, fd_cb, "The signing ID trie is empty");
2329 }
2330 socket_lock(so, 0);
2331
2332 if (free_signing_id) {
2333 FREE(signing_id, M_TEMP);
2334 }
2335
2336 if (error) {
2337 goto done;
2338 }
2339
39236c6e
A
2340 FDLOG0(LOG_INFO, fd_cb, "Connecting");
2341
fe8ab488 2342 error = flow_divert_send_connect(fd_cb, to, connect_packet);
39236c6e
A
2343 if (error) {
2344 goto done;
2345 }
2346
2347 fd_cb->flags |= FLOW_DIVERT_CONNECT_STARTED;
2348
2349 soisconnecting(so);
2350
2351done:
fe8ab488
A
2352 if (error && connect_packet != NULL) {
2353 mbuf_free(connect_packet);
2354 }
39236c6e
A
2355 return error;
2356}
2357
2358static int
2359flow_divert_connectx_out_common(struct socket *so, int af,
2360 struct sockaddr_list **src_sl, struct sockaddr_list **dst_sl,
2361 struct proc *p, uint32_t ifscope __unused, associd_t aid __unused,
2362 connid_t *pcid, uint32_t flags __unused, void *arg __unused,
2363 uint32_t arglen __unused)
2364{
2365 struct sockaddr_entry *src_se = NULL, *dst_se = NULL;
2366 struct inpcb *inp = sotoinpcb(so);
2367 int error;
2368
2369 if (inp == NULL) {
2370 return (EINVAL);
2371 }
2372
2373 VERIFY(dst_sl != NULL);
2374
2375 /* select source (if specified) and destination addresses */
2376 error = in_selectaddrs(af, src_sl, &src_se, dst_sl, &dst_se);
2377 if (error != 0) {
2378 return (error);
2379 }
2380
2381 VERIFY(*dst_sl != NULL && dst_se != NULL);
2382 VERIFY(src_se == NULL || *src_sl != NULL);
2383 VERIFY(dst_se->se_addr->sa_family == af);
2384 VERIFY(src_se == NULL || src_se->se_addr->sa_family == af);
2385
2386 error = flow_divert_connect_out(so, dst_se->se_addr, p);
2387
2388 if (error == 0 && pcid != NULL) {
2389 *pcid = 1; /* there is only 1 connection for a TCP */
2390 }
2391
2392 return (error);
2393}
2394
2395static int
2396flow_divert_connectx_out(struct socket *so, struct sockaddr_list **src_sl,
2397 struct sockaddr_list **dst_sl, struct proc *p, uint32_t ifscope,
2398 associd_t aid, connid_t *pcid, uint32_t flags, void *arg,
2399 uint32_t arglen)
2400{
2401 return (flow_divert_connectx_out_common(so, AF_INET, src_sl, dst_sl,
2402 p, ifscope, aid, pcid, flags, arg, arglen));
2403}
2404
2405#if INET6
2406static int
2407flow_divert_connectx6_out(struct socket *so, struct sockaddr_list **src_sl,
2408 struct sockaddr_list **dst_sl, struct proc *p, uint32_t ifscope,
2409 associd_t aid, connid_t *pcid, uint32_t flags, void *arg,
2410 uint32_t arglen)
2411{
2412 return (flow_divert_connectx_out_common(so, AF_INET6, src_sl, dst_sl,
2413 p, ifscope, aid, pcid, flags, arg, arglen));
2414}
2415#endif /* INET6 */
2416
2417static int
2418flow_divert_getconninfo(struct socket *so, connid_t cid, uint32_t *flags,
2419 uint32_t *ifindex, int32_t *soerror, user_addr_t src, socklen_t *src_len,
2420 user_addr_t dst, socklen_t *dst_len, uint32_t *aux_type,
2421 user_addr_t aux_data __unused, uint32_t *aux_len)
2422{
2423 int error = 0;
2424 struct flow_divert_pcb *fd_cb = so->so_fd_pcb;
2425 struct ifnet *ifp = NULL;
2426 struct inpcb *inp = sotoinpcb(so);
2427
2428 VERIFY((so->so_flags & SOF_FLOW_DIVERT));
2429
2430 if (so->so_fd_pcb == NULL || inp == NULL) {
2431 error = EINVAL;
2432 goto out;
2433 }
2434
2435 if (cid != CONNID_ANY && cid != CONNID_ALL && cid != 1) {
2436 error = EINVAL;
2437 goto out;
2438 }
2439
2440 ifp = inp->inp_last_outifp;
2441 *ifindex = ((ifp != NULL) ? ifp->if_index : 0);
2442 *soerror = so->so_error;
2443 *flags = 0;
2444
2445 if (so->so_state & SS_ISCONNECTED) {
2446 *flags |= (CIF_CONNECTED | CIF_PREFERRED);
2447 }
2448
2449 if (fd_cb->local_address == NULL) {
2450 struct sockaddr_in sin;
2451 bzero(&sin, sizeof(sin));
2452 sin.sin_len = sizeof(sin);
2453 sin.sin_family = AF_INET;
2454 *src_len = sin.sin_len;
2455 if (src != USER_ADDR_NULL) {
2456 error = copyout(&sin, src, sin.sin_len);
2457 if (error != 0) {
2458 goto out;
2459 }
2460 }
2461 } else {
2462 *src_len = fd_cb->local_address->sa_len;
2463 if (src != USER_ADDR_NULL) {
2464 error = copyout(fd_cb->local_address, src, fd_cb->local_address->sa_len);
2465 if (error != 0) {
2466 goto out;
2467 }
2468 }
2469 }
2470
2471 if (fd_cb->remote_address == NULL) {
2472 struct sockaddr_in sin;
2473 bzero(&sin, sizeof(sin));
2474 sin.sin_len = sizeof(sin);
2475 sin.sin_family = AF_INET;
2476 *dst_len = sin.sin_len;
2477 if (dst != USER_ADDR_NULL) {
2478 error = copyout(&sin, dst, sin.sin_len);
2479 if (error != 0) {
2480 goto out;
2481 }
2482 }
2483 } else {
2484 *dst_len = fd_cb->remote_address->sa_len;
2485 if (dst != USER_ADDR_NULL) {
2486 error = copyout(fd_cb->remote_address, dst, fd_cb->remote_address->sa_len);
2487 if (error != 0) {
2488 goto out;
2489 }
2490 }
2491 }
2492
2493 *aux_type = 0;
2494 *aux_len = 0;
2495
2496out:
2497 return error;
2498}
2499
2500static int
2501flow_divert_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp __unused, struct proc *p __unused)
2502{
2503 int error = 0;
2504
2505 switch (cmd) {
2506 case SIOCGCONNINFO32: {
2507 struct so_cinforeq32 cifr;
2508 bcopy(data, &cifr, sizeof (cifr));
2509 error = flow_divert_getconninfo(so, cifr.scir_cid, &cifr.scir_flags,
2510 &cifr.scir_ifindex, &cifr.scir_error, cifr.scir_src,
2511 &cifr.scir_src_len, cifr.scir_dst, &cifr.scir_dst_len,
2512 &cifr.scir_aux_type, cifr.scir_aux_data,
2513 &cifr.scir_aux_len);
2514 if (error == 0) {
2515 bcopy(&cifr, data, sizeof (cifr));
2516 }
2517 break;
2518 }
2519
2520 case SIOCGCONNINFO64: {
2521 struct so_cinforeq64 cifr;
2522 bcopy(data, &cifr, sizeof (cifr));
2523 error = flow_divert_getconninfo(so, cifr.scir_cid, &cifr.scir_flags,
2524 &cifr.scir_ifindex, &cifr.scir_error, cifr.scir_src,
2525 &cifr.scir_src_len, cifr.scir_dst, &cifr.scir_dst_len,
2526 &cifr.scir_aux_type, cifr.scir_aux_data,
2527 &cifr.scir_aux_len);
2528 if (error == 0) {
2529 bcopy(&cifr, data, sizeof (cifr));
2530 }
2531 break;
2532 }
2533
2534 default:
2535 error = EOPNOTSUPP;
2536 }
2537
2538 return error;
2539}
2540
2541static int
2542flow_divert_in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, struct proc *p)
2543{
2544 int error = flow_divert_control(so, cmd, data, ifp, p);
2545
2546 if (error == EOPNOTSUPP) {
2547 error = in_control(so, cmd, data, ifp, p);
2548 }
2549
2550 return error;
2551}
2552
2553static int
2554flow_divert_in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, struct proc *p)
2555{
2556 int error = flow_divert_control(so, cmd, data, ifp, p);
2557
2558 if (error == EOPNOTSUPP) {
2559 error = in6_control(so, cmd, data, ifp, p);
2560 }
2561
2562 return error;
2563}
2564
2565static errno_t
2566flow_divert_data_out(struct socket *so, int flags, mbuf_t data, struct sockaddr *to, mbuf_t control, struct proc *p __unused)
2567{
2568 struct flow_divert_pcb *fd_cb = so->so_fd_pcb;
2569 int error = 0;
2570 struct inpcb *inp;
2571
2572 VERIFY((so->so_flags & SOF_FLOW_DIVERT) && so->so_fd_pcb != NULL);
2573
2574 inp = sotoinpcb(so);
2575 if (inp == NULL || inp->inp_state == INPCB_STATE_DEAD) {
2576 error = ECONNRESET;
2577 goto done;
2578 }
2579
2580 if (control && mbuf_len(control) > 0) {
2581 error = EINVAL;
2582 goto done;
2583 }
2584
2585 if (flags & MSG_OOB) {
2586 error = EINVAL;
2587 goto done; /* We don't support OOB data */
2588 }
2589
fe8ab488
A
2590 error = flow_divert_check_no_cellular(fd_cb) ||
2591 flow_divert_check_no_expensive(fd_cb);
39236c6e
A
2592 if (error) {
2593 goto done;
2594 }
2595
2596 /* Implicit connect */
2597 if (!(fd_cb->flags & FLOW_DIVERT_CONNECT_STARTED)) {
2598 FDLOG0(LOG_INFO, fd_cb, "implicit connect");
2599 error = flow_divert_connect_out(so, to, NULL);
2600 if (error) {
2601 goto done;
2602 }
2603 }
2604
2605 FDLOG(LOG_DEBUG, fd_cb, "app wrote %lu bytes", mbuf_pkthdr_len(data));
2606
2607 fd_cb->bytes_written_by_app += mbuf_pkthdr_len(data);
2608 error = flow_divert_send_app_data(fd_cb, data);
2609 if (error) {
2610 goto done;
2611 }
2612
2613 data = NULL;
2614
2615 if (flags & PRUS_EOF) {
2616 flow_divert_shutdown(so);
2617 }
2618
2619done:
2620 if (data) {
2621 mbuf_free(data);
2622 }
2623 if (control) {
2624 mbuf_free(control);
2625 }
2626 return error;
2627}
2628
39236c6e
A
2629static void
2630flow_divert_set_protosw(struct socket *so)
2631{
2632 so->so_flags |= SOF_FLOW_DIVERT;
2633 if (SOCK_DOM(so) == PF_INET) {
2634 so->so_proto = &g_flow_divert_in_protosw;
2635 }
2636#if INET6
2637 else {
2638 so->so_proto = (struct protosw *)&g_flow_divert_in6_protosw;
2639 }
2640#endif /* INET6 */
2641}
2642
2643static errno_t
2644flow_divert_attach(struct socket *so, uint32_t flow_id, uint32_t ctl_unit)
2645{
2646 int error = 0;
2647 struct flow_divert_pcb *fd_cb = NULL;
2648 struct ifnet *ifp = NULL;
2649 struct inpcb *inp = NULL;
2650 struct socket *old_so;
2651 mbuf_t recv_data = NULL;
2652
2653 socket_unlock(so, 0);
2654
2655 FDLOG(LOG_INFO, &nil_pcb, "Attaching socket to flow %u", flow_id);
2656
2657 /* Find the flow divert control block */
2658 lck_rw_lock_shared(&g_flow_divert_group_lck);
2659 if (g_flow_divert_groups != NULL && g_active_group_count > 0) {
2660 struct flow_divert_group *group = g_flow_divert_groups[ctl_unit];
2661 if (group != NULL) {
2662 fd_cb = flow_divert_pcb_lookup(flow_id, group);
2663 }
2664 }
2665 lck_rw_done(&g_flow_divert_group_lck);
2666
2667 if (fd_cb == NULL) {
2668 error = ENOENT;
2669 goto done;
2670 }
2671
2672 FDLOCK(fd_cb);
2673
2674 /* Dis-associate the flow divert control block from its current socket */
2675 old_so = fd_cb->so;
2676
2677 inp = sotoinpcb(old_so);
2678
2679 VERIFY(inp != NULL);
2680
2681 socket_lock(old_so, 0);
2682 soisdisconnected(old_so);
2683 old_so->so_flags &= ~SOF_FLOW_DIVERT;
2684 old_so->so_fd_pcb = NULL;
2685 old_so->so_proto = pffindproto(SOCK_DOM(old_so), IPPROTO_TCP, SOCK_STREAM);
2686 fd_cb->so = NULL;
2687 /* Save the output interface */
2688 ifp = inp->inp_last_outifp;
2689 if (old_so->so_rcv.sb_cc > 0) {
2690 error = mbuf_dup(old_so->so_rcv.sb_mb, MBUF_DONTWAIT, &recv_data);
2691 sbflush(&old_so->so_rcv);
2692 }
2693 socket_unlock(old_so, 0);
2694
2695 /* Associate the new socket with the flow divert control block */
2696 socket_lock(so, 0);
2697 so->so_fd_pcb = fd_cb;
2698 inp = sotoinpcb(so);
2699 inp->inp_last_outifp = ifp;
2700 if (recv_data != NULL) {
2701 if (sbappendstream(&so->so_rcv, recv_data)) {
2702 sorwakeup(so);
2703 }
2704 }
2705 flow_divert_set_protosw(so);
2706 socket_unlock(so, 0);
2707
2708 fd_cb->so = so;
2709 fd_cb->flags |= FLOW_DIVERT_TRANSFERRED;
2710
2711 FDUNLOCK(fd_cb);
2712
2713done:
2714 socket_lock(so, 0);
2715
2716 if (fd_cb != NULL) {
2717 FDRELEASE(fd_cb); /* Release the reference obtained via flow_divert_pcb_lookup */
2718 }
2719
2720 return error;
2721}
2722
2723errno_t
2724flow_divert_pcb_init(struct socket *so, uint32_t ctl_unit)
2725{
2726 errno_t error = 0;
2727 struct flow_divert_pcb *fd_cb;
2728
2729 if (so->so_flags & SOF_FLOW_DIVERT) {
2730 return EALREADY;
2731 }
2732
2733 fd_cb = flow_divert_pcb_create(so);
2734 if (fd_cb != NULL) {
2735 error = flow_divert_pcb_insert(fd_cb, ctl_unit);
2736 if (error) {
2737 FDLOG(LOG_ERR, fd_cb, "pcb insert failed: %d", error);
2738 FDRELEASE(fd_cb);
2739 } else {
2740 fd_cb->log_level = LOG_NOTICE;
2741 fd_cb->control_group_unit = ctl_unit;
2742 so->so_fd_pcb = fd_cb;
2743
2744 flow_divert_set_protosw(so);
2745
2746 FDLOG0(LOG_INFO, fd_cb, "Created");
2747 }
2748 } else {
2749 error = ENOMEM;
2750 }
2751
2752 return error;
2753}
2754
2755errno_t
2756flow_divert_token_set(struct socket *so, struct sockopt *sopt)
2757{
2758 uint32_t ctl_unit = 0;
2759 uint32_t key_unit = 0;
2760 uint32_t flow_id = 0;
2761 int error = 0;
2762 mbuf_t token = NULL;
2763
2764 if (so->so_flags & SOF_FLOW_DIVERT) {
2765 error = EALREADY;
2766 goto done;
2767 }
2768
2769 if (g_init_result) {
2770 FDLOG(LOG_ERR, &nil_pcb, "flow_divert_init failed (%d), cannot use flow divert", g_init_result);
2771 error = ENOPROTOOPT;
2772 goto done;
2773 }
2774
2775 if (SOCK_TYPE(so) != SOCK_STREAM ||
2776 SOCK_PROTO(so) != IPPROTO_TCP ||
2777 (SOCK_DOM(so) != PF_INET
2778#if INET6
2779 && SOCK_DOM(so) != PF_INET6
2780#endif
2781 ))
2782 {
2783 error = EINVAL;
2784 goto done;
2785 } else {
2786 struct tcpcb *tp = sototcpcb(so);
2787 if (tp == NULL || tp->t_state != TCPS_CLOSED) {
2788 error = EINVAL;
2789 goto done;
2790 }
2791 }
2792
2793 error = soopt_getm(sopt, &token);
2794 if (error) {
2795 goto done;
2796 }
2797
2798 error = soopt_mcopyin(sopt, token);
2799 if (error) {
2800 goto done;
2801 }
2802
2803 error = flow_divert_packet_get_tlv(token, 0, FLOW_DIVERT_TLV_KEY_UNIT, sizeof(key_unit), (void *)&key_unit, NULL);
2804 if (!error) {
2805 key_unit = ntohl(key_unit);
2806 } else if (error != ENOENT) {
2807 FDLOG(LOG_ERR, &nil_pcb, "Failed to get the key unit from the token: %d", error);
2808 goto done;
2809 } else {
2810 key_unit = 0;
2811 }
2812
2813 error = flow_divert_packet_get_tlv(token, 0, FLOW_DIVERT_TLV_CTL_UNIT, sizeof(ctl_unit), (void *)&ctl_unit, NULL);
2814 if (error) {
2815 FDLOG(LOG_ERR, &nil_pcb, "Failed to get the control socket unit from the token: %d", error);
2816 goto done;
2817 }
2818
2819 /* A valid kernel control unit is required */
2820 ctl_unit = ntohl(ctl_unit);
2821 if (ctl_unit == 0 || ctl_unit >= GROUP_COUNT_MAX) {
2822 FDLOG(LOG_ERR, &nil_pcb, "Got an invalid control socket unit: %u", ctl_unit);
2823 error = EINVAL;
2824 goto done;
2825 }
2826
2827 socket_unlock(so, 0);
2828 error = flow_divert_packet_verify_hmac(token, (key_unit != 0 ? key_unit : ctl_unit));
2829 socket_lock(so, 0);
2830
2831 if (error) {
2832 FDLOG(LOG_ERR, &nil_pcb, "HMAC verfication failed: %d", error);
2833 goto done;
2834 }
2835
2836 error = flow_divert_packet_get_tlv(token, 0, FLOW_DIVERT_TLV_FLOW_ID, sizeof(flow_id), (void *)&flow_id, NULL);
2837 if (error && error != ENOENT) {
2838 FDLOG(LOG_ERR, &nil_pcb, "Failed to get the flow ID from the token: %d", error);
2839 goto done;
2840 }
2841
2842 if (flow_id == 0) {
2843 error = flow_divert_pcb_init(so, ctl_unit);
2844 if (error == 0) {
2845 struct flow_divert_pcb *fd_cb = so->so_fd_pcb;
2846 int log_level = LOG_NOTICE;
2847
2848 error = flow_divert_packet_get_tlv(token, 0, FLOW_DIVERT_TLV_LOG_LEVEL,
2849 sizeof(log_level), &log_level, NULL);
2850 if (error == 0) {
2851 fd_cb->log_level = log_level;
2852 }
2853 error = 0;
2854
2855 fd_cb->connect_token = token;
2856 token = NULL;
2857 }
2858 } else {
2859 error = flow_divert_attach(so, flow_id, ctl_unit);
2860 }
2861
2862done:
2863 if (token != NULL) {
2864 mbuf_freem(token);
2865 }
2866
2867 return error;
2868}
2869
2870errno_t
2871flow_divert_token_get(struct socket *so, struct sockopt *sopt)
2872{
2873 uint32_t ctl_unit;
2874 int error = 0;
2875 uint8_t hmac[SHA_DIGEST_LENGTH];
2876 struct flow_divert_pcb *fd_cb = so->so_fd_pcb;
2877 mbuf_t token = NULL;
2878 struct flow_divert_group *control_group = NULL;
2879
2880 if (!(so->so_flags & SOF_FLOW_DIVERT)) {
2881 error = EINVAL;
2882 goto done;
2883 }
2884
2885 VERIFY((so->so_flags & SOF_FLOW_DIVERT) && so->so_fd_pcb != NULL);
2886
2887 if (fd_cb->group == NULL) {
2888 error = EINVAL;
2889 goto done;
2890 }
2891
2892 error = mbuf_gethdr(MBUF_DONTWAIT, MBUF_TYPE_HEADER, &token);
2893 if (error) {
2894 FDLOG(LOG_ERR, fd_cb, "failed to allocate the header mbuf: %d", error);
2895 goto done;
2896 }
2897
2898 ctl_unit = htonl(fd_cb->group->ctl_unit);
2899
2900 error = flow_divert_packet_append_tlv(token, FLOW_DIVERT_TLV_CTL_UNIT, sizeof(ctl_unit), &ctl_unit);
2901 if (error) {
2902 goto done;
2903 }
2904
2905 error = flow_divert_packet_append_tlv(token, FLOW_DIVERT_TLV_FLOW_ID, sizeof(fd_cb->hash), &fd_cb->hash);
2906 if (error) {
2907 goto done;
2908 }
2909
2910 socket_unlock(so, 0);
2911 lck_rw_lock_shared(&g_flow_divert_group_lck);
2912
2913 if (g_flow_divert_groups != NULL && g_active_group_count > 0 &&
2914 fd_cb->control_group_unit > 0 && fd_cb->control_group_unit < GROUP_COUNT_MAX)
2915 {
2916 control_group = g_flow_divert_groups[fd_cb->control_group_unit];
2917 }
2918
2919 if (control_group != NULL) {
2920 lck_rw_lock_shared(&control_group->lck);
2921 ctl_unit = htonl(control_group->ctl_unit);
2922 error = flow_divert_packet_append_tlv(token, FLOW_DIVERT_TLV_KEY_UNIT, sizeof(ctl_unit), &ctl_unit);
2923 if (!error) {
2924 error = flow_divert_packet_compute_hmac(token, control_group, hmac);
2925 }
2926 lck_rw_done(&control_group->lck);
2927 } else {
2928 error = ENOPROTOOPT;
2929 }
2930
2931 lck_rw_done(&g_flow_divert_group_lck);
2932 socket_lock(so, 0);
2933
2934 if (error) {
2935 goto done;
2936 }
2937
2938 error = flow_divert_packet_append_tlv(token, FLOW_DIVERT_TLV_HMAC, sizeof(hmac), hmac);
2939 if (error) {
2940 goto done;
2941 }
2942
2943 error = soopt_mcopyout(sopt, token);
2944 if (error) {
2945 token = NULL; /* For some reason, soopt_mcopyout() frees the mbuf if it fails */
2946 goto done;
2947 }
2948
2949done:
2950 if (token != NULL) {
2951 mbuf_freem(token);
2952 }
2953
2954 return error;
2955}
2956
2957static errno_t
2958flow_divert_kctl_connect(kern_ctl_ref kctlref __unused, struct sockaddr_ctl *sac, void **unitinfo)
2959{
2960 struct flow_divert_group *new_group;
2961 int error = 0;
2962
2963 if (sac->sc_unit >= GROUP_COUNT_MAX) {
2964 error = EINVAL;
2965 goto done;
2966 }
2967
2968 *unitinfo = NULL;
2969
2970 MALLOC_ZONE(new_group, struct flow_divert_group *, sizeof(*new_group), M_FLOW_DIVERT_GROUP, M_WAITOK);
2971 if (new_group == NULL) {
2972 error = ENOBUFS;
2973 goto done;
2974 }
2975
2976 memset(new_group, 0, sizeof(*new_group));
2977
2978 lck_rw_init(&new_group->lck, flow_divert_mtx_grp, flow_divert_mtx_attr);
2979 RB_INIT(&new_group->pcb_tree);
2980 new_group->ctl_unit = sac->sc_unit;
2981 MBUFQ_INIT(&new_group->send_queue);
2982
2983 lck_rw_lock_exclusive(&g_flow_divert_group_lck);
2984
2985 if (g_flow_divert_groups == NULL) {
2986 MALLOC(g_flow_divert_groups,
2987 struct flow_divert_group **,
2988 GROUP_COUNT_MAX * sizeof(struct flow_divert_group *),
2989 M_TEMP,
2990 M_WAITOK | M_ZERO);
2991 }
2992
2993 if (g_flow_divert_groups == NULL) {
2994 error = ENOBUFS;
2995 } else if (g_flow_divert_groups[sac->sc_unit] != NULL) {
2996 error = EALREADY;
2997 } else {
2998 g_flow_divert_groups[sac->sc_unit] = new_group;
2999 g_active_group_count++;
3000 }
3001
3002 lck_rw_done(&g_flow_divert_group_lck);
3003
3004 *unitinfo = new_group;
3005
3006done:
3007 if (error != 0 && new_group != NULL) {
3008 FREE_ZONE(new_group, sizeof(*new_group), M_FLOW_DIVERT_GROUP);
3009 }
3010 return error;
3011}
3012
3013static errno_t
3014flow_divert_kctl_disconnect(kern_ctl_ref kctlref __unused, uint32_t unit, void *unitinfo)
3015{
3016 struct flow_divert_group *group = NULL;
3017 errno_t error = 0;
3018 uint16_t node = 0;
3019
3020 if (unit >= GROUP_COUNT_MAX) {
3021 return EINVAL;
3022 }
3023
3024 FDLOG(LOG_INFO, &nil_pcb, "disconnecting group %d", unit);
3025
3026 lck_rw_lock_exclusive(&g_flow_divert_group_lck);
3027
3028 if (g_flow_divert_groups == NULL || g_active_group_count == 0) {
3029 panic("flow divert group %u is disconnecting, but no groups are active (groups = %p, active count = %u", unit,
3030 g_flow_divert_groups, g_active_group_count);
3031 }
3032
3033 group = g_flow_divert_groups[unit];
3034
3035 if (group != (struct flow_divert_group *)unitinfo) {
3036 panic("group with unit %d (%p) != unit info (%p)", unit, group, unitinfo);
3037 }
3038
3039 if (group != NULL) {
3040 flow_divert_close_all(group);
3041 if (group->token_key != NULL) {
3042 memset(group->token_key, 0, group->token_key_size);
3043 FREE(group->token_key, M_TEMP);
3044 group->token_key = NULL;
3045 group->token_key_size = 0;
3046 }
3047 FREE_ZONE(group, sizeof(*group), M_FLOW_DIVERT_GROUP);
3048 g_flow_divert_groups[unit] = NULL;
3049 g_active_group_count--;
3050 } else {
3051 error = EINVAL;
3052 }
3053
3054 if (g_active_group_count == 0) {
3055 FREE(g_flow_divert_groups, M_TEMP);
3056 g_flow_divert_groups = NULL;
3057 }
3058
3059 /* Remove all signing IDs that point to this unit */
3060 for (node = 0; node < g_signing_id_trie.nodes_count; node++) {
3061 if (TRIE_NODE(&g_signing_id_trie, node).group_unit == unit) {
3062 TRIE_NODE(&g_signing_id_trie, node).group_unit = 0;
3063 }
3064 }
3065
3066 lck_rw_done(&g_flow_divert_group_lck);
3067
3068 return error;
3069}
3070
3071static errno_t
3072flow_divert_kctl_send(kern_ctl_ref kctlref __unused, uint32_t unit __unused, void *unitinfo, mbuf_t m, int flags __unused)
3073{
3074 return flow_divert_input(m, (struct flow_divert_group *)unitinfo);
3075}
3076
3077static void
3078flow_divert_kctl_rcvd(kern_ctl_ref kctlref __unused, uint32_t unit __unused, void *unitinfo, int flags __unused)
3079{
3080 struct flow_divert_group *group = (struct flow_divert_group *)unitinfo;
3081
3082 if (!OSTestAndClear(GROUP_BIT_CTL_ENQUEUE_BLOCKED, &group->atomic_bits)) {
3083 struct flow_divert_pcb *fd_cb;
3084 SLIST_HEAD(, flow_divert_pcb) tmp_list;
3085
3086 lck_rw_lock_shared(&g_flow_divert_group_lck);
3087 lck_rw_lock_exclusive(&group->lck);
3088
3089 while (!MBUFQ_EMPTY(&group->send_queue)) {
3090 mbuf_t next_packet;
3091 FDLOG0(LOG_DEBUG, &nil_pcb, "trying ctl_enqueuembuf again");
3092 next_packet = MBUFQ_FIRST(&group->send_queue);
3093 int error = ctl_enqueuembuf(g_flow_divert_kctl_ref, group->ctl_unit, next_packet, CTL_DATA_EOR);
3094 if (error) {
3095 FDLOG(LOG_DEBUG, &nil_pcb, "ctl_enqueuembuf returned an error: %d", error);
3096 OSTestAndSet(GROUP_BIT_CTL_ENQUEUE_BLOCKED, &group->atomic_bits);
3097 lck_rw_done(&group->lck);
3098 lck_rw_done(&g_flow_divert_group_lck);
3099 return;
3100 }
3101 MBUFQ_DEQUEUE(&group->send_queue, next_packet);
3102 }
3103
3104 SLIST_INIT(&tmp_list);
3105
3106 RB_FOREACH(fd_cb, fd_pcb_tree, &group->pcb_tree) {
3107 FDRETAIN(fd_cb);
3108 SLIST_INSERT_HEAD(&tmp_list, fd_cb, tmp_list_entry);
3109 }
3110
3111 lck_rw_done(&group->lck);
3112
3113 SLIST_FOREACH(fd_cb, &tmp_list, tmp_list_entry) {
3114 FDLOCK(fd_cb);
3115 if (fd_cb->so != NULL) {
3116 socket_lock(fd_cb->so, 0);
3117 if (fd_cb->group != NULL) {
3118 flow_divert_send_buffered_data(fd_cb, FALSE);
3119 }
3120 socket_unlock(fd_cb->so, 0);
3121 }
3122 FDUNLOCK(fd_cb);
3123 FDRELEASE(fd_cb);
3124 }
3125
3126 lck_rw_done(&g_flow_divert_group_lck);
3127 }
3128}
3129
3130static int
3131flow_divert_kctl_init(void)
3132{
3133 struct kern_ctl_reg ctl_reg;
3134 int result;
3135
3136 memset(&ctl_reg, 0, sizeof(ctl_reg));
3137
fe8ab488 3138 strlcpy(ctl_reg.ctl_name, FLOW_DIVERT_CONTROL_NAME, sizeof(ctl_reg.ctl_name));
39236c6e
A
3139 ctl_reg.ctl_name[sizeof(ctl_reg.ctl_name)-1] = '\0';
3140 ctl_reg.ctl_flags = CTL_FLAG_PRIVILEGED | CTL_FLAG_REG_EXTENDED;
3141 ctl_reg.ctl_sendsize = FD_CTL_SENDBUFF_SIZE;
3142 ctl_reg.ctl_recvsize = FD_CTL_RCVBUFF_SIZE;
3143
3144 ctl_reg.ctl_connect = flow_divert_kctl_connect;
3145 ctl_reg.ctl_disconnect = flow_divert_kctl_disconnect;
3146 ctl_reg.ctl_send = flow_divert_kctl_send;
3147 ctl_reg.ctl_rcvd = flow_divert_kctl_rcvd;
3148
3149 result = ctl_register(&ctl_reg, &g_flow_divert_kctl_ref);
3150
3151 if (result) {
3152 FDLOG(LOG_ERR, &nil_pcb, "flow_divert_kctl_init - ctl_register failed: %d\n", result);
3153 return result;
3154 }
3155
3156 return 0;
3157}
3158
3159void
3160flow_divert_init(void)
3161{
3162 memset(&nil_pcb, 0, sizeof(nil_pcb));
fe8ab488 3163 nil_pcb.log_level = LOG_NOTICE;
39236c6e
A
3164
3165 g_tcp_protosw = pffindproto(AF_INET, IPPROTO_TCP, SOCK_STREAM);
3166
3167 VERIFY(g_tcp_protosw != NULL);
3168
3169 memcpy(&g_flow_divert_in_protosw, g_tcp_protosw, sizeof(g_flow_divert_in_protosw));
3170 memcpy(&g_flow_divert_in_usrreqs, g_tcp_protosw->pr_usrreqs, sizeof(g_flow_divert_in_usrreqs));
3171
3172 g_flow_divert_in_usrreqs.pru_connect = flow_divert_connect_out;
3173 g_flow_divert_in_usrreqs.pru_connectx = flow_divert_connectx_out;
3174 g_flow_divert_in_usrreqs.pru_control = flow_divert_in_control;
3175 g_flow_divert_in_usrreqs.pru_disconnect = flow_divert_close;
3176 g_flow_divert_in_usrreqs.pru_disconnectx = flow_divert_disconnectx;
3177 g_flow_divert_in_usrreqs.pru_peeraddr = flow_divert_getpeername;
3178 g_flow_divert_in_usrreqs.pru_rcvd = flow_divert_rcvd;
3179 g_flow_divert_in_usrreqs.pru_send = flow_divert_data_out;
3180 g_flow_divert_in_usrreqs.pru_shutdown = flow_divert_shutdown;
3181 g_flow_divert_in_usrreqs.pru_sockaddr = flow_divert_getsockaddr;
3182
3183 g_flow_divert_in_protosw.pr_usrreqs = &g_flow_divert_in_usrreqs;
3184 g_flow_divert_in_protosw.pr_ctloutput = flow_divert_ctloutput;
3185
3186 /*
3187 * Socket filters shouldn't attach/detach to/from this protosw
3188 * since pr_protosw is to be used instead, which points to the
3189 * real protocol; if they do, it is a bug and we should panic.
3190 */
3191 g_flow_divert_in_protosw.pr_filter_head.tqh_first =
3192 (struct socket_filter *)(uintptr_t)0xdeadbeefdeadbeef;
3193 g_flow_divert_in_protosw.pr_filter_head.tqh_last =
3194 (struct socket_filter **)(uintptr_t)0xdeadbeefdeadbeef;
3195
3196#if INET6
3197 g_tcp6_protosw = (struct ip6protosw *)pffindproto(AF_INET6, IPPROTO_TCP, SOCK_STREAM);
3198
3199 VERIFY(g_tcp6_protosw != NULL);
3200
3201 memcpy(&g_flow_divert_in6_protosw, g_tcp6_protosw, sizeof(g_flow_divert_in6_protosw));
3202 memcpy(&g_flow_divert_in6_usrreqs, g_tcp6_protosw->pr_usrreqs, sizeof(g_flow_divert_in6_usrreqs));
3203
3204 g_flow_divert_in6_usrreqs.pru_connect = flow_divert_connect_out;
3205 g_flow_divert_in6_usrreqs.pru_connectx = flow_divert_connectx6_out;
3206 g_flow_divert_in6_usrreqs.pru_control = flow_divert_in6_control;
3207 g_flow_divert_in6_usrreqs.pru_disconnect = flow_divert_close;
3208 g_flow_divert_in6_usrreqs.pru_disconnectx = flow_divert_disconnectx;
3209 g_flow_divert_in6_usrreqs.pru_peeraddr = flow_divert_getpeername;
3210 g_flow_divert_in6_usrreqs.pru_rcvd = flow_divert_rcvd;
3211 g_flow_divert_in6_usrreqs.pru_send = flow_divert_data_out;
3212 g_flow_divert_in6_usrreqs.pru_shutdown = flow_divert_shutdown;
3213 g_flow_divert_in6_usrreqs.pru_sockaddr = flow_divert_getsockaddr;
3214
3215 g_flow_divert_in6_protosw.pr_usrreqs = &g_flow_divert_in6_usrreqs;
3216 g_flow_divert_in6_protosw.pr_ctloutput = flow_divert_ctloutput;
3217 /*
3218 * Socket filters shouldn't attach/detach to/from this protosw
3219 * since pr_protosw is to be used instead, which points to the
3220 * real protocol; if they do, it is a bug and we should panic.
3221 */
3222 g_flow_divert_in6_protosw.pr_filter_head.tqh_first =
3223 (struct socket_filter *)(uintptr_t)0xdeadbeefdeadbeef;
3224 g_flow_divert_in6_protosw.pr_filter_head.tqh_last =
3225 (struct socket_filter **)(uintptr_t)0xdeadbeefdeadbeef;
3226#endif /* INET6 */
3227
3228 flow_divert_grp_attr = lck_grp_attr_alloc_init();
3229 if (flow_divert_grp_attr == NULL) {
3230 FDLOG0(LOG_ERR, &nil_pcb, "lck_grp_attr_alloc_init failed");
3231 g_init_result = ENOMEM;
3232 goto done;
3233 }
3234
3235 flow_divert_mtx_grp = lck_grp_alloc_init(FLOW_DIVERT_CONTROL_NAME, flow_divert_grp_attr);
3236 if (flow_divert_mtx_grp == NULL) {
3237 FDLOG0(LOG_ERR, &nil_pcb, "lck_grp_alloc_init failed");
3238 g_init_result = ENOMEM;
3239 goto done;
3240 }
3241
3242 flow_divert_mtx_attr = lck_attr_alloc_init();
3243 if (flow_divert_mtx_attr == NULL) {
3244 FDLOG0(LOG_ERR, &nil_pcb, "lck_attr_alloc_init failed");
3245 g_init_result = ENOMEM;
3246 goto done;
3247 }
3248
3249 g_init_result = flow_divert_kctl_init();
3250 if (g_init_result) {
3251 goto done;
3252 }
3253
3254 lck_rw_init(&g_flow_divert_group_lck, flow_divert_mtx_grp, flow_divert_mtx_attr);
3255
3256 memset(&g_signing_id_trie, 0, sizeof(g_signing_id_trie));
3257 g_signing_id_trie.root = NULL_TRIE_IDX;
3258
3259done:
3260 if (g_init_result != 0) {
3261 if (flow_divert_mtx_attr != NULL) {
3262 lck_attr_free(flow_divert_mtx_attr);
3263 flow_divert_mtx_attr = NULL;
3264 }
3265 if (flow_divert_mtx_grp != NULL) {
3266 lck_grp_free(flow_divert_mtx_grp);
3267 flow_divert_mtx_grp = NULL;
3268 }
3269 if (flow_divert_grp_attr != NULL) {
3270 lck_grp_attr_free(flow_divert_grp_attr);
3271 flow_divert_grp_attr = NULL;
3272 }
3273
3274 if (g_flow_divert_kctl_ref != NULL) {
3275 ctl_deregister(g_flow_divert_kctl_ref);
3276 g_flow_divert_kctl_ref = NULL;
3277 }
3278 }
3279}