2 * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
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>
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>
60 #include <netinet6/ip6protosw.h>
62 #include <dev/random/randomdev.h>
63 #include <libkern/crypto/sha1.h>
64 #include <libkern/crypto/crypto_internal.h>
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
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__); \
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); \
85 #define FDRETAIN(pcb) if ((pcb) != NULL) OSIncrementAtomic(&(pcb)->ref_count)
86 #define FDRELEASE(pcb) \
88 if ((pcb) != NULL && 1 == OSDecrementAtomic(&(pcb)->ref_count)) { \
89 flow_divert_pcb_destroy(pcb); \
93 #define FDLOCK(pcb) lck_mtx_lock(&(pcb)->mtx)
94 #define FDUNLOCK(pcb) lck_mtx_unlock(&(pcb)->mtx)
96 #define FD_CTL_SENDBUFF_SIZE (2 * FLOW_DIVERT_CHUNK_SIZE)
97 #define FD_CTL_RCVBUFF_SIZE (128 * 1024)
99 #define GROUP_BIT_CTL_ENQUEUE_BLOCKED 0
101 #define GROUP_COUNT_MAX 32
102 #define FLOW_DIVERT_MAX_NAME_SIZE 4096
103 #define FLOW_DIVERT_MAX_KEY_SIZE 1024
105 #define DNS_SERVICE_GROUP_UNIT (GROUP_COUNT_MAX + 1)
107 struct flow_divert_trie_node
115 struct flow_divert_trie
117 struct flow_divert_trie_node
*nodes
;
118 uint16_t *child_maps
;
122 size_t child_maps_count
;
124 size_t nodes_free_next
;
125 size_t child_maps_free_next
;
126 size_t bytes_free_next
;
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)])
136 static struct flow_divert_pcb nil_pcb
;
138 decl_lck_rw_data(static, g_flow_divert_group_lck
);
139 static struct flow_divert_group
**g_flow_divert_groups
= NULL
;
140 static uint32_t g_active_group_count
= 0;
141 static struct flow_divert_trie g_signing_id_trie
;
143 static lck_grp_attr_t
*flow_divert_grp_attr
= NULL
;
144 static lck_attr_t
*flow_divert_mtx_attr
= NULL
;
145 static lck_grp_t
*flow_divert_mtx_grp
= NULL
;
146 static errno_t g_init_result
= 0;
148 static kern_ctl_ref g_flow_divert_kctl_ref
= NULL
;
150 static struct protosw g_flow_divert_in_protosw
;
151 static struct pr_usrreqs g_flow_divert_in_usrreqs
;
153 static struct ip6protosw g_flow_divert_in6_protosw
;
154 static struct pr_usrreqs g_flow_divert_in6_usrreqs
;
157 static struct protosw
*g_tcp_protosw
= NULL
;
158 static struct ip6protosw
*g_tcp6_protosw
= NULL
;
161 flow_divert_pcb_cmp(const struct flow_divert_pcb
*pcb_a
, const struct flow_divert_pcb
*pcb_b
)
163 return memcmp(&pcb_a
->hash
, &pcb_b
->hash
, sizeof(pcb_a
->hash
));
166 RB_PROTOTYPE(fd_pcb_tree
, flow_divert_pcb
, rb_link
, flow_divert_pcb_cmp
);
167 RB_GENERATE(fd_pcb_tree
, flow_divert_pcb
, rb_link
, flow_divert_pcb_cmp
);
170 flow_divert_packet_type2str(uint8_t packet_type
)
172 switch (packet_type
) {
173 case FLOW_DIVERT_PKT_CONNECT
:
175 case FLOW_DIVERT_PKT_CONNECT_RESULT
:
176 return "connect result";
177 case FLOW_DIVERT_PKT_DATA
:
179 case FLOW_DIVERT_PKT_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";
194 static struct flow_divert_pcb
*
195 flow_divert_pcb_lookup(uint32_t hash
, struct flow_divert_group
*group
)
197 struct flow_divert_pcb key_item
;
198 struct flow_divert_pcb
*fd_cb
= NULL
;
200 key_item
.hash
= hash
;
202 lck_rw_lock_shared(&group
->lck
);
203 fd_cb
= RB_FIND(fd_pcb_tree
, &group
->pcb_tree
, &key_item
);
205 lck_rw_done(&group
->lck
);
211 flow_divert_pcb_insert(struct flow_divert_pcb
*fd_cb
, uint32_t ctl_unit
)
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;
221 if (ctl_unit
== 0 || ctl_unit
>= GROUP_COUNT_MAX
) {
225 socket_unlock(fd_cb
->so
, 0);
226 lck_rw_lock_shared(&g_flow_divert_group_lck
);
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");
234 group
= g_flow_divert_groups
[ctl_unit
];
236 FDLOG(LOG_ERR
, &nil_pcb
, "Group for control unit %u is NULL, flow divert cannot be used for this socket", ctl_unit
);
241 socket_lock(fd_cb
->so
, 0);
247 key
[0] = g_nextkey
++;
248 key
[1] = RandomULong();
250 if (g_hash_seed
== 0) {
251 g_hash_seed
= RandomULong();
254 fd_cb
->hash
= net_flowhash(key
, sizeof(key
), g_hash_seed
);
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
);
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
);
273 } while (exist
!= NULL
&& try_count
++ < 3);
276 fd_cb
->group
= group
;
277 FDRETAIN(fd_cb
); /* The group now has a reference */
283 socket_unlock(fd_cb
->so
, 0);
286 lck_rw_done(&g_flow_divert_group_lck
);
287 socket_lock(fd_cb
->so
, 0);
292 static struct flow_divert_pcb
*
293 flow_divert_pcb_create(socket_t so
)
295 struct flow_divert_pcb
*new_pcb
= NULL
;
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");
303 memset(new_pcb
, 0, sizeof(*new_pcb
));
305 lck_mtx_init(&new_pcb
->mtx
, flow_divert_mtx_grp
, flow_divert_mtx_attr
);
307 new_pcb
->log_level
= nil_pcb
.log_level
;
309 FDRETAIN(new_pcb
); /* Represents the socket's reference */
315 flow_divert_pcb_destroy(struct flow_divert_pcb
*fd_cb
)
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
);
320 if (fd_cb
->local_address
!= NULL
) {
321 FREE(fd_cb
->local_address
, M_SONAME
);
323 if (fd_cb
->remote_address
!= NULL
) {
324 FREE(fd_cb
->remote_address
, M_SONAME
);
326 if (fd_cb
->connect_token
!= NULL
) {
327 mbuf_freem(fd_cb
->connect_token
);
329 FREE_ZONE(fd_cb
, sizeof(*fd_cb
), M_FLOW_DIVERT_PCB
);
333 flow_divert_pcb_remove(struct flow_divert_pcb
*fd_cb
)
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
);
341 FDRELEASE(fd_cb
); /* Release the group's reference */
342 lck_rw_done(&group
->lck
);
347 flow_divert_packet_init(struct flow_divert_pcb
*fd_cb
, uint8_t packet_type
, mbuf_t
*packet
)
349 struct flow_divert_packet_header hdr
;
352 error
= mbuf_gethdr(MBUF_DONTWAIT
, MBUF_TYPE_HEADER
, packet
);
354 FDLOG(LOG_ERR
, fd_cb
, "failed to allocate the header mbuf: %d", error
);
358 hdr
.packet_type
= packet_type
;
359 hdr
.conn_id
= htonl(fd_cb
->hash
);
361 /* Lay down the header */
362 error
= mbuf_copyback(*packet
, 0, sizeof(hdr
), &hdr
, MBUF_DONTWAIT
);
364 FDLOG(LOG_ERR
, fd_cb
, "mbuf_copyback(hdr) failed: %d", error
);
374 flow_divert_packet_append_tlv(mbuf_t packet
, uint8_t type
, size_t length
, const void *value
)
376 size_t net_length
= htonl(length
);
379 error
= mbuf_copyback(packet
, mbuf_pkthdr_len(packet
), sizeof(type
), &type
, MBUF_DONTWAIT
);
381 FDLOG(LOG_ERR
, &nil_pcb
, "failed to append the type (%d)", type
);
385 error
= mbuf_copyback(packet
, mbuf_pkthdr_len(packet
), sizeof(net_length
), &net_length
, MBUF_DONTWAIT
);
387 FDLOG(LOG_ERR
, &nil_pcb
, "failed to append the length (%lu)", length
);
391 error
= mbuf_copyback(packet
, mbuf_pkthdr_len(packet
), length
, value
, MBUF_DONTWAIT
);
393 FDLOG0(LOG_ERR
, &nil_pcb
, "failed to append the value");
401 flow_divert_packet_find_tlv(mbuf_t packet
, int offset
, uint8_t type
, int *err
, int next
)
403 size_t cursor
= offset
;
412 error
= mbuf_copydata(packet
, cursor
, sizeof(curr_type
), &curr_type
);
419 curr_type
= FLOW_DIVERT_TLV_NIL
;
422 if (curr_type
!= type
) {
423 cursor
+= sizeof(curr_type
);
424 error
= mbuf_copydata(packet
, cursor
, sizeof(curr_length
), &curr_length
);
430 cursor
+= (sizeof(curr_length
) + ntohl(curr_length
));
432 } while (curr_type
!= type
);
438 flow_divert_packet_get_tlv(mbuf_t packet
, int offset
, uint8_t type
, size_t buff_len
, void *buff
, size_t *val_size
)
444 tlv_offset
= flow_divert_packet_find_tlv(packet
, offset
, type
, &error
, 0);
445 if (tlv_offset
< 0) {
449 error
= mbuf_copydata(packet
, tlv_offset
+ sizeof(type
), sizeof(length
), &length
);
454 length
= ntohl(length
);
456 if (val_size
!= NULL
) {
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
);
472 flow_divert_packet_compute_hmac(mbuf_t packet
, struct flow_divert_group
*group
, uint8_t *hmac
)
474 mbuf_t curr_mbuf
= packet
;
476 if (g_crypto_funcs
== NULL
|| group
->token_key
== NULL
) {
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
);
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
);
488 g_crypto_funcs
->cchmac_final_fn(g_crypto_funcs
->ccsha1_di
, hmac_ctx
, hmac
);
494 flow_divert_packet_verify_hmac(mbuf_t packet
, uint32_t ctl_unit
)
497 struct flow_divert_group
*group
= NULL
;
499 uint8_t packet_hmac
[SHA_DIGEST_LENGTH
];
500 uint8_t computed_hmac
[SHA_DIGEST_LENGTH
];
503 lck_rw_lock_shared(&g_flow_divert_group_lck
);
505 if (g_flow_divert_groups
!= NULL
&& g_active_group_count
> 0) {
506 group
= g_flow_divert_groups
[ctl_unit
];
510 lck_rw_done(&g_flow_divert_group_lck
);
514 lck_rw_lock_shared(&group
->lck
);
516 if (group
->token_key
== NULL
) {
521 hmac_offset
= flow_divert_packet_find_tlv(packet
, 0, FLOW_DIVERT_TLV_HMAC
, &error
, 0);
522 if (hmac_offset
< 0) {
526 error
= flow_divert_packet_get_tlv(packet
, hmac_offset
, FLOW_DIVERT_TLV_HMAC
, sizeof(packet_hmac
), packet_hmac
, NULL
);
531 /* Chop off the HMAC TLV */
532 error
= mbuf_split(packet
, hmac_offset
, MBUF_WAITOK
, &tail
);
539 error
= flow_divert_packet_compute_hmac(packet
, group
, computed_hmac
);
544 if (memcmp(packet_hmac
, computed_hmac
, sizeof(packet_hmac
))) {
545 FDLOG0(LOG_WARNING
, &nil_pcb
, "HMAC in token does not match computed HMAC");
551 lck_rw_done(&group
->lck
);
552 lck_rw_done(&g_flow_divert_group_lck
);
557 flow_divert_add_data_statistics(struct flow_divert_pcb
*fd_cb
, int data_len
, Boolean send
)
559 struct inpcb
*inp
= NULL
;
560 struct ifnet
*ifp
= NULL
;
561 Boolean cell
= FALSE
;
562 Boolean wifi
= FALSE
;
563 Boolean wired
= FALSE
;
565 inp
= sotoinpcb(fd_cb
->so
);
570 ifp
= inp
->inp_last_outifp
;
572 cell
= IFNET_IS_CELLULAR(ifp
);
573 wifi
= (!cell
&& IFNET_IS_WIFI(ifp
));
574 wired
= (!wifi
&& IFNET_IS_WIRED(ifp
));
578 INP_ADD_STAT(inp
, cell
, wifi
, wired
, txpackets
, 1);
579 INP_ADD_STAT(inp
, cell
, wifi
, wired
, txbytes
, data_len
);
581 INP_ADD_STAT(inp
, cell
, wifi
, wired
, rxpackets
, 1);
582 INP_ADD_STAT(inp
, cell
, wifi
, wired
, rxbytes
, data_len
);
587 flow_divert_check_no_cellular(struct flow_divert_pcb
*fd_cb
)
589 struct inpcb
*inp
= NULL
;
591 inp
= sotoinpcb(fd_cb
->so
);
592 if (inp
&& INP_NO_CELLULAR(inp
) && inp
->inp_last_outifp
&&
593 IFNET_IS_CELLULAR(inp
->inp_last_outifp
))
600 flow_divert_check_no_expensive(struct flow_divert_pcb
*fd_cb
)
602 struct inpcb
*inp
= NULL
;
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
))
613 flow_divert_update_closed_state(struct flow_divert_pcb
*fd_cb
, int how
, Boolean tunnel
)
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
);
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
;
632 trie_node_alloc(struct flow_divert_trie
*trie
)
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
;
639 return NULL_TRIE_IDX
;
644 trie_child_map_alloc(struct flow_divert_trie
*trie
)
646 if (trie
->child_maps_free_next
< trie
->child_maps_count
) {
647 return trie
->child_maps_free_next
++;
649 return NULL_TRIE_IDX
;
654 trie_bytes_move(struct flow_divert_trie
*trie
, uint16_t bytes_idx
, size_t bytes_size
)
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
);
661 trie
->bytes_free_next
+= bytes_size
;
664 return NULL_TRIE_IDX
;
669 flow_divert_trie_insert(struct flow_divert_trie
*trie
, uint16_t string_start
, size_t string_len
)
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
;
677 while (child
!= NULL_TRIE_IDX
) {
678 uint16_t parent
= current
;
680 uint16_t current_end
;
683 child
= NULL_TRIE_IDX
;
685 current_end
= TRIE_NODE(trie
, current
).start
+ TRIE_NODE(trie
, current
).length
;
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
++);
693 string_remainder
= string_end
- string_idx
;
695 if (node_idx
< (TRIE_NODE(trie
, current
).start
+ TRIE_NODE(trie
, current
).length
)) {
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.
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
;
711 * Prefix points to the portion of the current nodes's string that has matched
712 * the input string thus far.
714 TRIE_NODE(trie
, prefix
).start
= TRIE_NODE(trie
, current
).start
;
715 TRIE_NODE(trie
, prefix
).length
= (node_idx
- TRIE_NODE(trie
, current
).start
);
718 * Prefix has the current node as the child corresponding to the first byte
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
;
726 TRIE_CHILD(trie
, prefix
, TRIE_BYTE(trie
, node_idx
)) = current
;
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
;
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
;
735 /* We want to insert the new leaf (if any) as a child of the prefix */
739 if (string_remainder
> 0) {
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.
745 if (TRIE_NODE(trie
, current
).child_map
!= NULL_TRIE_IDX
) {
746 child
= TRIE_CHILD(trie
, current
, TRIE_BYTE(trie
, string_idx
));
749 } /* while (child != NULL_TRIE_IDX) */
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
;
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
;
764 TRIE_NODE(trie
, leaf
).length
= string_remainder
;
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
;
774 TRIE_CHILD(trie
, current
, TRIE_BYTE(trie
, TRIE_NODE(trie
, leaf
).start
)) = leaf
;
776 } /* else duplicate or this string is a prefix of one of the existing strings */
782 flow_divert_trie_search(struct flow_divert_trie
*trie
, const uint8_t *string_bytes
)
784 uint16_t current
= trie
->root
;
785 uint16_t string_idx
= 0;
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
;
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
++);
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
]);
806 return NULL_TRIE_IDX
;
810 flow_divert_get_src_proc(struct socket
*so
, proc_t
*proc
, boolean_t match_delegate
)
814 if (!match_delegate
&&
815 (so
->so_flags
& SOF_DELEGATED
) &&
816 (*proc
== PROC_NULL
|| (*proc
)->p_pid
!= so
->e_pid
))
818 *proc
= proc_find(so
->e_pid
);
820 } else if (*proc
== PROC_NULL
) {
821 *proc
= current_proc();
824 if (*proc
!= PROC_NULL
) {
825 if ((*proc
)->p_pid
== 0) {
838 flow_divert_send_packet(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, Boolean enqueue
)
842 if (fd_cb
->group
== NULL
) {
843 fd_cb
->so
->so_error
= ECONNABORTED
;
844 soisdisconnected(fd_cb
->so
);
848 lck_rw_lock_shared(&fd_cb
->group
->lck
);
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
);
856 if (error
== ENOBUFS
) {
858 if (!lck_rw_lock_shared_to_exclusive(&fd_cb
->group
->lck
)) {
859 lck_rw_lock_exclusive(&fd_cb
->group
->lck
);
861 MBUFQ_ENQUEUE(&fd_cb
->group
->send_queue
, packet
);
864 OSTestAndSet(GROUP_BIT_CTL_ENQUEUE_BLOCKED
, &fd_cb
->group
->atomic_bits
);
867 lck_rw_done(&fd_cb
->group
->lck
);
873 flow_divert_send_connect(struct flow_divert_pcb
*fd_cb
, struct sockaddr
*to
, mbuf_t connect_packet
)
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
);
885 if (fd_cb
->so
->so_flags
& SOF_DELEGATED
) {
886 error
= flow_divert_packet_append_tlv(connect_packet
,
888 sizeof(fd_cb
->so
->e_pid
),
894 error
= flow_divert_packet_append_tlv(connect_packet
,
895 FLOW_DIVERT_TLV_UUID
,
896 sizeof(fd_cb
->so
->e_uuid
),
902 error
= flow_divert_packet_append_tlv(connect_packet
,
904 sizeof(fd_cb
->so
->e_pid
),
905 &fd_cb
->so
->last_pid
);
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
);
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
;
925 uint32_t ctl_unit
= htonl(fd_cb
->control_group_unit
);
928 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), &ctl_unit
);
933 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_TARGET_ADDRESS
, to
->sa_len
, to
);
938 if (to
->sa_family
== AF_INET
) {
939 port
= ntohs((satosin(to
))->sin_port
);
943 port
= ntohs((satosin6(to
))->sin6_port
);
947 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_TARGET_PORT
, sizeof(port
), &port
);
953 error
= flow_divert_send_packet(fd_cb
, connect_packet
, TRUE
);
963 flow_divert_send_connect_result(struct flow_divert_pcb
*fd_cb
)
966 mbuf_t packet
= NULL
;
969 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_CONNECT_RESULT
, &packet
);
971 FDLOG(LOG_ERR
, fd_cb
, "failed to create a connect result packet: %d", error
);
975 rbuff_space
= sbspace(&fd_cb
->so
->so_rcv
);
976 if (rbuff_space
< 0) {
979 rbuff_space
= htonl(rbuff_space
);
980 error
= flow_divert_packet_append_tlv(packet
,
981 FLOW_DIVERT_TLV_SPACE_AVAILABLE
,
988 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
994 if (error
&& packet
!= NULL
) {
1002 flow_divert_send_close(struct flow_divert_pcb
*fd_cb
, int how
)
1005 mbuf_t packet
= NULL
;
1008 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_CLOSE
, &packet
);
1010 FDLOG(LOG_ERR
, fd_cb
, "failed to create a close packet: %d", error
);
1014 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_ERROR_CODE
, sizeof(zero
), &zero
);
1016 FDLOG(LOG_ERR
, fd_cb
, "failed to add the error code TLV: %d", error
);
1021 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_HOW
, sizeof(how
), &how
);
1023 FDLOG(LOG_ERR
, fd_cb
, "failed to add the how flag: %d", error
);
1027 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1033 if (error
&& packet
!= NULL
) {
1041 flow_divert_tunnel_how_closed(struct flow_divert_pcb
*fd_cb
)
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
))
1047 } else if (fd_cb
->flags
& FLOW_DIVERT_TUNNEL_RD_CLOSED
) {
1049 } else if (fd_cb
->flags
& FLOW_DIVERT_TUNNEL_WR_CLOSED
) {
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.
1061 flow_divert_send_close_if_needed(struct flow_divert_pcb
*fd_cb
)
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 */
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
) {
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
;
1088 if (how
!= SHUT_WR
) {
1089 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_RD_CLOSED
;
1094 if (flow_divert_tunnel_how_closed(fd_cb
) == SHUT_RDWR
) {
1095 soisdisconnected(fd_cb
->so
);
1100 flow_divert_send_data_packet(struct flow_divert_pcb
*fd_cb
, mbuf_t data
, size_t data_len
, Boolean force
)
1106 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_DATA
, &packet
);
1108 FDLOG(LOG_ERR
, fd_cb
, "flow_divert_packet_init failed: %d", error
);
1112 last
= m_last(packet
);
1113 mbuf_setnext(last
, data
);
1114 mbuf_pkthdr_adjustlen(packet
, data_len
);
1116 error
= flow_divert_send_packet(fd_cb
, packet
, force
);
1119 mbuf_setnext(last
, NULL
);
1122 fd_cb
->bytes_sent
+= data_len
;
1123 flow_divert_add_data_statistics(fd_cb
, data_len
, TRUE
);
1130 flow_divert_send_buffered_data(struct flow_divert_pcb
*fd_cb
, Boolean force
)
1137 to_send
= fd_cb
->so
->so_snd
.sb_cc
;
1138 buffer
= fd_cb
->so
->so_snd
.sb_mb
;
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
);
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
;
1150 while (sent
< to_send
) {
1154 data_len
= to_send
- sent
;
1155 if (data_len
> FLOW_DIVERT_CHUNK_SIZE
) {
1156 data_len
= FLOW_DIVERT_CHUNK_SIZE
;
1159 error
= mbuf_copym(buffer
, sent
, data_len
, MBUF_DONTWAIT
, &data
);
1161 FDLOG(LOG_ERR
, fd_cb
, "mbuf_copym failed: %d", error
);
1165 error
= flow_divert_send_data_packet(fd_cb
, data
, data_len
, force
);
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
;
1179 fd_cb
->send_window
= 0;
1181 sbdrop(&fd_cb
->so
->so_snd
, sent
);
1182 sowwakeup(fd_cb
->so
);
1187 flow_divert_send_app_data(struct flow_divert_pcb
*fd_cb
, mbuf_t data
)
1189 size_t to_send
= mbuf_pkthdr_len(data
);
1192 mbuf_t remaining_data
= data
;
1193 mbuf_t pkt_data
= NULL
;
1195 if (to_send
> fd_cb
->send_window
) {
1196 to_send
= fd_cb
->send_window
;
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 */
1203 while (sent
< to_send
) {
1204 size_t pkt_data_len
;
1206 pkt_data
= remaining_data
;
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
);
1212 FDLOG(LOG_ERR
, fd_cb
, "mbuf_split failed: %d", error
);
1217 pkt_data_len
= to_send
- sent
;
1218 remaining_data
= NULL
;
1221 error
= flow_divert_send_data_packet(fd_cb
, pkt_data
, pkt_data_len
, FALSE
);
1228 sent
+= pkt_data_len
;
1231 fd_cb
->send_window
-= sent
;
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
);
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
);
1261 flow_divert_send_read_notification(struct flow_divert_pcb
*fd_cb
, uint32_t read_count
)
1264 mbuf_t packet
= NULL
;
1265 uint32_t net_read_count
= htonl(read_count
);
1267 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_READ_NOTIFY
, &packet
);
1269 FDLOG(LOG_ERR
, fd_cb
, "failed to create a read notification packet: %d", error
);
1273 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_READ_COUNT
, sizeof(net_read_count
), &net_read_count
);
1275 FDLOG(LOG_ERR
, fd_cb
, "failed to add the read count: %d", error
);
1279 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1285 if (error
&& packet
!= NULL
) {
1293 flow_divert_send_traffic_class_update(struct flow_divert_pcb
*fd_cb
, int traffic_class
)
1296 mbuf_t packet
= NULL
;
1298 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_PROPERTIES_UPDATE
, &packet
);
1300 FDLOG(LOG_ERR
, fd_cb
, "failed to create a properties update packet: %d", error
);
1304 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_TRAFFIC_CLASS
, sizeof(traffic_class
), &traffic_class
);
1306 FDLOG(LOG_ERR
, fd_cb
, "failed to add the traffic class: %d", error
);
1310 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1316 if (error
&& packet
!= NULL
) {
1324 flow_divert_handle_connect_result(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
1326 uint32_t connect_error
;
1327 uint32_t ctl_unit
= 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
;
1335 memset(&local_address
, 0, sizeof(local_address
));
1336 memset(&remote_address
, 0, sizeof(remote_address
));
1338 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_ERROR_CODE
, sizeof(connect_error
), &connect_error
, NULL
);
1340 FDLOG(LOG_ERR
, fd_cb
, "failed to get the connect result: %d", error
);
1344 FDLOG(LOG_INFO
, fd_cb
, "received connect result %u", connect_error
);
1346 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_SPACE_AVAILABLE
, sizeof(send_window
), &send_window
, NULL
);
1348 FDLOG(LOG_ERR
, fd_cb
, "failed to get the send window: %d", error
);
1352 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), &ctl_unit
, NULL
);
1354 FDLOG(LOG_ERR
, fd_cb
, "failed to get the control unit: %d", error
);
1358 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_LOCAL_ADDR
, sizeof(local_address
), &local_address
, NULL
);
1360 FDLOG0(LOG_NOTICE
, fd_cb
, "No local address provided");
1363 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_REMOTE_ADDR
, sizeof(remote_address
), &remote_address
, NULL
);
1365 FDLOG0(LOG_NOTICE
, fd_cb
, "No remote address provided");
1368 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_OUT_IF_INDEX
, sizeof(out_if_index
), &out_if_index
, NULL
);
1370 FDLOG0(LOG_NOTICE
, fd_cb
, "No output if index provided");
1373 connect_error
= ntohl(connect_error
);
1374 ctl_unit
= ntohl(ctl_unit
);
1376 lck_rw_lock_shared(&g_flow_divert_group_lck
);
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
);
1382 } else if (g_flow_divert_groups
== NULL
|| g_active_group_count
== 0) {
1383 FDLOG0(LOG_ERR
, fd_cb
, "No active groups, dropping connection");
1386 grp
= g_flow_divert_groups
[ctl_unit
];
1394 if (fd_cb
->so
!= NULL
) {
1395 struct inpcb
*inp
= NULL
;
1396 struct ifnet
*ifp
= NULL
;
1397 struct flow_divert_group
*old_group
;
1399 socket_lock(fd_cb
->so
, 0);
1401 if (!(fd_cb
->so
->so_state
& SS_ISCONNECTING
)) {
1405 inp
= sotoinpcb(fd_cb
->so
);
1407 if (connect_error
|| error
) {
1408 goto set_socket_state
;
1411 if (local_address
.ss_family
!= 0) {
1412 if (local_address
.ss_len
> sizeof(local_address
)) {
1413 local_address
.ss_len
= sizeof(local_address
);
1415 fd_cb
->local_address
= dup_sockaddr((struct sockaddr
*)&local_address
, 1);
1418 goto set_socket_state
;
1421 if (remote_address
.ss_family
!= 0) {
1422 if (remote_address
.ss_len
> sizeof(remote_address
)) {
1423 remote_address
.ss_len
= sizeof(remote_address
);
1425 fd_cb
->remote_address
= dup_sockaddr((struct sockaddr
*)&remote_address
, 1);
1428 goto set_socket_state
;
1431 ifnet_head_lock_shared();
1432 if (out_if_index
> 0 && out_if_index
<= if_index
) {
1433 ifp
= ifindex2ifnet
[out_if_index
];
1437 inp
->inp_last_outifp
= ifp
;
1444 goto set_socket_state
;
1447 if (fd_cb
->group
== NULL
) {
1449 goto set_socket_state
;
1452 old_group
= fd_cb
->group
;
1454 lck_rw_lock_exclusive(&old_group
->lck
);
1455 lck_rw_lock_exclusive(&grp
->lck
);
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
);
1464 lck_rw_done(&grp
->lck
);
1465 lck_rw_done(&old_group
->lck
);
1467 fd_cb
->send_window
= ntohl(send_window
);
1468 flow_divert_send_buffered_data(fd_cb
, FALSE
);
1471 if (!connect_error
&& !error
) {
1472 FDLOG0(LOG_INFO
, fd_cb
, "sending connect result");
1473 error
= flow_divert_send_connect_result(fd_cb
);
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
);
1482 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, TRUE
);
1483 fd_cb
->so
->so_error
= connect_error
;
1485 soisdisconnected(fd_cb
->so
);
1487 soisconnected(fd_cb
->so
);
1491 socket_unlock(fd_cb
->so
, 0);
1495 lck_rw_done(&g_flow_divert_group_lck
);
1499 flow_divert_handle_close(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
1501 uint32_t close_error
;
1505 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_ERROR_CODE
, sizeof(close_error
), &close_error
, NULL
);
1507 FDLOG(LOG_ERR
, fd_cb
, "failed to get the close error: %d", error
);
1511 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_HOW
, sizeof(how
), &how
, NULL
);
1513 FDLOG(LOG_ERR
, fd_cb
, "failed to get the close how flag: %d", error
);
1519 FDLOG(LOG_INFO
, fd_cb
, "close received, how = %d", how
);
1522 if (fd_cb
->so
!= NULL
) {
1523 socket_lock(fd_cb
->so
, 0);
1525 fd_cb
->so
->so_error
= ntohl(close_error
);
1527 flow_divert_update_closed_state(fd_cb
, how
, TRUE
);
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
);
1538 socket_unlock(fd_cb
->so
, 0);
1544 flow_divert_handle_data(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, size_t offset
)
1550 data_size
= (mbuf_pkthdr_len(packet
) - offset
);
1552 FDLOG(LOG_DEBUG
, fd_cb
, "received %lu bytes of data", data_size
);
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
);
1561 if (fd_cb
->so
!= NULL
) {
1562 socket_lock(fd_cb
->so
, 0);
1563 if (flow_divert_check_no_cellular(fd_cb
) ||
1564 flow_divert_check_no_expensive(fd_cb
)) {
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
);
1576 FDLOG0(LOG_ERR
, fd_cb
, "received data, but appendstream failed");
1579 socket_unlock(fd_cb
->so
, 0);
1589 flow_divert_handle_read_notification(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
1591 uint32_t read_count
;
1594 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_READ_COUNT
, sizeof(read_count
), &read_count
, NULL
);
1596 FDLOG(LOG_ERR
, fd_cb
, "failed to get the read count: %d", error
);
1600 FDLOG(LOG_DEBUG
, fd_cb
, "received a read notification for %u bytes", read_count
);
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);
1613 flow_divert_handle_group_init(struct flow_divert_group
*group
, mbuf_t packet
, int offset
)
1616 size_t key_size
= 0;
1619 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_TOKEN_KEY
, 0, NULL
, &key_size
);
1621 FDLOG(LOG_ERR
, &nil_pcb
, "failed to get the key size: %d", error
);
1625 if (key_size
== 0 || key_size
> FLOW_DIVERT_MAX_KEY_SIZE
) {
1626 FDLOG(LOG_ERR
, &nil_pcb
, "Invalid key size: %lu", key_size
);
1630 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_LOG_LEVEL
, sizeof(log_level
), &log_level
, NULL
);
1632 nil_pcb
.log_level
= log_level
;
1635 lck_rw_lock_exclusive(&group
->lck
);
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
);
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
);
1647 group
->token_key_size
= key_size
;
1649 lck_rw_done(&group
->lck
);
1653 flow_divert_handle_properties_update(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
1656 struct sockaddr_storage local_address
;
1657 int out_if_index
= 0;
1658 struct sockaddr_storage remote_address
;
1660 FDLOG0(LOG_INFO
, fd_cb
, "received a properties update");
1662 memset(&local_address
, 0, sizeof(local_address
));
1663 memset(&remote_address
, 0, sizeof(remote_address
));
1665 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_LOCAL_ADDR
, sizeof(local_address
), &local_address
, NULL
);
1667 FDLOG0(LOG_INFO
, fd_cb
, "No local address provided");
1670 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_REMOTE_ADDR
, sizeof(remote_address
), &remote_address
, NULL
);
1672 FDLOG0(LOG_INFO
, fd_cb
, "No remote address provided");
1675 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_OUT_IF_INDEX
, sizeof(out_if_index
), &out_if_index
, NULL
);
1677 FDLOG0(LOG_INFO
, fd_cb
, "No output if index provided");
1681 if (fd_cb
->so
!= NULL
) {
1682 struct inpcb
*inp
= NULL
;
1683 struct ifnet
*ifp
= NULL
;
1685 socket_lock(fd_cb
->so
, 0);
1687 inp
= sotoinpcb(fd_cb
->so
);
1689 if (local_address
.ss_family
!= 0) {
1690 if (local_address
.ss_len
> sizeof(local_address
)) {
1691 local_address
.ss_len
= sizeof(local_address
);
1693 fd_cb
->local_address
= dup_sockaddr((struct sockaddr
*)&local_address
, 1);
1696 if (remote_address
.ss_family
!= 0) {
1697 if (remote_address
.ss_len
> sizeof(remote_address
)) {
1698 remote_address
.ss_len
= sizeof(remote_address
);
1700 fd_cb
->remote_address
= dup_sockaddr((struct sockaddr
*)&remote_address
, 1);
1703 ifnet_head_lock_shared();
1704 if (out_if_index
> 0 && out_if_index
<= if_index
) {
1705 ifp
= ifindex2ifnet
[out_if_index
];
1709 inp
->inp_last_outifp
= ifp
;
1713 socket_unlock(fd_cb
->so
, 0);
1719 flow_divert_handle_app_map_create(mbuf_t packet
, int offset
)
1721 size_t bytes_mem_size
;
1722 size_t child_maps_mem_size
;
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;
1731 lck_rw_lock_exclusive(&g_flow_divert_group_lck
);
1733 /* Re-set the current trie */
1734 if (g_signing_id_trie
.memory
!= NULL
) {
1735 FREE(g_signing_id_trie
.memory
, M_TEMP
);
1737 memset(&g_signing_id_trie
, 0, sizeof(g_signing_id_trie
));
1738 g_signing_id_trie
.root
= NULL_TRIE_IDX
;
1740 memset(&new_trie
, 0, sizeof(new_trie
));
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
);
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);
1748 cursor
= flow_divert_packet_find_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 1))
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
;
1756 if (signing_id_count
== 0) {
1757 lck_rw_done(&g_flow_divert_group_lck
);
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 */
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
);
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
);
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
);
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
);
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
);
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;
1790 /* The root is an empty node */
1791 new_trie
.root
= trie_node_alloc(&new_trie
);
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);
1796 cursor
= flow_divert_packet_find_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 1))
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
) {
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
,
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
) {
1811 FDLOG(LOG_INFO
, &nil_pcb
, "Setting group unit for %s to %d", FLOW_DIVERT_DNS_SERVICE_SIGNING_ID
, DNS_SERVICE_GROUP_UNIT
);
1812 TRIE_NODE(&new_trie
, new_node_idx
).group_unit
= DNS_SERVICE_GROUP_UNIT
;
1815 insert_error
= EINVAL
;
1819 FDLOG0(LOG_ERR
, &nil_pcb
, "No place to put signing ID for insertion");
1820 insert_error
= ENOBUFS
;
1825 if (!insert_error
) {
1826 g_signing_id_trie
= new_trie
;
1828 FREE(new_trie
.memory
, M_TEMP
);
1831 lck_rw_done(&g_flow_divert_group_lck
);
1835 flow_divert_handle_app_map_update(struct flow_divert_group
*group
, mbuf_t packet
, int offset
)
1839 size_t max_size
= 0;
1840 uint8_t *signing_id
;
1843 lck_rw_lock_shared(&group
->lck
);
1844 ctl_unit
= group
->ctl_unit
;
1845 lck_rw_done(&group
->lck
);
1847 for (cursor
= flow_divert_packet_find_tlv(packet
, offset
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 0);
1849 cursor
= flow_divert_packet_find_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 1))
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
;
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
);
1864 for (cursor
= flow_divert_packet_find_tlv(packet
, offset
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 0);
1866 cursor
= flow_divert_packet_find_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 1))
1868 size_t signing_id_len
= 0;
1871 flow_divert_packet_get_tlv(packet
,
1872 cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, max_size
, signing_id
, &signing_id_len
);
1874 signing_id
[signing_id_len
] = '\0';
1876 lck_rw_lock_exclusive(&g_flow_divert_group_lck
);
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
;
1885 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to find signing ID %s", signing_id
);
1888 lck_rw_done(&g_flow_divert_group_lck
);
1891 FREE(signing_id
, M_TEMP
);
1895 flow_divert_input(mbuf_t packet
, struct flow_divert_group
*group
)
1897 struct flow_divert_packet_header hdr
;
1899 struct flow_divert_pcb
*fd_cb
;
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
));
1907 error
= mbuf_copydata(packet
, 0, sizeof(hdr
), &hdr
);
1909 FDLOG(LOG_ERR
, &nil_pcb
, "mbuf_copydata failed for the header: %d", error
);
1914 hdr
.conn_id
= ntohl(hdr
.conn_id
);
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
));
1921 case FLOW_DIVERT_PKT_APP_MAP_CREATE
:
1922 flow_divert_handle_app_map_create(packet
, sizeof(hdr
));
1924 case FLOW_DIVERT_PKT_APP_MAP_UPDATE
:
1925 flow_divert_handle_app_map_update(group
, packet
, sizeof(hdr
));
1928 FDLOG(LOG_WARNING
, &nil_pcb
, "got an unknown message type: %d", hdr
.packet_type
);
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
);
1942 switch (hdr
.packet_type
) {
1943 case FLOW_DIVERT_PKT_CONNECT_RESULT
:
1944 flow_divert_handle_connect_result(fd_cb
, packet
, sizeof(hdr
));
1946 case FLOW_DIVERT_PKT_CLOSE
:
1947 flow_divert_handle_close(fd_cb
, packet
, sizeof(hdr
));
1949 case FLOW_DIVERT_PKT_DATA
:
1950 flow_divert_handle_data(fd_cb
, packet
, sizeof(hdr
));
1952 case FLOW_DIVERT_PKT_READ_NOTIFY
:
1953 flow_divert_handle_read_notification(fd_cb
, packet
, sizeof(hdr
));
1955 case FLOW_DIVERT_PKT_PROPERTIES_UPDATE
:
1956 flow_divert_handle_properties_update(fd_cb
, packet
, sizeof(hdr
));
1959 FDLOG(LOG_WARNING
, fd_cb
, "got an unknown message type: %d", hdr
.packet_type
);
1971 flow_divert_close_all(struct flow_divert_group
*group
)
1973 struct flow_divert_pcb
*fd_cb
;
1974 SLIST_HEAD(, flow_divert_pcb
) tmp_list
;
1976 SLIST_INIT(&tmp_list
);
1978 lck_rw_lock_exclusive(&group
->lck
);
1980 MBUFQ_DRAIN(&group
->send_queue
);
1982 RB_FOREACH(fd_cb
, fd_pcb_tree
, &group
->pcb_tree
) {
1984 SLIST_INSERT_HEAD(&tmp_list
, fd_cb
, tmp_list_entry
);
1987 lck_rw_done(&group
->lck
);
1989 while (!SLIST_EMPTY(&tmp_list
)) {
1990 fd_cb
= SLIST_FIRST(&tmp_list
);
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);
2006 flow_divert_detach(struct socket
*so
)
2008 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2010 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2012 so
->so_flags
&= ~SOF_FLOW_DIVERT
;
2013 so
->so_fd_pcb
= NULL
;
2015 FDLOG(LOG_INFO
, fd_cb
, "Detaching, ref count = %d", fd_cb
->ref_count
);
2017 if (fd_cb
->group
!= NULL
) {
2018 /* Last-ditch effort to send any buffered data */
2019 flow_divert_send_buffered_data(fd_cb
, TRUE
);
2021 /* Remove from the group */
2022 flow_divert_pcb_remove(fd_cb
);
2025 socket_unlock(so
, 0);
2031 FDRELEASE(fd_cb
); /* Release the socket's reference */
2035 flow_divert_close(struct socket
*so
)
2037 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2039 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2041 FDLOG0(LOG_INFO
, fd_cb
, "Closing");
2043 soisdisconnecting(so
);
2044 sbflush(&so
->so_rcv
);
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
);
2050 /* Remove from the group */
2051 flow_divert_pcb_remove(fd_cb
);
2057 flow_divert_disconnectx(struct socket
*so
, associd_t aid
, connid_t cid __unused
)
2059 if (aid
!= ASSOCID_ANY
&& aid
!= ASSOCID_ALL
) {
2063 return (flow_divert_close(so
));
2067 flow_divert_shutdown(struct socket
*so
)
2069 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2071 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2073 FDLOG0(LOG_INFO
, fd_cb
, "Can't send more");
2077 flow_divert_update_closed_state(fd_cb
, SHUT_WR
, FALSE
);
2078 flow_divert_send_close_if_needed(fd_cb
);
2084 flow_divert_rcvd(struct socket
*so
, int flags __unused
)
2086 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2087 uint32_t latest_sb_size
;
2088 uint32_t read_count
;
2090 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2092 latest_sb_size
= fd_cb
->so
->so_rcv
.sb_cc
;
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
);
2099 read_count
= fd_cb
->sb_size
- latest_sb_size
;
2101 FDLOG(LOG_DEBUG
, fd_cb
, "app read %u bytes", read_count
);
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
;
2112 flow_divert_dup_addr(sa_family_t family
, struct sockaddr
*addr
,
2113 struct sockaddr
**dup
)
2116 struct sockaddr
*result
;
2117 struct sockaddr_storage ss
;
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
);
2128 else if (ss
.ss_family
== AF_INET6
) {
2129 ss
.ss_len
= sizeof(struct sockaddr_in6
);
2135 result
= (struct sockaddr
*)&ss
;
2139 *dup
= dup_sockaddr(result
, 1);
2149 flow_divert_getpeername(struct socket
*so
, struct sockaddr
**sa
)
2151 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2153 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2155 return flow_divert_dup_addr(so
->so_proto
->pr_domain
->dom_family
,
2156 fd_cb
->remote_address
,
2161 flow_divert_getsockaddr(struct socket
*so
, struct sockaddr
**sa
)
2163 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2165 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2167 return flow_divert_dup_addr(so
->so_proto
->pr_domain
->dom_family
,
2168 fd_cb
->local_address
,
2173 flow_divert_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
2175 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2177 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
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
);
2185 if (SOCK_DOM(so
) == PF_INET
) {
2186 return g_tcp_protosw
->pr_ctloutput(so
, sopt
);
2189 else if (SOCK_DOM(so
) == PF_INET6
) {
2190 return g_tcp6_protosw
->pr_ctloutput(so
, sopt
);
2197 flow_divert_connect_out(struct socket
*so
, struct sockaddr
*to
, proc_t p
)
2199 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2201 struct inpcb
*inp
= sotoinpcb(so
);
2202 struct sockaddr_in
*sinp
;
2203 mbuf_t connect_packet
= NULL
;
2204 char *signing_id
= NULL
;
2205 int free_signing_id
= 0;
2207 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2209 if (fd_cb
->group
== NULL
) {
2210 error
= ENETUNREACH
;
2217 } else if (inp
->inp_state
== INPCB_STATE_DEAD
) {
2219 error
= so
->so_error
;
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
;
2233 if ((fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
) && !(fd_cb
->flags
& FLOW_DIVERT_TRANSFERRED
)) {
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
);
2247 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_CONNECT
, &connect_packet
);
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;
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;
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
);
2279 FDLOG0(LOG_WARNING
, fd_cb
, "Signature is invalid");
2282 FDLOG0(LOG_WARNING
, fd_cb
, "Failed to determine the current proc");
2285 src_proc
= PROC_NULL
;
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
) {
2295 FDLOG(LOG_INFO
, fd_cb
, "%s matched", signing_id
);
2297 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_SIGNING_ID
, strlen(signing_id
), signing_id
);
2299 if (src_proc
!= PROC_NULL
) {
2300 unsigned char cdhash
[SHA1_RESULTLEN
];
2301 error
= proc_getcdhash(src_proc
, cdhash
);
2303 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_CDHASH
, sizeof(cdhash
), cdhash
);
2305 FDLOG(LOG_ERR
, fd_cb
, "failed to append the cdhash: %d", error
);
2308 FDLOG(LOG_ERR
, fd_cb
, "failed to get the cdhash: %d", error
);
2312 FDLOG(LOG_ERR
, fd_cb
, "failed to append the signing ID: %d", error
);
2315 FDLOG(LOG_WARNING
, fd_cb
, "%s did not match", signing_id
);
2318 FDLOG0(LOG_WARNING
, fd_cb
, "Failed to get the code signing identity");
2321 if (src_proc
!= PROC_NULL
) {
2322 proc_unlock(src_proc
);
2324 proc_rele(src_proc
);
2328 FDLOG0(LOG_WARNING
, fd_cb
, "The signing ID trie is empty");
2332 if (free_signing_id
) {
2333 FREE(signing_id
, M_TEMP
);
2340 FDLOG0(LOG_INFO
, fd_cb
, "Connecting");
2342 error
= flow_divert_send_connect(fd_cb
, to
, connect_packet
);
2347 fd_cb
->flags
|= FLOW_DIVERT_CONNECT_STARTED
;
2352 if (error
&& connect_packet
!= NULL
) {
2353 mbuf_free(connect_packet
);
2359 flow_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
)
2365 struct sockaddr_entry
*src_se
= NULL
, *dst_se
= NULL
;
2366 struct inpcb
*inp
= sotoinpcb(so
);
2373 VERIFY(dst_sl
!= NULL
);
2375 /* select source (if specified) and destination addresses */
2376 error
= in_selectaddrs(af
, src_sl
, &src_se
, dst_sl
, &dst_se
);
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
);
2386 error
= flow_divert_connect_out(so
, dst_se
->se_addr
, p
);
2388 if (error
== 0 && pcid
!= NULL
) {
2389 *pcid
= 1; /* there is only 1 connection for a TCP */
2396 flow_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
,
2401 return (flow_divert_connectx_out_common(so
, AF_INET
, src_sl
, dst_sl
,
2402 p
, ifscope
, aid
, pcid
, flags
, arg
, arglen
));
2407 flow_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
,
2412 return (flow_divert_connectx_out_common(so
, AF_INET6
, src_sl
, dst_sl
,
2413 p
, ifscope
, aid
, pcid
, flags
, arg
, arglen
));
2418 flow_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
)
2424 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2425 struct ifnet
*ifp
= NULL
;
2426 struct inpcb
*inp
= sotoinpcb(so
);
2428 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
));
2430 if (so
->so_fd_pcb
== NULL
|| inp
== NULL
) {
2435 if (cid
!= CONNID_ANY
&& cid
!= CONNID_ALL
&& cid
!= 1) {
2440 ifp
= inp
->inp_last_outifp
;
2441 *ifindex
= ((ifp
!= NULL
) ? ifp
->if_index
: 0);
2442 *soerror
= so
->so_error
;
2445 if (so
->so_state
& SS_ISCONNECTED
) {
2446 *flags
|= (CIF_CONNECTED
| CIF_PREFERRED
);
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
);
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
);
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
);
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
);
2501 flow_divert_control(struct socket
*so
, u_long cmd
, caddr_t data
, struct ifnet
*ifp __unused
, struct proc
*p __unused
)
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
);
2515 bcopy(&cifr
, data
, sizeof (cifr
));
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
);
2529 bcopy(&cifr
, data
, sizeof (cifr
));
2542 flow_divert_in_control(struct socket
*so
, u_long cmd
, caddr_t data
, struct ifnet
*ifp
, struct proc
*p
)
2544 int error
= flow_divert_control(so
, cmd
, data
, ifp
, p
);
2546 if (error
== EOPNOTSUPP
) {
2547 error
= in_control(so
, cmd
, data
, ifp
, p
);
2554 flow_divert_in6_control(struct socket
*so
, u_long cmd
, caddr_t data
, struct ifnet
*ifp
, struct proc
*p
)
2556 int error
= flow_divert_control(so
, cmd
, data
, ifp
, p
);
2558 if (error
== EOPNOTSUPP
) {
2559 error
= in6_control(so
, cmd
, data
, ifp
, p
);
2566 flow_divert_data_out(struct socket
*so
, int flags
, mbuf_t data
, struct sockaddr
*to
, mbuf_t control
, struct proc
*p __unused
)
2568 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2572 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2574 inp
= sotoinpcb(so
);
2575 if (inp
== NULL
|| inp
->inp_state
== INPCB_STATE_DEAD
) {
2580 if (control
&& mbuf_len(control
) > 0) {
2585 if (flags
& MSG_OOB
) {
2587 goto done
; /* We don't support OOB data */
2590 error
= flow_divert_check_no_cellular(fd_cb
) ||
2591 flow_divert_check_no_expensive(fd_cb
);
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
);
2605 FDLOG(LOG_DEBUG
, fd_cb
, "app wrote %lu bytes", mbuf_pkthdr_len(data
));
2607 fd_cb
->bytes_written_by_app
+= mbuf_pkthdr_len(data
);
2608 error
= flow_divert_send_app_data(fd_cb
, data
);
2615 if (flags
& PRUS_EOF
) {
2616 flow_divert_shutdown(so
);
2630 flow_divert_set_protosw(struct socket
*so
)
2632 so
->so_flags
|= SOF_FLOW_DIVERT
;
2633 if (SOCK_DOM(so
) == PF_INET
) {
2634 so
->so_proto
= &g_flow_divert_in_protosw
;
2638 so
->so_proto
= (struct protosw
*)&g_flow_divert_in6_protosw
;
2644 flow_divert_attach(struct socket
*so
, uint32_t flow_id
, uint32_t ctl_unit
)
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
;
2653 socket_unlock(so
, 0);
2655 FDLOG(LOG_INFO
, &nil_pcb
, "Attaching socket to flow %u", flow_id
);
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
);
2665 lck_rw_done(&g_flow_divert_group_lck
);
2667 if (fd_cb
== NULL
) {
2674 /* Dis-associate the flow divert control block from its current socket */
2677 inp
= sotoinpcb(old_so
);
2679 VERIFY(inp
!= NULL
);
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
);
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
);
2693 socket_unlock(old_so
, 0);
2695 /* Associate the new socket with the flow divert control block */
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
)) {
2705 flow_divert_set_protosw(so
);
2706 socket_unlock(so
, 0);
2709 fd_cb
->flags
|= FLOW_DIVERT_TRANSFERRED
;
2716 if (fd_cb
!= NULL
) {
2717 FDRELEASE(fd_cb
); /* Release the reference obtained via flow_divert_pcb_lookup */
2724 flow_divert_pcb_init(struct socket
*so
, uint32_t ctl_unit
)
2727 struct flow_divert_pcb
*fd_cb
;
2729 if (so
->so_flags
& SOF_FLOW_DIVERT
) {
2733 fd_cb
= flow_divert_pcb_create(so
);
2734 if (fd_cb
!= NULL
) {
2735 error
= flow_divert_pcb_insert(fd_cb
, ctl_unit
);
2737 FDLOG(LOG_ERR
, fd_cb
, "pcb insert failed: %d", error
);
2740 fd_cb
->log_level
= LOG_NOTICE
;
2741 fd_cb
->control_group_unit
= ctl_unit
;
2742 so
->so_fd_pcb
= fd_cb
;
2744 flow_divert_set_protosw(so
);
2746 FDLOG0(LOG_INFO
, fd_cb
, "Created");
2756 flow_divert_token_set(struct socket
*so
, struct sockopt
*sopt
)
2758 uint32_t ctl_unit
= 0;
2759 uint32_t key_unit
= 0;
2760 uint32_t flow_id
= 0;
2762 mbuf_t token
= NULL
;
2764 if (so
->so_flags
& SOF_FLOW_DIVERT
) {
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
;
2775 if (SOCK_TYPE(so
) != SOCK_STREAM
||
2776 SOCK_PROTO(so
) != IPPROTO_TCP
||
2777 (SOCK_DOM(so
) != PF_INET
2779 && SOCK_DOM(so
) != PF_INET6
2786 struct tcpcb
*tp
= sototcpcb(so
);
2787 if (tp
== NULL
|| tp
->t_state
!= TCPS_CLOSED
) {
2793 error
= soopt_getm(sopt
, &token
);
2798 error
= soopt_mcopyin(sopt
, token
);
2803 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_KEY_UNIT
, sizeof(key_unit
), (void *)&key_unit
, NULL
);
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
);
2813 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), (void *)&ctl_unit
, NULL
);
2815 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to get the control socket unit from the token: %d", error
);
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
);
2827 socket_unlock(so
, 0);
2828 error
= flow_divert_packet_verify_hmac(token
, (key_unit
!= 0 ? key_unit
: ctl_unit
));
2832 FDLOG(LOG_ERR
, &nil_pcb
, "HMAC verfication failed: %d", error
);
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
);
2843 error
= flow_divert_pcb_init(so
, ctl_unit
);
2845 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2846 int log_level
= LOG_NOTICE
;
2848 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_LOG_LEVEL
,
2849 sizeof(log_level
), &log_level
, NULL
);
2851 fd_cb
->log_level
= log_level
;
2855 fd_cb
->connect_token
= token
;
2859 error
= flow_divert_attach(so
, flow_id
, ctl_unit
);
2863 if (token
!= NULL
) {
2871 flow_divert_token_get(struct socket
*so
, struct sockopt
*sopt
)
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
;
2880 if (!(so
->so_flags
& SOF_FLOW_DIVERT
)) {
2885 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2887 if (fd_cb
->group
== NULL
) {
2892 error
= mbuf_gethdr(MBUF_DONTWAIT
, MBUF_TYPE_HEADER
, &token
);
2894 FDLOG(LOG_ERR
, fd_cb
, "failed to allocate the header mbuf: %d", error
);
2898 ctl_unit
= htonl(fd_cb
->group
->ctl_unit
);
2900 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), &ctl_unit
);
2905 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_FLOW_ID
, sizeof(fd_cb
->hash
), &fd_cb
->hash
);
2910 socket_unlock(so
, 0);
2911 lck_rw_lock_shared(&g_flow_divert_group_lck
);
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
)
2916 control_group
= g_flow_divert_groups
[fd_cb
->control_group_unit
];
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
);
2924 error
= flow_divert_packet_compute_hmac(token
, control_group
, hmac
);
2926 lck_rw_done(&control_group
->lck
);
2928 error
= ENOPROTOOPT
;
2931 lck_rw_done(&g_flow_divert_group_lck
);
2938 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_HMAC
, sizeof(hmac
), hmac
);
2943 error
= soopt_mcopyout(sopt
, token
);
2945 token
= NULL
; /* For some reason, soopt_mcopyout() frees the mbuf if it fails */
2950 if (token
!= NULL
) {
2958 flow_divert_kctl_connect(kern_ctl_ref kctlref __unused
, struct sockaddr_ctl
*sac
, void **unitinfo
)
2960 struct flow_divert_group
*new_group
;
2963 if (sac
->sc_unit
>= GROUP_COUNT_MAX
) {
2970 MALLOC_ZONE(new_group
, struct flow_divert_group
*, sizeof(*new_group
), M_FLOW_DIVERT_GROUP
, M_WAITOK
);
2971 if (new_group
== NULL
) {
2976 memset(new_group
, 0, sizeof(*new_group
));
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
);
2983 lck_rw_lock_exclusive(&g_flow_divert_group_lck
);
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
*),
2993 if (g_flow_divert_groups
== NULL
) {
2995 } else if (g_flow_divert_groups
[sac
->sc_unit
] != NULL
) {
2998 g_flow_divert_groups
[sac
->sc_unit
] = new_group
;
2999 g_active_group_count
++;
3002 lck_rw_done(&g_flow_divert_group_lck
);
3004 *unitinfo
= new_group
;
3007 if (error
!= 0 && new_group
!= NULL
) {
3008 FREE_ZONE(new_group
, sizeof(*new_group
), M_FLOW_DIVERT_GROUP
);
3014 flow_divert_kctl_disconnect(kern_ctl_ref kctlref __unused
, uint32_t unit
, void *unitinfo
)
3016 struct flow_divert_group
*group
= NULL
;
3020 if (unit
>= GROUP_COUNT_MAX
) {
3024 FDLOG(LOG_INFO
, &nil_pcb
, "disconnecting group %d", unit
);
3026 lck_rw_lock_exclusive(&g_flow_divert_group_lck
);
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
);
3033 group
= g_flow_divert_groups
[unit
];
3035 if (group
!= (struct flow_divert_group
*)unitinfo
) {
3036 panic("group with unit %d (%p) != unit info (%p)", unit
, group
, unitinfo
);
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;
3047 FREE_ZONE(group
, sizeof(*group
), M_FLOW_DIVERT_GROUP
);
3048 g_flow_divert_groups
[unit
] = NULL
;
3049 g_active_group_count
--;
3054 if (g_active_group_count
== 0) {
3055 FREE(g_flow_divert_groups
, M_TEMP
);
3056 g_flow_divert_groups
= NULL
;
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;
3066 lck_rw_done(&g_flow_divert_group_lck
);
3072 flow_divert_kctl_send(kern_ctl_ref kctlref __unused
, uint32_t unit __unused
, void *unitinfo
, mbuf_t m
, int flags __unused
)
3074 return flow_divert_input(m
, (struct flow_divert_group
*)unitinfo
);
3078 flow_divert_kctl_rcvd(kern_ctl_ref kctlref __unused
, uint32_t unit __unused
, void *unitinfo
, int flags __unused
)
3080 struct flow_divert_group
*group
= (struct flow_divert_group
*)unitinfo
;
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
;
3086 lck_rw_lock_shared(&g_flow_divert_group_lck
);
3087 lck_rw_lock_exclusive(&group
->lck
);
3089 while (!MBUFQ_EMPTY(&group
->send_queue
)) {
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
);
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
);
3101 MBUFQ_DEQUEUE(&group
->send_queue
, next_packet
);
3104 SLIST_INIT(&tmp_list
);
3106 RB_FOREACH(fd_cb
, fd_pcb_tree
, &group
->pcb_tree
) {
3108 SLIST_INSERT_HEAD(&tmp_list
, fd_cb
, tmp_list_entry
);
3111 lck_rw_done(&group
->lck
);
3113 SLIST_FOREACH(fd_cb
, &tmp_list
, tmp_list_entry
) {
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
);
3120 socket_unlock(fd_cb
->so
, 0);
3126 lck_rw_done(&g_flow_divert_group_lck
);
3131 flow_divert_kctl_init(void)
3133 struct kern_ctl_reg ctl_reg
;
3136 memset(&ctl_reg
, 0, sizeof(ctl_reg
));
3138 strlcpy(ctl_reg
.ctl_name
, FLOW_DIVERT_CONTROL_NAME
, sizeof(ctl_reg
.ctl_name
));
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
;
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
;
3149 result
= ctl_register(&ctl_reg
, &g_flow_divert_kctl_ref
);
3152 FDLOG(LOG_ERR
, &nil_pcb
, "flow_divert_kctl_init - ctl_register failed: %d\n", result
);
3160 flow_divert_init(void)
3162 memset(&nil_pcb
, 0, sizeof(nil_pcb
));
3163 nil_pcb
.log_level
= LOG_NOTICE
;
3165 g_tcp_protosw
= pffindproto(AF_INET
, IPPROTO_TCP
, SOCK_STREAM
);
3167 VERIFY(g_tcp_protosw
!= NULL
);
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
));
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
;
3183 g_flow_divert_in_protosw
.pr_usrreqs
= &g_flow_divert_in_usrreqs
;
3184 g_flow_divert_in_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
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.
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;
3197 g_tcp6_protosw
= (struct ip6protosw
*)pffindproto(AF_INET6
, IPPROTO_TCP
, SOCK_STREAM
);
3199 VERIFY(g_tcp6_protosw
!= NULL
);
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
));
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
;
3215 g_flow_divert_in6_protosw
.pr_usrreqs
= &g_flow_divert_in6_usrreqs
;
3216 g_flow_divert_in6_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
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.
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;
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
;
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
;
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
;
3249 g_init_result
= flow_divert_kctl_init();
3250 if (g_init_result
) {
3254 lck_rw_init(&g_flow_divert_group_lck
, flow_divert_mtx_grp
, flow_divert_mtx_attr
);
3256 memset(&g_signing_id_trie
, 0, sizeof(g_signing_id_trie
));
3257 g_signing_id_trie
.root
= NULL_TRIE_IDX
;
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
;
3265 if (flow_divert_mtx_grp
!= NULL
) {
3266 lck_grp_free(flow_divert_mtx_grp
);
3267 flow_divert_mtx_grp
= NULL
;
3269 if (flow_divert_grp_attr
!= NULL
) {
3270 lck_grp_attr_free(flow_divert_grp_attr
);
3271 flow_divert_grp_attr
= NULL
;
3274 if (g_flow_divert_kctl_ref
!= NULL
) {
3275 ctl_deregister(g_flow_divert_kctl_ref
);
3276 g_flow_divert_kctl_ref
= NULL
;