2 * Copyright (c) 2012-2015 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/in6_pcb.h>
61 #include <netinet6/ip6protosw.h>
63 #include <dev/random/randomdev.h>
64 #include <libkern/crypto/sha1.h>
65 #include <libkern/crypto/crypto_internal.h>
67 #define FLOW_DIVERT_CONNECT_STARTED 0x00000001
68 #define FLOW_DIVERT_READ_CLOSED 0x00000002
69 #define FLOW_DIVERT_WRITE_CLOSED 0x00000004
70 #define FLOW_DIVERT_TUNNEL_RD_CLOSED 0x00000008
71 #define FLOW_DIVERT_TUNNEL_WR_CLOSED 0x00000010
72 #define FLOW_DIVERT_TRANSFERRED 0x00000020
74 #define FDLOG(level, pcb, format, ...) do { \
75 if (level <= (pcb)->log_level) { \
76 log((level > LOG_NOTICE ? LOG_NOTICE : level), "%s (%u): " format "\n", __FUNCTION__, (pcb)->hash, __VA_ARGS__); \
80 #define FDLOG0(level, pcb, msg) do { \
81 if (level <= (pcb)->log_level) { \
82 log((level > LOG_NOTICE ? LOG_NOTICE : level), "%s (%u): %s\n", __FUNCTION__, (pcb)->hash, msg); \
86 #define FDRETAIN(pcb) if ((pcb) != NULL) OSIncrementAtomic(&(pcb)->ref_count)
87 #define FDRELEASE(pcb) \
89 if ((pcb) != NULL && 1 == OSDecrementAtomic(&(pcb)->ref_count)) { \
90 flow_divert_pcb_destroy(pcb); \
94 #define FDLOCK(pcb) lck_mtx_lock(&(pcb)->mtx)
95 #define FDUNLOCK(pcb) lck_mtx_unlock(&(pcb)->mtx)
97 #define FD_CTL_SENDBUFF_SIZE (2 * FLOW_DIVERT_CHUNK_SIZE)
98 #define FD_CTL_RCVBUFF_SIZE (128 * 1024)
100 #define GROUP_BIT_CTL_ENQUEUE_BLOCKED 0
102 #define GROUP_COUNT_MAX 32
103 #define FLOW_DIVERT_MAX_NAME_SIZE 4096
104 #define FLOW_DIVERT_MAX_KEY_SIZE 1024
106 #define DNS_SERVICE_GROUP_UNIT (GROUP_COUNT_MAX + 1)
108 struct flow_divert_trie_node
116 struct flow_divert_trie
118 struct flow_divert_trie_node
*nodes
;
119 uint16_t *child_maps
;
123 size_t child_maps_count
;
125 size_t nodes_free_next
;
126 size_t child_maps_free_next
;
127 size_t bytes_free_next
;
131 #define CHILD_MAP_SIZE 256
132 #define NULL_TRIE_IDX 0xffff
133 #define TRIE_NODE(t, i) ((t)->nodes[(i)])
134 #define TRIE_CHILD(t, i, b) (((t)->child_maps + (CHILD_MAP_SIZE * TRIE_NODE(t, i).child_map))[(b)])
135 #define TRIE_BYTE(t, i) ((t)->bytes[(i)])
137 static struct flow_divert_pcb nil_pcb
;
139 decl_lck_rw_data(static, g_flow_divert_group_lck
);
140 static struct flow_divert_group
**g_flow_divert_groups
= NULL
;
141 static uint32_t g_active_group_count
= 0;
142 static struct flow_divert_trie g_signing_id_trie
;
144 static lck_grp_attr_t
*flow_divert_grp_attr
= NULL
;
145 static lck_attr_t
*flow_divert_mtx_attr
= NULL
;
146 static lck_grp_t
*flow_divert_mtx_grp
= NULL
;
147 static errno_t g_init_result
= 0;
149 static kern_ctl_ref g_flow_divert_kctl_ref
= NULL
;
151 static struct protosw g_flow_divert_in_protosw
;
152 static struct pr_usrreqs g_flow_divert_in_usrreqs
;
153 static struct protosw g_flow_divert_in_udp_protosw
;
154 static struct pr_usrreqs g_flow_divert_in_udp_usrreqs
;
156 static struct ip6protosw g_flow_divert_in6_protosw
;
157 static struct pr_usrreqs g_flow_divert_in6_usrreqs
;
158 static struct ip6protosw g_flow_divert_in6_udp_protosw
;
159 static struct pr_usrreqs g_flow_divert_in6_udp_usrreqs
;
162 static struct protosw
*g_tcp_protosw
= NULL
;
163 static struct ip6protosw
*g_tcp6_protosw
= NULL
;
164 static struct protosw
*g_udp_protosw
= NULL
;
165 static struct ip6protosw
*g_udp6_protosw
= NULL
;
168 flow_divert_dup_addr(sa_family_t family
, struct sockaddr
*addr
, struct sockaddr
**dup
);
171 flow_divert_inp_to_sockaddr(const struct inpcb
*inp
, struct sockaddr
**local_socket
);
174 flow_divert_is_sockaddr_valid(struct sockaddr
*addr
);
177 flow_divert_append_target_endpoint_tlv(mbuf_t connect_packet
, struct sockaddr
*toaddr
);
180 flow_divert_get_buffered_target_address(mbuf_t buffer
);
183 flow_divert_has_pcb_local_address(const struct inpcb
*inp
);
186 flow_divert_disconnect_socket(struct socket
*so
);
189 flow_divert_pcb_cmp(const struct flow_divert_pcb
*pcb_a
, const struct flow_divert_pcb
*pcb_b
)
191 return memcmp(&pcb_a
->hash
, &pcb_b
->hash
, sizeof(pcb_a
->hash
));
194 RB_PROTOTYPE(fd_pcb_tree
, flow_divert_pcb
, rb_link
, flow_divert_pcb_cmp
);
195 RB_GENERATE(fd_pcb_tree
, flow_divert_pcb
, rb_link
, flow_divert_pcb_cmp
);
198 flow_divert_packet_type2str(uint8_t packet_type
)
200 switch (packet_type
) {
201 case FLOW_DIVERT_PKT_CONNECT
:
203 case FLOW_DIVERT_PKT_CONNECT_RESULT
:
204 return "connect result";
205 case FLOW_DIVERT_PKT_DATA
:
207 case FLOW_DIVERT_PKT_CLOSE
:
209 case FLOW_DIVERT_PKT_READ_NOTIFY
:
210 return "read notification";
211 case FLOW_DIVERT_PKT_PROPERTIES_UPDATE
:
212 return "properties update";
213 case FLOW_DIVERT_PKT_APP_MAP_UPDATE
:
214 return "app map update";
215 case FLOW_DIVERT_PKT_APP_MAP_CREATE
:
216 return "app map create";
222 static struct flow_divert_pcb
*
223 flow_divert_pcb_lookup(uint32_t hash
, struct flow_divert_group
*group
)
225 struct flow_divert_pcb key_item
;
226 struct flow_divert_pcb
*fd_cb
= NULL
;
228 key_item
.hash
= hash
;
230 lck_rw_lock_shared(&group
->lck
);
231 fd_cb
= RB_FIND(fd_pcb_tree
, &group
->pcb_tree
, &key_item
);
233 lck_rw_done(&group
->lck
);
239 flow_divert_pcb_insert(struct flow_divert_pcb
*fd_cb
, uint32_t ctl_unit
)
242 struct flow_divert_pcb
*exist
= NULL
;
243 struct flow_divert_group
*group
;
244 static uint32_t g_nextkey
= 1;
245 static uint32_t g_hash_seed
= 0;
248 if (ctl_unit
== 0 || ctl_unit
>= GROUP_COUNT_MAX
) {
252 socket_unlock(fd_cb
->so
, 0);
253 lck_rw_lock_shared(&g_flow_divert_group_lck
);
255 if (g_flow_divert_groups
== NULL
|| g_active_group_count
== 0) {
256 FDLOG0(LOG_ERR
, &nil_pcb
, "No active groups, flow divert cannot be used for this socket");
261 group
= g_flow_divert_groups
[ctl_unit
];
263 FDLOG(LOG_ERR
, &nil_pcb
, "Group for control unit %u is NULL, flow divert cannot be used for this socket", ctl_unit
);
268 socket_lock(fd_cb
->so
, 0);
274 key
[0] = g_nextkey
++;
275 key
[1] = RandomULong();
277 if (g_hash_seed
== 0) {
278 g_hash_seed
= RandomULong();
281 fd_cb
->hash
= net_flowhash(key
, sizeof(key
), g_hash_seed
);
283 for (idx
= 1; idx
< GROUP_COUNT_MAX
; idx
++) {
284 struct flow_divert_group
*curr_group
= g_flow_divert_groups
[idx
];
285 if (curr_group
!= NULL
&& curr_group
!= group
) {
286 lck_rw_lock_shared(&curr_group
->lck
);
287 exist
= RB_FIND(fd_pcb_tree
, &curr_group
->pcb_tree
, fd_cb
);
288 lck_rw_done(&curr_group
->lck
);
296 lck_rw_lock_exclusive(&group
->lck
);
297 exist
= RB_INSERT(fd_pcb_tree
, &group
->pcb_tree
, fd_cb
);
298 lck_rw_done(&group
->lck
);
300 } while (exist
!= NULL
&& try_count
++ < 3);
303 fd_cb
->group
= group
;
304 FDRETAIN(fd_cb
); /* The group now has a reference */
310 socket_unlock(fd_cb
->so
, 0);
313 lck_rw_done(&g_flow_divert_group_lck
);
314 socket_lock(fd_cb
->so
, 0);
319 static struct flow_divert_pcb
*
320 flow_divert_pcb_create(socket_t so
)
322 struct flow_divert_pcb
*new_pcb
= NULL
;
324 MALLOC_ZONE(new_pcb
, struct flow_divert_pcb
*, sizeof(*new_pcb
), M_FLOW_DIVERT_PCB
, M_WAITOK
);
325 if (new_pcb
== NULL
) {
326 FDLOG0(LOG_ERR
, &nil_pcb
, "failed to allocate a pcb");
330 memset(new_pcb
, 0, sizeof(*new_pcb
));
332 lck_mtx_init(&new_pcb
->mtx
, flow_divert_mtx_grp
, flow_divert_mtx_attr
);
334 new_pcb
->log_level
= nil_pcb
.log_level
;
336 FDRETAIN(new_pcb
); /* Represents the socket's reference */
342 flow_divert_pcb_destroy(struct flow_divert_pcb
*fd_cb
)
344 FDLOG(LOG_INFO
, fd_cb
, "Destroying, app tx %u, app rx %u, tunnel tx %u, tunnel rx %u",
345 fd_cb
->bytes_written_by_app
, fd_cb
->bytes_read_by_app
, fd_cb
->bytes_sent
, fd_cb
->bytes_received
);
347 if (fd_cb
->local_address
!= NULL
) {
348 FREE(fd_cb
->local_address
, M_SONAME
);
350 if (fd_cb
->remote_address
!= NULL
) {
351 FREE(fd_cb
->remote_address
, M_SONAME
);
353 if (fd_cb
->connect_token
!= NULL
) {
354 mbuf_freem(fd_cb
->connect_token
);
356 FREE_ZONE(fd_cb
, sizeof(*fd_cb
), M_FLOW_DIVERT_PCB
);
360 flow_divert_pcb_remove(struct flow_divert_pcb
*fd_cb
)
362 if (fd_cb
->group
!= NULL
) {
363 struct flow_divert_group
*group
= fd_cb
->group
;
364 lck_rw_lock_exclusive(&group
->lck
);
365 FDLOG(LOG_INFO
, fd_cb
, "Removing from group %d, ref count = %d", group
->ctl_unit
, fd_cb
->ref_count
);
366 RB_REMOVE(fd_pcb_tree
, &group
->pcb_tree
, fd_cb
);
368 FDRELEASE(fd_cb
); /* Release the group's reference */
369 lck_rw_done(&group
->lck
);
374 flow_divert_packet_init(struct flow_divert_pcb
*fd_cb
, uint8_t packet_type
, mbuf_t
*packet
)
376 struct flow_divert_packet_header hdr
;
379 error
= mbuf_gethdr(MBUF_DONTWAIT
, MBUF_TYPE_HEADER
, packet
);
381 FDLOG(LOG_ERR
, fd_cb
, "failed to allocate the header mbuf: %d", error
);
385 hdr
.packet_type
= packet_type
;
386 hdr
.conn_id
= htonl(fd_cb
->hash
);
388 /* Lay down the header */
389 error
= mbuf_copyback(*packet
, 0, sizeof(hdr
), &hdr
, MBUF_DONTWAIT
);
391 FDLOG(LOG_ERR
, fd_cb
, "mbuf_copyback(hdr) failed: %d", error
);
401 flow_divert_packet_append_tlv(mbuf_t packet
, uint8_t type
, uint32_t length
, const void *value
)
403 uint32_t net_length
= htonl(length
);
406 error
= mbuf_copyback(packet
, mbuf_pkthdr_len(packet
), sizeof(type
), &type
, MBUF_DONTWAIT
);
408 FDLOG(LOG_ERR
, &nil_pcb
, "failed to append the type (%d)", type
);
412 error
= mbuf_copyback(packet
, mbuf_pkthdr_len(packet
), sizeof(net_length
), &net_length
, MBUF_DONTWAIT
);
414 FDLOG(LOG_ERR
, &nil_pcb
, "failed to append the length (%lu)", length
);
418 error
= mbuf_copyback(packet
, mbuf_pkthdr_len(packet
), length
, value
, MBUF_DONTWAIT
);
420 FDLOG0(LOG_ERR
, &nil_pcb
, "failed to append the value");
428 flow_divert_packet_find_tlv(mbuf_t packet
, int offset
, uint8_t type
, int *err
, int next
)
430 size_t cursor
= offset
;
432 uint32_t curr_length
;
439 error
= mbuf_copydata(packet
, cursor
, sizeof(curr_type
), &curr_type
);
446 curr_type
= FLOW_DIVERT_TLV_NIL
;
449 if (curr_type
!= type
) {
450 cursor
+= sizeof(curr_type
);
451 error
= mbuf_copydata(packet
, cursor
, sizeof(curr_length
), &curr_length
);
457 cursor
+= (sizeof(curr_length
) + ntohl(curr_length
));
459 } while (curr_type
!= type
);
465 flow_divert_packet_get_tlv(mbuf_t packet
, int offset
, uint8_t type
, size_t buff_len
, void *buff
, uint32_t *val_size
)
471 tlv_offset
= flow_divert_packet_find_tlv(packet
, offset
, type
, &error
, 0);
472 if (tlv_offset
< 0) {
476 error
= mbuf_copydata(packet
, tlv_offset
+ sizeof(type
), sizeof(length
), &length
);
481 length
= ntohl(length
);
483 if (val_size
!= NULL
) {
487 if (buff
!= NULL
&& buff_len
> 0) {
488 size_t to_copy
= (length
< buff_len
) ? length
: buff_len
;
489 error
= mbuf_copydata(packet
, tlv_offset
+ sizeof(type
) + sizeof(length
), to_copy
, buff
);
499 flow_divert_packet_compute_hmac(mbuf_t packet
, struct flow_divert_group
*group
, uint8_t *hmac
)
501 mbuf_t curr_mbuf
= packet
;
503 if (g_crypto_funcs
== NULL
|| group
->token_key
== NULL
) {
507 cchmac_di_decl(g_crypto_funcs
->ccsha1_di
, hmac_ctx
);
508 g_crypto_funcs
->cchmac_init_fn(g_crypto_funcs
->ccsha1_di
, hmac_ctx
, group
->token_key_size
, group
->token_key
);
510 while (curr_mbuf
!= NULL
) {
511 g_crypto_funcs
->cchmac_update_fn(g_crypto_funcs
->ccsha1_di
, hmac_ctx
, mbuf_len(curr_mbuf
), mbuf_data(curr_mbuf
));
512 curr_mbuf
= mbuf_next(curr_mbuf
);
515 g_crypto_funcs
->cchmac_final_fn(g_crypto_funcs
->ccsha1_di
, hmac_ctx
, hmac
);
521 flow_divert_packet_verify_hmac(mbuf_t packet
, uint32_t ctl_unit
)
524 struct flow_divert_group
*group
= NULL
;
526 uint8_t packet_hmac
[SHA_DIGEST_LENGTH
];
527 uint8_t computed_hmac
[SHA_DIGEST_LENGTH
];
530 lck_rw_lock_shared(&g_flow_divert_group_lck
);
532 if (g_flow_divert_groups
!= NULL
&& g_active_group_count
> 0) {
533 group
= g_flow_divert_groups
[ctl_unit
];
537 lck_rw_done(&g_flow_divert_group_lck
);
541 lck_rw_lock_shared(&group
->lck
);
543 if (group
->token_key
== NULL
) {
548 hmac_offset
= flow_divert_packet_find_tlv(packet
, 0, FLOW_DIVERT_TLV_HMAC
, &error
, 0);
549 if (hmac_offset
< 0) {
553 error
= flow_divert_packet_get_tlv(packet
, hmac_offset
, FLOW_DIVERT_TLV_HMAC
, sizeof(packet_hmac
), packet_hmac
, NULL
);
558 /* Chop off the HMAC TLV */
559 error
= mbuf_split(packet
, hmac_offset
, MBUF_WAITOK
, &tail
);
566 error
= flow_divert_packet_compute_hmac(packet
, group
, computed_hmac
);
571 if (memcmp(packet_hmac
, computed_hmac
, sizeof(packet_hmac
))) {
572 FDLOG0(LOG_WARNING
, &nil_pcb
, "HMAC in token does not match computed HMAC");
578 lck_rw_done(&group
->lck
);
579 lck_rw_done(&g_flow_divert_group_lck
);
584 flow_divert_add_data_statistics(struct flow_divert_pcb
*fd_cb
, int data_len
, Boolean send
)
586 struct inpcb
*inp
= NULL
;
587 struct ifnet
*ifp
= NULL
;
588 Boolean cell
= FALSE
;
589 Boolean wifi
= FALSE
;
590 Boolean wired
= FALSE
;
592 inp
= sotoinpcb(fd_cb
->so
);
597 ifp
= inp
->inp_last_outifp
;
599 cell
= IFNET_IS_CELLULAR(ifp
);
600 wifi
= (!cell
&& IFNET_IS_WIFI(ifp
));
601 wired
= (!wifi
&& IFNET_IS_WIRED(ifp
));
605 INP_ADD_STAT(inp
, cell
, wifi
, wired
, txpackets
, 1);
606 INP_ADD_STAT(inp
, cell
, wifi
, wired
, txbytes
, data_len
);
608 INP_ADD_STAT(inp
, cell
, wifi
, wired
, rxpackets
, 1);
609 INP_ADD_STAT(inp
, cell
, wifi
, wired
, rxbytes
, data_len
);
614 flow_divert_check_no_cellular(struct flow_divert_pcb
*fd_cb
)
616 struct inpcb
*inp
= NULL
;
618 inp
= sotoinpcb(fd_cb
->so
);
619 if (inp
&& INP_NO_CELLULAR(inp
) && inp
->inp_last_outifp
&&
620 IFNET_IS_CELLULAR(inp
->inp_last_outifp
))
627 flow_divert_check_no_expensive(struct flow_divert_pcb
*fd_cb
)
629 struct inpcb
*inp
= NULL
;
631 inp
= sotoinpcb(fd_cb
->so
);
632 if (inp
&& INP_NO_EXPENSIVE(inp
) && inp
->inp_last_outifp
&&
633 IFNET_IS_EXPENSIVE(inp
->inp_last_outifp
))
640 flow_divert_update_closed_state(struct flow_divert_pcb
*fd_cb
, int how
, Boolean tunnel
)
642 if (how
!= SHUT_RD
) {
643 fd_cb
->flags
|= FLOW_DIVERT_WRITE_CLOSED
;
644 if (tunnel
|| !(fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
)) {
645 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_WR_CLOSED
;
646 /* If the tunnel is not accepting writes any more, then flush the send buffer */
647 sbflush(&fd_cb
->so
->so_snd
);
650 if (how
!= SHUT_WR
) {
651 fd_cb
->flags
|= FLOW_DIVERT_READ_CLOSED
;
652 if (tunnel
|| !(fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
)) {
653 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_RD_CLOSED
;
659 trie_node_alloc(struct flow_divert_trie
*trie
)
661 if (trie
->nodes_free_next
< trie
->nodes_count
) {
662 uint16_t node_idx
= trie
->nodes_free_next
++;
663 TRIE_NODE(trie
, node_idx
).child_map
= NULL_TRIE_IDX
;
666 return NULL_TRIE_IDX
;
671 trie_child_map_alloc(struct flow_divert_trie
*trie
)
673 if (trie
->child_maps_free_next
< trie
->child_maps_count
) {
674 return trie
->child_maps_free_next
++;
676 return NULL_TRIE_IDX
;
681 trie_bytes_move(struct flow_divert_trie
*trie
, uint16_t bytes_idx
, size_t bytes_size
)
683 uint16_t start
= trie
->bytes_free_next
;
684 if (start
+ bytes_size
<= trie
->bytes_count
) {
685 if (start
!= bytes_idx
) {
686 memmove(&TRIE_BYTE(trie
, start
), &TRIE_BYTE(trie
, bytes_idx
), bytes_size
);
688 trie
->bytes_free_next
+= bytes_size
;
691 return NULL_TRIE_IDX
;
696 flow_divert_trie_insert(struct flow_divert_trie
*trie
, uint16_t string_start
, size_t string_len
)
698 uint16_t current
= trie
->root
;
699 uint16_t child
= trie
->root
;
700 uint16_t string_end
= string_start
+ string_len
;
701 uint16_t string_idx
= string_start
;
702 uint16_t string_remainder
= string_len
;
704 while (child
!= NULL_TRIE_IDX
) {
705 uint16_t parent
= current
;
707 uint16_t current_end
;
710 child
= NULL_TRIE_IDX
;
712 current_end
= TRIE_NODE(trie
, current
).start
+ TRIE_NODE(trie
, current
).length
;
714 for (node_idx
= TRIE_NODE(trie
, current
).start
;
715 node_idx
< current_end
&&
716 string_idx
< string_end
&&
717 TRIE_BYTE(trie
, node_idx
) == TRIE_BYTE(trie
, string_idx
);
718 node_idx
++, string_idx
++);
720 string_remainder
= string_end
- string_idx
;
722 if (node_idx
< (TRIE_NODE(trie
, current
).start
+ TRIE_NODE(trie
, current
).length
)) {
724 * We did not reach the end of the current node's string.
725 * We need to split the current node into two:
726 * 1. A new node that contains the prefix of the node that matches
727 * the prefix of the string being inserted.
728 * 2. The current node modified to point to the remainder
729 * of the current node's string.
731 uint16_t prefix
= trie_node_alloc(trie
);
732 if (prefix
== NULL_TRIE_IDX
) {
733 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of trie nodes while splitting an existing node");
734 return NULL_TRIE_IDX
;
738 * Prefix points to the portion of the current nodes's string that has matched
739 * the input string thus far.
741 TRIE_NODE(trie
, prefix
).start
= TRIE_NODE(trie
, current
).start
;
742 TRIE_NODE(trie
, prefix
).length
= (node_idx
- TRIE_NODE(trie
, current
).start
);
745 * Prefix has the current node as the child corresponding to the first byte
748 TRIE_NODE(trie
, prefix
).child_map
= trie_child_map_alloc(trie
);
749 if (TRIE_NODE(trie
, prefix
).child_map
== NULL_TRIE_IDX
) {
750 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of child maps while splitting an existing node");
751 return NULL_TRIE_IDX
;
753 TRIE_CHILD(trie
, prefix
, TRIE_BYTE(trie
, node_idx
)) = current
;
755 /* Parent has the prefix as the child correspoding to the first byte in the prefix */
756 TRIE_CHILD(trie
, parent
, TRIE_BYTE(trie
, TRIE_NODE(trie
, prefix
).start
)) = prefix
;
758 /* Current node is adjusted to point to the remainder */
759 TRIE_NODE(trie
, current
).start
= node_idx
;
760 TRIE_NODE(trie
, current
).length
-= TRIE_NODE(trie
, prefix
).length
;
762 /* We want to insert the new leaf (if any) as a child of the prefix */
766 if (string_remainder
> 0) {
768 * We still have bytes in the string that have not been matched yet.
769 * If the current node has children, iterate to the child corresponding
770 * to the next byte in the string.
772 if (TRIE_NODE(trie
, current
).child_map
!= NULL_TRIE_IDX
) {
773 child
= TRIE_CHILD(trie
, current
, TRIE_BYTE(trie
, string_idx
));
776 } /* while (child != NULL_TRIE_IDX) */
778 if (string_remainder
> 0) {
779 /* Add a new leaf containing the remainder of the string */
780 uint16_t leaf
= trie_node_alloc(trie
);
781 if (leaf
== NULL_TRIE_IDX
) {
782 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of trie nodes while inserting a new leaf");
783 return NULL_TRIE_IDX
;
786 TRIE_NODE(trie
, leaf
).start
= trie_bytes_move(trie
, string_idx
, string_remainder
);
787 if (TRIE_NODE(trie
, leaf
).start
== NULL_TRIE_IDX
) {
788 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of bytes while inserting a new leaf");
789 return NULL_TRIE_IDX
;
791 TRIE_NODE(trie
, leaf
).length
= string_remainder
;
793 /* Set the new leaf as the child of the current node */
794 if (TRIE_NODE(trie
, current
).child_map
== NULL_TRIE_IDX
) {
795 TRIE_NODE(trie
, current
).child_map
= trie_child_map_alloc(trie
);
796 if (TRIE_NODE(trie
, current
).child_map
== NULL_TRIE_IDX
) {
797 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of child maps while inserting a new leaf");
798 return NULL_TRIE_IDX
;
801 TRIE_CHILD(trie
, current
, TRIE_BYTE(trie
, TRIE_NODE(trie
, leaf
).start
)) = leaf
;
803 } /* else duplicate or this string is a prefix of one of the existing strings */
808 #define APPLE_WEBCLIP_ID_PREFIX "com.apple.webapp"
810 flow_divert_trie_search(struct flow_divert_trie
*trie
, uint8_t *string_bytes
)
812 uint16_t current
= trie
->root
;
813 uint16_t string_idx
= 0;
815 while (current
!= NULL_TRIE_IDX
) {
816 uint16_t next
= NULL_TRIE_IDX
;
817 uint16_t node_end
= TRIE_NODE(trie
, current
).start
+ TRIE_NODE(trie
, current
).length
;
820 for (node_idx
= TRIE_NODE(trie
, current
).start
;
821 node_idx
< node_end
&& string_bytes
[string_idx
] != '\0' && string_bytes
[string_idx
] == TRIE_BYTE(trie
, node_idx
);
822 node_idx
++, string_idx
++);
824 if (node_idx
== node_end
) {
825 if (string_bytes
[string_idx
] == '\0') {
826 return current
; /* Got an exact match */
827 } else if (string_idx
== strlen(APPLE_WEBCLIP_ID_PREFIX
) &&
828 0 == strncmp((const char *)string_bytes
, APPLE_WEBCLIP_ID_PREFIX
, string_idx
)) {
829 string_bytes
[string_idx
] = '\0';
830 return current
; /* Got an apple webclip id prefix match */
831 } else if (TRIE_NODE(trie
, current
).child_map
!= NULL_TRIE_IDX
) {
832 next
= TRIE_CHILD(trie
, current
, string_bytes
[string_idx
]);
838 return NULL_TRIE_IDX
;
842 flow_divert_get_src_proc(struct socket
*so
, proc_t
*proc
, boolean_t match_delegate
)
846 if (!match_delegate
&&
847 (so
->so_flags
& SOF_DELEGATED
) &&
848 (*proc
== PROC_NULL
|| (*proc
)->p_pid
!= so
->e_pid
))
850 *proc
= proc_find(so
->e_pid
);
852 } else if (*proc
== PROC_NULL
) {
853 *proc
= current_proc();
856 if (*proc
!= PROC_NULL
) {
857 if ((*proc
)->p_pid
== 0) {
870 flow_divert_send_packet(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, Boolean enqueue
)
874 if (fd_cb
->group
== NULL
) {
875 fd_cb
->so
->so_error
= ECONNABORTED
;
876 flow_divert_disconnect_socket(fd_cb
->so
);
880 lck_rw_lock_shared(&fd_cb
->group
->lck
);
882 if (MBUFQ_EMPTY(&fd_cb
->group
->send_queue
)) {
883 error
= ctl_enqueuembuf(g_flow_divert_kctl_ref
, fd_cb
->group
->ctl_unit
, packet
, CTL_DATA_EOR
);
888 if (error
== ENOBUFS
) {
890 if (!lck_rw_lock_shared_to_exclusive(&fd_cb
->group
->lck
)) {
891 lck_rw_lock_exclusive(&fd_cb
->group
->lck
);
893 MBUFQ_ENQUEUE(&fd_cb
->group
->send_queue
, packet
);
896 OSTestAndSet(GROUP_BIT_CTL_ENQUEUE_BLOCKED
, &fd_cb
->group
->atomic_bits
);
899 lck_rw_done(&fd_cb
->group
->lck
);
905 flow_divert_send_connect(struct flow_divert_pcb
*fd_cb
, struct sockaddr
*to
, mbuf_t connect_packet
)
910 error
= flow_divert_packet_append_tlv(connect_packet
,
911 FLOW_DIVERT_TLV_TRAFFIC_CLASS
,
912 sizeof(fd_cb
->so
->so_traffic_class
),
913 &fd_cb
->so
->so_traffic_class
);
918 if (SOCK_TYPE(fd_cb
->so
) == SOCK_STREAM
) {
919 flow_type
= FLOW_DIVERT_FLOW_TYPE_TCP
;
920 } else if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
921 flow_type
= FLOW_DIVERT_FLOW_TYPE_UDP
;
926 error
= flow_divert_packet_append_tlv(connect_packet
,
927 FLOW_DIVERT_TLV_FLOW_TYPE
,
935 if (fd_cb
->so
->so_flags
& SOF_DELEGATED
) {
936 error
= flow_divert_packet_append_tlv(connect_packet
,
938 sizeof(fd_cb
->so
->e_pid
),
944 error
= flow_divert_packet_append_tlv(connect_packet
,
945 FLOW_DIVERT_TLV_UUID
,
946 sizeof(fd_cb
->so
->e_uuid
),
952 error
= flow_divert_packet_append_tlv(connect_packet
,
954 sizeof(fd_cb
->so
->e_pid
),
955 &fd_cb
->so
->last_pid
);
960 error
= flow_divert_packet_append_tlv(connect_packet
,
961 FLOW_DIVERT_TLV_UUID
,
962 sizeof(fd_cb
->so
->e_uuid
),
963 &fd_cb
->so
->last_uuid
);
969 if (fd_cb
->connect_token
!= NULL
) {
970 unsigned int token_len
= m_length(fd_cb
->connect_token
);
971 mbuf_concatenate(connect_packet
, fd_cb
->connect_token
);
972 mbuf_pkthdr_adjustlen(connect_packet
, token_len
);
973 fd_cb
->connect_token
= NULL
;
975 uint32_t ctl_unit
= htonl(fd_cb
->control_group_unit
);
977 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), &ctl_unit
);
982 error
= flow_divert_append_target_endpoint_tlv(connect_packet
, to
);
988 if (fd_cb
->local_address
!= NULL
) {
989 /* socket is bound. */
990 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_LOCAL_ADDR
,
991 sizeof(struct sockaddr_storage
), fd_cb
->local_address
);
997 error
= flow_divert_send_packet(fd_cb
, connect_packet
, TRUE
);
1007 flow_divert_send_connect_result(struct flow_divert_pcb
*fd_cb
)
1010 mbuf_t packet
= NULL
;
1011 int rbuff_space
= 0;
1013 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_CONNECT_RESULT
, &packet
);
1015 FDLOG(LOG_ERR
, fd_cb
, "failed to create a connect result packet: %d", error
);
1019 rbuff_space
= fd_cb
->so
->so_rcv
.sb_hiwat
;
1020 if (rbuff_space
< 0) {
1023 rbuff_space
= htonl(rbuff_space
);
1024 error
= flow_divert_packet_append_tlv(packet
,
1025 FLOW_DIVERT_TLV_SPACE_AVAILABLE
,
1026 sizeof(rbuff_space
),
1032 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1038 if (error
&& packet
!= NULL
) {
1046 flow_divert_send_close(struct flow_divert_pcb
*fd_cb
, int how
)
1049 mbuf_t packet
= NULL
;
1052 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_CLOSE
, &packet
);
1054 FDLOG(LOG_ERR
, fd_cb
, "failed to create a close packet: %d", error
);
1058 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_ERROR_CODE
, sizeof(zero
), &zero
);
1060 FDLOG(LOG_ERR
, fd_cb
, "failed to add the error code TLV: %d", error
);
1065 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_HOW
, sizeof(how
), &how
);
1067 FDLOG(LOG_ERR
, fd_cb
, "failed to add the how flag: %d", error
);
1071 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1077 if (error
&& packet
!= NULL
) {
1085 flow_divert_tunnel_how_closed(struct flow_divert_pcb
*fd_cb
)
1087 if ((fd_cb
->flags
& (FLOW_DIVERT_TUNNEL_RD_CLOSED
|FLOW_DIVERT_TUNNEL_WR_CLOSED
)) ==
1088 (FLOW_DIVERT_TUNNEL_RD_CLOSED
|FLOW_DIVERT_TUNNEL_WR_CLOSED
))
1091 } else if (fd_cb
->flags
& FLOW_DIVERT_TUNNEL_RD_CLOSED
) {
1093 } else if (fd_cb
->flags
& FLOW_DIVERT_TUNNEL_WR_CLOSED
) {
1101 * Determine what close messages if any need to be sent to the tunnel. Returns TRUE if the tunnel is closed for both reads and
1102 * writes. Returns FALSE otherwise.
1105 flow_divert_send_close_if_needed(struct flow_divert_pcb
*fd_cb
)
1109 /* Do not send any close messages if there is still data in the send buffer */
1110 if (fd_cb
->so
->so_snd
.sb_cc
== 0) {
1111 if ((fd_cb
->flags
& (FLOW_DIVERT_READ_CLOSED
|FLOW_DIVERT_TUNNEL_RD_CLOSED
)) == FLOW_DIVERT_READ_CLOSED
) {
1112 /* Socket closed reads, but tunnel did not. Tell tunnel to close reads */
1115 if ((fd_cb
->flags
& (FLOW_DIVERT_WRITE_CLOSED
|FLOW_DIVERT_TUNNEL_WR_CLOSED
)) == FLOW_DIVERT_WRITE_CLOSED
) {
1116 /* Socket closed writes, but tunnel did not. Tell tunnel to close writes */
1117 if (how
== SHUT_RD
) {
1126 FDLOG(LOG_INFO
, fd_cb
, "sending close, how = %d", how
);
1127 if (flow_divert_send_close(fd_cb
, how
) != ENOBUFS
) {
1128 /* Successfully sent the close packet. Record the ways in which the tunnel has been closed */
1129 if (how
!= SHUT_RD
) {
1130 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_WR_CLOSED
;
1132 if (how
!= SHUT_WR
) {
1133 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_RD_CLOSED
;
1138 if (flow_divert_tunnel_how_closed(fd_cb
) == SHUT_RDWR
) {
1139 flow_divert_disconnect_socket(fd_cb
->so
);
1144 flow_divert_send_data_packet(struct flow_divert_pcb
*fd_cb
, mbuf_t data
, size_t data_len
, struct sockaddr
*toaddr
, Boolean force
)
1150 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_DATA
, &packet
);
1152 FDLOG(LOG_ERR
, fd_cb
, "flow_divert_packet_init failed: %d", error
);
1156 if (toaddr
!= NULL
) {
1157 error
= flow_divert_append_target_endpoint_tlv(packet
, toaddr
);
1159 FDLOG(LOG_ERR
, fd_cb
, "flow_divert_append_target_endpoint_tlv() failed: %d", error
);
1164 last
= m_last(packet
);
1165 mbuf_setnext(last
, data
);
1166 mbuf_pkthdr_adjustlen(packet
, data_len
);
1167 error
= flow_divert_send_packet(fd_cb
, packet
, force
);
1170 mbuf_setnext(last
, NULL
);
1173 fd_cb
->bytes_sent
+= data_len
;
1174 flow_divert_add_data_statistics(fd_cb
, data_len
, TRUE
);
1181 flow_divert_send_buffered_data(struct flow_divert_pcb
*fd_cb
, Boolean force
)
1188 to_send
= fd_cb
->so
->so_snd
.sb_cc
;
1189 buffer
= fd_cb
->so
->so_snd
.sb_mb
;
1191 if (buffer
== NULL
&& to_send
> 0) {
1192 FDLOG(LOG_ERR
, fd_cb
, "Send buffer is NULL, but size is supposed to be %lu", to_send
);
1196 /* Ignore the send window if force is enabled */
1197 if (!force
&& (to_send
> fd_cb
->send_window
)) {
1198 to_send
= fd_cb
->send_window
;
1201 if (SOCK_TYPE(fd_cb
->so
) == SOCK_STREAM
) {
1202 while (sent
< to_send
) {
1206 data_len
= to_send
- sent
;
1207 if (data_len
> FLOW_DIVERT_CHUNK_SIZE
) {
1208 data_len
= FLOW_DIVERT_CHUNK_SIZE
;
1211 error
= mbuf_copym(buffer
, sent
, data_len
, MBUF_DONTWAIT
, &data
);
1213 FDLOG(LOG_ERR
, fd_cb
, "mbuf_copym failed: %d", error
);
1217 error
= flow_divert_send_data_packet(fd_cb
, data
, data_len
, NULL
, force
);
1225 sbdrop(&fd_cb
->so
->so_snd
, sent
);
1226 sowwakeup(fd_cb
->so
);
1227 } else if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
1233 struct sockaddr
*toaddr
= flow_divert_get_buffered_target_address(buffer
);
1236 if (toaddr
!= NULL
) {
1237 /* look for data in the chain */
1240 if (m
!= NULL
&& m
->m_type
== MT_DATA
) {
1246 FDLOG0(LOG_ERR
, fd_cb
, "failed to find type MT_DATA in the mbuf chain.");
1250 data_len
= mbuf_pkthdr_len(m
);
1251 FDLOG(LOG_DEBUG
, fd_cb
, "mbuf_copym() data_len = %u", data_len
);
1252 error
= mbuf_copym(m
, 0, data_len
, MBUF_DONTWAIT
, &data
);
1254 FDLOG(LOG_ERR
, fd_cb
, "mbuf_copym failed: %d", error
);
1257 error
= flow_divert_send_data_packet(fd_cb
, data
, data_len
, toaddr
, force
);
1264 buffer
= buffer
->m_nextpkt
;
1265 (void) sbdroprecord(&(fd_cb
->so
->so_snd
));
1270 FDLOG(LOG_DEBUG
, fd_cb
, "sent %lu bytes of buffered data", sent
);
1271 if (fd_cb
->send_window
>= sent
) {
1272 fd_cb
->send_window
-= sent
;
1274 fd_cb
->send_window
= 0;
1280 flow_divert_send_app_data(struct flow_divert_pcb
*fd_cb
, mbuf_t data
, struct sockaddr
*toaddr
)
1282 size_t to_send
= mbuf_pkthdr_len(data
);
1285 if (to_send
> fd_cb
->send_window
) {
1286 to_send
= fd_cb
->send_window
;
1289 if (fd_cb
->so
->so_snd
.sb_cc
> 0) {
1290 to_send
= 0; /* If the send buffer is non-empty, then we can't send anything */
1293 if (SOCK_TYPE(fd_cb
->so
) == SOCK_STREAM
) {
1295 mbuf_t remaining_data
= data
;
1296 mbuf_t pkt_data
= NULL
;
1297 while (sent
< to_send
) {
1298 size_t pkt_data_len
;
1300 pkt_data
= remaining_data
;
1302 if ((to_send
- sent
) > FLOW_DIVERT_CHUNK_SIZE
) {
1303 pkt_data_len
= FLOW_DIVERT_CHUNK_SIZE
;
1305 pkt_data_len
= to_send
- sent
;
1308 if (pkt_data_len
< mbuf_pkthdr_len(pkt_data
)) {
1309 error
= mbuf_split(pkt_data
, pkt_data_len
, MBUF_DONTWAIT
, &remaining_data
);
1311 FDLOG(LOG_ERR
, fd_cb
, "mbuf_split failed: %d", error
);
1316 remaining_data
= NULL
;
1319 error
= flow_divert_send_data_packet(fd_cb
, pkt_data
, pkt_data_len
, NULL
, FALSE
);
1326 sent
+= pkt_data_len
;
1329 fd_cb
->send_window
-= sent
;
1333 if (pkt_data
!= NULL
) {
1334 if (sbspace(&fd_cb
->so
->so_snd
) > 0) {
1335 if (!sbappendstream(&fd_cb
->so
->so_snd
, pkt_data
)) {
1336 FDLOG(LOG_ERR
, fd_cb
, "sbappendstream failed with pkt_data, send buffer size = %u, send_window = %u\n",
1337 fd_cb
->so
->so_snd
.sb_cc
, fd_cb
->send_window
);
1344 if (remaining_data
!= NULL
) {
1345 if (sbspace(&fd_cb
->so
->so_snd
) > 0) {
1346 if (!sbappendstream(&fd_cb
->so
->so_snd
, remaining_data
)) {
1347 FDLOG(LOG_ERR
, fd_cb
, "sbappendstream failed with remaining_data, send buffer size = %u, send_window = %u\n",
1348 fd_cb
->so
->so_snd
.sb_cc
, fd_cb
->send_window
);
1354 } else if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
1356 error
= flow_divert_send_data_packet(fd_cb
, data
, to_send
, toaddr
, FALSE
);
1358 FDLOG(LOG_ERR
, fd_cb
, "flow_divert_send_data_packet failed. send data size = %u", to_send
);
1360 fd_cb
->send_window
-= to_send
;
1364 if (sbspace(&fd_cb
->so
->so_snd
) >= (int)mbuf_pkthdr_len(data
)) {
1365 if (toaddr
!= NULL
) {
1366 if (!sbappendaddr(&fd_cb
->so
->so_snd
, toaddr
, data
, NULL
, &error
)) {
1367 FDLOG(LOG_ERR
, fd_cb
,
1368 "sbappendaddr failed. send buffer size = %u, send_window = %u, error = %d\n",
1369 fd_cb
->so
->so_snd
.sb_cc
, fd_cb
->send_window
, error
);
1372 if (!sbappendrecord(&fd_cb
->so
->so_snd
, data
)) {
1373 FDLOG(LOG_ERR
, fd_cb
,
1374 "sbappendrecord failed. send buffer size = %u, send_window = %u, error = %d\n",
1375 fd_cb
->so
->so_snd
.sb_cc
, fd_cb
->send_window
, error
);
1388 flow_divert_send_read_notification(struct flow_divert_pcb
*fd_cb
, uint32_t read_count
)
1391 mbuf_t packet
= NULL
;
1392 uint32_t net_read_count
= htonl(read_count
);
1394 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_READ_NOTIFY
, &packet
);
1396 FDLOG(LOG_ERR
, fd_cb
, "failed to create a read notification packet: %d", error
);
1400 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_READ_COUNT
, sizeof(net_read_count
), &net_read_count
);
1402 FDLOG(LOG_ERR
, fd_cb
, "failed to add the read count: %d", error
);
1406 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1412 if (error
&& packet
!= NULL
) {
1420 flow_divert_send_traffic_class_update(struct flow_divert_pcb
*fd_cb
, int traffic_class
)
1423 mbuf_t packet
= NULL
;
1425 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_PROPERTIES_UPDATE
, &packet
);
1427 FDLOG(LOG_ERR
, fd_cb
, "failed to create a properties update packet: %d", error
);
1431 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_TRAFFIC_CLASS
, sizeof(traffic_class
), &traffic_class
);
1433 FDLOG(LOG_ERR
, fd_cb
, "failed to add the traffic class: %d", error
);
1437 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1443 if (error
&& packet
!= NULL
) {
1451 flow_divert_handle_connect_result(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
1453 uint32_t connect_error
;
1454 uint32_t ctl_unit
= 0;
1456 struct flow_divert_group
*grp
= NULL
;
1457 struct sockaddr_storage local_address
;
1458 int out_if_index
= 0;
1459 struct sockaddr_storage remote_address
;
1460 uint32_t send_window
;
1462 memset(&local_address
, 0, sizeof(local_address
));
1463 memset(&remote_address
, 0, sizeof(remote_address
));
1465 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_ERROR_CODE
, sizeof(connect_error
), &connect_error
, NULL
);
1467 FDLOG(LOG_ERR
, fd_cb
, "failed to get the connect result: %d", error
);
1471 FDLOG(LOG_INFO
, fd_cb
, "received connect result %u", connect_error
);
1473 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_SPACE_AVAILABLE
, sizeof(send_window
), &send_window
, NULL
);
1475 FDLOG(LOG_ERR
, fd_cb
, "failed to get the send window: %d", error
);
1479 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), &ctl_unit
, NULL
);
1481 FDLOG(LOG_ERR
, fd_cb
, "failed to get the control unit: %d", error
);
1485 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_LOCAL_ADDR
, sizeof(local_address
), &local_address
, NULL
);
1487 FDLOG0(LOG_NOTICE
, fd_cb
, "No local address provided");
1490 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_REMOTE_ADDR
, sizeof(remote_address
), &remote_address
, NULL
);
1492 FDLOG0(LOG_NOTICE
, fd_cb
, "No remote address provided");
1495 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_OUT_IF_INDEX
, sizeof(out_if_index
), &out_if_index
, NULL
);
1497 FDLOG0(LOG_NOTICE
, fd_cb
, "No output if index provided");
1500 connect_error
= ntohl(connect_error
);
1501 ctl_unit
= ntohl(ctl_unit
);
1503 lck_rw_lock_shared(&g_flow_divert_group_lck
);
1505 if (connect_error
== 0) {
1506 if (ctl_unit
== 0 || ctl_unit
>= GROUP_COUNT_MAX
) {
1507 FDLOG(LOG_ERR
, fd_cb
, "Connect result contains an invalid control unit: %u", ctl_unit
);
1509 } else if (g_flow_divert_groups
== NULL
|| g_active_group_count
== 0) {
1510 FDLOG0(LOG_ERR
, fd_cb
, "No active groups, dropping connection");
1513 grp
= g_flow_divert_groups
[ctl_unit
];
1521 if (fd_cb
->so
!= NULL
) {
1522 struct inpcb
*inp
= NULL
;
1523 struct ifnet
*ifp
= NULL
;
1524 struct flow_divert_group
*old_group
;
1526 socket_lock(fd_cb
->so
, 0);
1528 if (!(fd_cb
->so
->so_state
& SS_ISCONNECTING
)) {
1532 inp
= sotoinpcb(fd_cb
->so
);
1534 if (connect_error
|| error
) {
1535 goto set_socket_state
;
1538 if (local_address
.ss_family
== 0 && fd_cb
->local_address
== NULL
) {
1540 goto set_socket_state
;
1542 if (local_address
.ss_family
!= 0 && fd_cb
->local_address
== NULL
) {
1543 if (local_address
.ss_len
> sizeof(local_address
)) {
1544 local_address
.ss_len
= sizeof(local_address
);
1546 fd_cb
->local_address
= dup_sockaddr((struct sockaddr
*)&local_address
, 1);
1549 if (remote_address
.ss_family
!= 0) {
1550 if (remote_address
.ss_len
> sizeof(remote_address
)) {
1551 remote_address
.ss_len
= sizeof(remote_address
);
1553 fd_cb
->remote_address
= dup_sockaddr((struct sockaddr
*)&remote_address
, 1);
1556 goto set_socket_state
;
1559 ifnet_head_lock_shared();
1560 if (out_if_index
> 0 && out_if_index
<= if_index
) {
1561 ifp
= ifindex2ifnet
[out_if_index
];
1565 inp
->inp_last_outifp
= ifp
;
1572 goto set_socket_state
;
1575 if (fd_cb
->group
== NULL
) {
1577 goto set_socket_state
;
1580 old_group
= fd_cb
->group
;
1582 lck_rw_lock_exclusive(&old_group
->lck
);
1583 lck_rw_lock_exclusive(&grp
->lck
);
1585 RB_REMOVE(fd_pcb_tree
, &old_group
->pcb_tree
, fd_cb
);
1586 if (RB_INSERT(fd_pcb_tree
, &grp
->pcb_tree
, fd_cb
) != NULL
) {
1587 panic("group with unit %u already contains a connection with hash %u", grp
->ctl_unit
, fd_cb
->hash
);
1592 lck_rw_done(&grp
->lck
);
1593 lck_rw_done(&old_group
->lck
);
1595 fd_cb
->send_window
= ntohl(send_window
);
1596 flow_divert_send_buffered_data(fd_cb
, FALSE
);
1599 if (!connect_error
&& !error
) {
1600 FDLOG0(LOG_INFO
, fd_cb
, "sending connect result");
1601 error
= flow_divert_send_connect_result(fd_cb
);
1604 if (connect_error
|| error
) {
1605 if (!connect_error
) {
1606 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, FALSE
);
1607 fd_cb
->so
->so_error
= error
;
1608 flow_divert_send_close_if_needed(fd_cb
);
1610 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, TRUE
);
1611 fd_cb
->so
->so_error
= connect_error
;
1613 flow_divert_disconnect_socket(fd_cb
->so
);
1615 soisconnected(fd_cb
->so
);
1619 socket_unlock(fd_cb
->so
, 0);
1623 lck_rw_done(&g_flow_divert_group_lck
);
1627 flow_divert_handle_close(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
1629 uint32_t close_error
;
1633 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_ERROR_CODE
, sizeof(close_error
), &close_error
, NULL
);
1635 FDLOG(LOG_ERR
, fd_cb
, "failed to get the close error: %d", error
);
1639 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_HOW
, sizeof(how
), &how
, NULL
);
1641 FDLOG(LOG_ERR
, fd_cb
, "failed to get the close how flag: %d", error
);
1647 FDLOG(LOG_INFO
, fd_cb
, "close received, how = %d", how
);
1650 if (fd_cb
->so
!= NULL
) {
1651 socket_lock(fd_cb
->so
, 0);
1653 fd_cb
->so
->so_error
= ntohl(close_error
);
1655 flow_divert_update_closed_state(fd_cb
, how
, TRUE
);
1657 how
= flow_divert_tunnel_how_closed(fd_cb
);
1658 if (how
== SHUT_RDWR
) {
1659 flow_divert_disconnect_socket(fd_cb
->so
);
1660 } else if (how
== SHUT_RD
) {
1661 socantrcvmore(fd_cb
->so
);
1662 } else if (how
== SHUT_WR
) {
1663 socantsendmore(fd_cb
->so
);
1666 socket_unlock(fd_cb
->so
, 0);
1672 flow_divert_get_control_mbuf(struct flow_divert_pcb
*fd_cb
)
1674 struct inpcb
*inp
= sotoinpcb(fd_cb
->so
);
1675 if (inp
->inp_vflag
& INP_IPV4
&& inp
->inp_flags
& INP_RECVDSTADDR
) {
1676 struct sockaddr_in
*sin
= (struct sockaddr_in
*)(void *)fd_cb
->local_address
;
1678 return sbcreatecontrol((caddr_t
) &sin
->sin_addr
, sizeof(struct in_addr
), IP_RECVDSTADDR
, IPPROTO_IP
);
1679 } else if (inp
->inp_vflag
& INP_IPV6
&& (inp
->inp_flags
& IN6P_PKTINFO
) != 0) {
1680 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)(void *)fd_cb
->local_address
;
1681 struct in6_pktinfo pi6
;
1683 bcopy(&sin6
->sin6_addr
, &pi6
.ipi6_addr
, sizeof (struct in6_addr
));
1684 pi6
.ipi6_ifindex
= 0;
1685 return sbcreatecontrol((caddr_t
)&pi6
, sizeof (struct in6_pktinfo
), IPV6_PKTINFO
, IPPROTO_IPV6
);
1691 flow_divert_handle_data(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, size_t offset
)
1694 if (fd_cb
->so
!= NULL
) {
1698 struct sockaddr_storage remote_address
;
1699 boolean_t got_remote_sa
= FALSE
;
1701 socket_lock(fd_cb
->so
, 0);
1703 if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
1704 uint32_t val_size
= 0;
1706 /* check if we got remote address with data */
1707 memset(&remote_address
, 0, sizeof(remote_address
));
1708 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_REMOTE_ADDR
, sizeof(remote_address
), &remote_address
, &val_size
);
1709 if (error
|| val_size
> sizeof(remote_address
)) {
1710 FDLOG0(LOG_INFO
, fd_cb
, "No remote address provided");
1713 /* validate the address */
1714 if (flow_divert_is_sockaddr_valid((struct sockaddr
*)&remote_address
)) {
1715 got_remote_sa
= TRUE
;
1717 offset
+= (sizeof(uint8_t) + sizeof(uint32_t) + val_size
);
1721 data_size
= (mbuf_pkthdr_len(packet
) - offset
);
1723 FDLOG(LOG_DEBUG
, fd_cb
, "received %lu bytes of data", data_size
);
1725 error
= mbuf_split(packet
, offset
, MBUF_DONTWAIT
, &data
);
1726 if (error
|| data
== NULL
) {
1727 FDLOG(LOG_ERR
, fd_cb
, "mbuf_split failed: %d", error
);
1729 if (flow_divert_check_no_cellular(fd_cb
) ||
1730 flow_divert_check_no_expensive(fd_cb
))
1732 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, TRUE
);
1733 flow_divert_send_close(fd_cb
, SHUT_RDWR
);
1734 flow_divert_disconnect_socket(fd_cb
->so
);
1735 } else if (!(fd_cb
->so
->so_state
& SS_CANTRCVMORE
)) {
1736 if (SOCK_TYPE(fd_cb
->so
) == SOCK_STREAM
) {
1737 if (sbappendstream(&fd_cb
->so
->so_rcv
, data
)) {
1738 fd_cb
->bytes_received
+= data_size
;
1739 flow_divert_add_data_statistics(fd_cb
, data_size
, FALSE
);
1740 fd_cb
->sb_size
= fd_cb
->so
->so_rcv
.sb_cc
;
1741 sorwakeup(fd_cb
->so
);
1744 FDLOG0(LOG_ERR
, fd_cb
, "received data, but appendstream failed");
1746 } else if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
1747 struct sockaddr
*append_sa
;
1750 if (got_remote_sa
== TRUE
) {
1751 error
= flow_divert_dup_addr(fd_cb
->so
->so_proto
->pr_domain
->dom_family
,
1752 (struct sockaddr
*)&remote_address
, &append_sa
);
1754 error
= flow_divert_dup_addr(fd_cb
->so
->so_proto
->pr_domain
->dom_family
,
1755 fd_cb
->remote_address
, &append_sa
);
1758 FDLOG0(LOG_ERR
, fd_cb
, "failed to dup the socket address.");
1761 mctl
= flow_divert_get_control_mbuf(fd_cb
);
1762 if (sbappendaddr(&fd_cb
->so
->so_rcv
, append_sa
, data
, mctl
, NULL
)) {
1763 fd_cb
->bytes_received
+= data_size
;
1764 flow_divert_add_data_statistics(fd_cb
, data_size
, FALSE
);
1765 fd_cb
->sb_size
= fd_cb
->so
->so_rcv
.sb_cc
;
1766 sorwakeup(fd_cb
->so
);
1769 FDLOG0(LOG_ERR
, fd_cb
, "received data, but sbappendaddr failed");
1772 FREE(append_sa
, M_TEMP
);
1777 socket_unlock(fd_cb
->so
, 0);
1787 flow_divert_handle_read_notification(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
1789 uint32_t read_count
;
1792 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_READ_COUNT
, sizeof(read_count
), &read_count
, NULL
);
1794 FDLOG(LOG_ERR
, fd_cb
, "failed to get the read count: %d", error
);
1798 FDLOG(LOG_DEBUG
, fd_cb
, "received a read notification for %u bytes", ntohl(read_count
));
1801 if (fd_cb
->so
!= NULL
) {
1802 socket_lock(fd_cb
->so
, 0);
1803 fd_cb
->send_window
+= ntohl(read_count
);
1804 flow_divert_send_buffered_data(fd_cb
, FALSE
);
1805 socket_unlock(fd_cb
->so
, 0);
1811 flow_divert_handle_group_init(struct flow_divert_group
*group
, mbuf_t packet
, int offset
)
1814 uint32_t key_size
= 0;
1817 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_TOKEN_KEY
, 0, NULL
, &key_size
);
1819 FDLOG(LOG_ERR
, &nil_pcb
, "failed to get the key size: %d", error
);
1823 if (key_size
== 0 || key_size
> FLOW_DIVERT_MAX_KEY_SIZE
) {
1824 FDLOG(LOG_ERR
, &nil_pcb
, "Invalid key size: %lu", key_size
);
1828 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_LOG_LEVEL
, sizeof(log_level
), &log_level
, NULL
);
1830 nil_pcb
.log_level
= log_level
;
1833 lck_rw_lock_exclusive(&group
->lck
);
1835 MALLOC(group
->token_key
, uint8_t *, key_size
, M_TEMP
, M_WAITOK
);
1836 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_TOKEN_KEY
, key_size
, group
->token_key
, NULL
);
1838 FDLOG(LOG_ERR
, &nil_pcb
, "failed to get the token key: %d", error
);
1839 FREE(group
->token_key
, M_TEMP
);
1840 group
->token_key
= NULL
;
1841 lck_rw_done(&group
->lck
);
1845 group
->token_key_size
= key_size
;
1847 lck_rw_done(&group
->lck
);
1851 flow_divert_handle_properties_update(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
1854 struct sockaddr_storage local_address
;
1855 int out_if_index
= 0;
1856 struct sockaddr_storage remote_address
;
1858 FDLOG0(LOG_INFO
, fd_cb
, "received a properties update");
1860 memset(&local_address
, 0, sizeof(local_address
));
1861 memset(&remote_address
, 0, sizeof(remote_address
));
1863 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_LOCAL_ADDR
, sizeof(local_address
), &local_address
, NULL
);
1865 FDLOG0(LOG_INFO
, fd_cb
, "No local address provided");
1868 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_REMOTE_ADDR
, sizeof(remote_address
), &remote_address
, NULL
);
1870 FDLOG0(LOG_INFO
, fd_cb
, "No remote address provided");
1873 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_OUT_IF_INDEX
, sizeof(out_if_index
), &out_if_index
, NULL
);
1875 FDLOG0(LOG_INFO
, fd_cb
, "No output if index provided");
1879 if (fd_cb
->so
!= NULL
) {
1880 struct inpcb
*inp
= NULL
;
1881 struct ifnet
*ifp
= NULL
;
1883 socket_lock(fd_cb
->so
, 0);
1885 inp
= sotoinpcb(fd_cb
->so
);
1887 if (local_address
.ss_family
!= 0) {
1888 if (local_address
.ss_len
> sizeof(local_address
)) {
1889 local_address
.ss_len
= sizeof(local_address
);
1891 fd_cb
->local_address
= dup_sockaddr((struct sockaddr
*)&local_address
, 1);
1894 if (remote_address
.ss_family
!= 0) {
1895 if (remote_address
.ss_len
> sizeof(remote_address
)) {
1896 remote_address
.ss_len
= sizeof(remote_address
);
1898 fd_cb
->remote_address
= dup_sockaddr((struct sockaddr
*)&remote_address
, 1);
1901 ifnet_head_lock_shared();
1902 if (out_if_index
> 0 && out_if_index
<= if_index
) {
1903 ifp
= ifindex2ifnet
[out_if_index
];
1907 inp
->inp_last_outifp
= ifp
;
1911 socket_unlock(fd_cb
->so
, 0);
1917 flow_divert_handle_app_map_create(mbuf_t packet
, int offset
)
1919 size_t bytes_mem_size
;
1920 size_t child_maps_mem_size
;
1923 struct flow_divert_trie new_trie
;
1924 int insert_error
= 0;
1925 size_t nodes_mem_size
;
1926 int prefix_count
= 0;
1927 int signing_id_count
= 0;
1929 lck_rw_lock_exclusive(&g_flow_divert_group_lck
);
1931 /* Re-set the current trie */
1932 if (g_signing_id_trie
.memory
!= NULL
) {
1933 FREE(g_signing_id_trie
.memory
, M_TEMP
);
1935 memset(&g_signing_id_trie
, 0, sizeof(g_signing_id_trie
));
1936 g_signing_id_trie
.root
= NULL_TRIE_IDX
;
1938 memset(&new_trie
, 0, sizeof(new_trie
));
1940 /* Get the number of shared prefixes in the new set of signing ID strings */
1941 flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_PREFIX_COUNT
, sizeof(prefix_count
), &prefix_count
, NULL
);
1943 /* Compute the number of signing IDs and the total amount of bytes needed to store them */
1944 for (cursor
= flow_divert_packet_find_tlv(packet
, offset
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 0);
1946 cursor
= flow_divert_packet_find_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 1))
1948 uint32_t sid_size
= 0;
1949 flow_divert_packet_get_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, 0, NULL
, &sid_size
);
1950 new_trie
.bytes_count
+= sid_size
;
1954 if (signing_id_count
== 0) {
1955 lck_rw_done(&g_flow_divert_group_lck
);
1959 new_trie
.nodes_count
= (prefix_count
+ signing_id_count
+ 1); /* + 1 for the root node */
1960 new_trie
.child_maps_count
= (prefix_count
+ 1); /* + 1 for the root node */
1962 FDLOG(LOG_INFO
, &nil_pcb
, "Nodes count = %lu, child maps count = %lu, bytes_count = %lu",
1963 new_trie
.nodes_count
, new_trie
.child_maps_count
, new_trie
.bytes_count
);
1965 nodes_mem_size
= (sizeof(*new_trie
.nodes
) * new_trie
.nodes_count
);
1966 child_maps_mem_size
= (sizeof(*new_trie
.child_maps
) * CHILD_MAP_SIZE
* new_trie
.child_maps_count
);
1967 bytes_mem_size
= (sizeof(*new_trie
.bytes
) * new_trie
.bytes_count
);
1969 MALLOC(new_trie
.memory
, void *, nodes_mem_size
+ child_maps_mem_size
+ bytes_mem_size
, M_TEMP
, M_WAITOK
);
1970 if (new_trie
.memory
== NULL
) {
1971 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to allocate %lu bytes of memory for the signing ID trie",
1972 nodes_mem_size
+ child_maps_mem_size
+ bytes_mem_size
);
1976 /* Initialize the free lists */
1977 new_trie
.nodes
= (struct flow_divert_trie_node
*)new_trie
.memory
;
1978 new_trie
.nodes_free_next
= 0;
1979 memset(new_trie
.nodes
, 0, nodes_mem_size
);
1981 new_trie
.child_maps
= (uint16_t *)(void *)((uint8_t *)new_trie
.memory
+ nodes_mem_size
);
1982 new_trie
.child_maps_free_next
= 0;
1983 memset(new_trie
.child_maps
, 0xff, child_maps_mem_size
);
1985 new_trie
.bytes
= (uint8_t *)(void *)((uint8_t *)new_trie
.memory
+ nodes_mem_size
+ child_maps_mem_size
);
1986 new_trie
.bytes_free_next
= 0;
1988 /* The root is an empty node */
1989 new_trie
.root
= trie_node_alloc(&new_trie
);
1991 /* Add each signing ID to the trie */
1992 for (cursor
= flow_divert_packet_find_tlv(packet
, offset
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 0);
1994 cursor
= flow_divert_packet_find_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 1))
1996 uint32_t sid_size
= 0;
1997 flow_divert_packet_get_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, 0, NULL
, &sid_size
);
1998 if (new_trie
.bytes_free_next
+ sid_size
<= new_trie
.bytes_count
) {
2000 uint16_t new_node_idx
;
2001 flow_divert_packet_get_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, sid_size
, &TRIE_BYTE(&new_trie
, new_trie
.bytes_free_next
), NULL
);
2002 is_dns
= (sid_size
== sizeof(FLOW_DIVERT_DNS_SERVICE_SIGNING_ID
) - 1 &&
2003 !memcmp(&TRIE_BYTE(&new_trie
, new_trie
.bytes_free_next
),
2004 FLOW_DIVERT_DNS_SERVICE_SIGNING_ID
,
2006 new_node_idx
= flow_divert_trie_insert(&new_trie
, new_trie
.bytes_free_next
, sid_size
);
2007 if (new_node_idx
!= NULL_TRIE_IDX
) {
2009 FDLOG(LOG_INFO
, &nil_pcb
, "Setting group unit for %s to %d", FLOW_DIVERT_DNS_SERVICE_SIGNING_ID
, DNS_SERVICE_GROUP_UNIT
);
2010 TRIE_NODE(&new_trie
, new_node_idx
).group_unit
= DNS_SERVICE_GROUP_UNIT
;
2013 insert_error
= EINVAL
;
2017 FDLOG0(LOG_ERR
, &nil_pcb
, "No place to put signing ID for insertion");
2018 insert_error
= ENOBUFS
;
2023 if (!insert_error
) {
2024 g_signing_id_trie
= new_trie
;
2026 FREE(new_trie
.memory
, M_TEMP
);
2029 lck_rw_done(&g_flow_divert_group_lck
);
2033 flow_divert_handle_app_map_update(struct flow_divert_group
*group
, mbuf_t packet
, int offset
)
2037 size_t max_size
= 0;
2038 uint8_t *signing_id
;
2041 lck_rw_lock_shared(&group
->lck
);
2042 ctl_unit
= group
->ctl_unit
;
2043 lck_rw_done(&group
->lck
);
2045 for (cursor
= flow_divert_packet_find_tlv(packet
, offset
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 0);
2047 cursor
= flow_divert_packet_find_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 1))
2049 uint32_t sid_size
= 0;
2050 flow_divert_packet_get_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, 0, NULL
, &sid_size
);
2051 if (sid_size
> max_size
) {
2052 max_size
= sid_size
;
2056 MALLOC(signing_id
, uint8_t *, max_size
+ 1, M_TEMP
, M_WAITOK
);
2057 if (signing_id
== NULL
) {
2058 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to allocate a string to hold the signing ID (size %lu)", max_size
);
2062 for (cursor
= flow_divert_packet_find_tlv(packet
, offset
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 0);
2064 cursor
= flow_divert_packet_find_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 1))
2066 uint32_t signing_id_len
= 0;
2069 flow_divert_packet_get_tlv(packet
,
2070 cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, max_size
, signing_id
, &signing_id_len
);
2072 signing_id
[signing_id_len
] = '\0';
2074 lck_rw_lock_exclusive(&g_flow_divert_group_lck
);
2076 node
= flow_divert_trie_search(&g_signing_id_trie
, signing_id
);
2077 if (node
!= NULL_TRIE_IDX
) {
2078 if (TRIE_NODE(&g_signing_id_trie
, node
).group_unit
!= DNS_SERVICE_GROUP_UNIT
) {
2079 FDLOG(LOG_INFO
, &nil_pcb
, "Setting %s to ctl unit %u", signing_id
, group
->ctl_unit
);
2080 TRIE_NODE(&g_signing_id_trie
, node
).group_unit
= ctl_unit
;
2083 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to find signing ID %s", signing_id
);
2086 lck_rw_done(&g_flow_divert_group_lck
);
2089 FREE(signing_id
, M_TEMP
);
2093 flow_divert_input(mbuf_t packet
, struct flow_divert_group
*group
)
2095 struct flow_divert_packet_header hdr
;
2097 struct flow_divert_pcb
*fd_cb
;
2099 if (mbuf_pkthdr_len(packet
) < sizeof(hdr
)) {
2100 FDLOG(LOG_ERR
, &nil_pcb
, "got a bad packet, length (%lu) < sizeof hdr (%lu)", mbuf_pkthdr_len(packet
), sizeof(hdr
));
2105 if (mbuf_pkthdr_len(packet
) > FD_CTL_RCVBUFF_SIZE
) {
2106 FDLOG(LOG_ERR
, &nil_pcb
, "got a bad packet, length (%lu) > %lu", mbuf_pkthdr_len(packet
), FD_CTL_RCVBUFF_SIZE
);
2111 error
= mbuf_copydata(packet
, 0, sizeof(hdr
), &hdr
);
2113 FDLOG(LOG_ERR
, &nil_pcb
, "mbuf_copydata failed for the header: %d", error
);
2118 hdr
.conn_id
= ntohl(hdr
.conn_id
);
2120 if (hdr
.conn_id
== 0) {
2121 switch (hdr
.packet_type
) {
2122 case FLOW_DIVERT_PKT_GROUP_INIT
:
2123 flow_divert_handle_group_init(group
, packet
, sizeof(hdr
));
2125 case FLOW_DIVERT_PKT_APP_MAP_CREATE
:
2126 flow_divert_handle_app_map_create(packet
, sizeof(hdr
));
2128 case FLOW_DIVERT_PKT_APP_MAP_UPDATE
:
2129 flow_divert_handle_app_map_update(group
, packet
, sizeof(hdr
));
2132 FDLOG(LOG_WARNING
, &nil_pcb
, "got an unknown message type: %d", hdr
.packet_type
);
2138 fd_cb
= flow_divert_pcb_lookup(hdr
.conn_id
, group
); /* This retains the PCB */
2139 if (fd_cb
== NULL
) {
2140 if (hdr
.packet_type
!= FLOW_DIVERT_PKT_CLOSE
&& hdr
.packet_type
!= FLOW_DIVERT_PKT_READ_NOTIFY
) {
2141 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
);
2146 switch (hdr
.packet_type
) {
2147 case FLOW_DIVERT_PKT_CONNECT_RESULT
:
2148 flow_divert_handle_connect_result(fd_cb
, packet
, sizeof(hdr
));
2150 case FLOW_DIVERT_PKT_CLOSE
:
2151 flow_divert_handle_close(fd_cb
, packet
, sizeof(hdr
));
2153 case FLOW_DIVERT_PKT_DATA
:
2154 flow_divert_handle_data(fd_cb
, packet
, sizeof(hdr
));
2156 case FLOW_DIVERT_PKT_READ_NOTIFY
:
2157 flow_divert_handle_read_notification(fd_cb
, packet
, sizeof(hdr
));
2159 case FLOW_DIVERT_PKT_PROPERTIES_UPDATE
:
2160 flow_divert_handle_properties_update(fd_cb
, packet
, sizeof(hdr
));
2163 FDLOG(LOG_WARNING
, fd_cb
, "got an unknown message type: %d", hdr
.packet_type
);
2175 flow_divert_close_all(struct flow_divert_group
*group
)
2177 struct flow_divert_pcb
*fd_cb
;
2178 SLIST_HEAD(, flow_divert_pcb
) tmp_list
;
2180 SLIST_INIT(&tmp_list
);
2182 lck_rw_lock_exclusive(&group
->lck
);
2184 MBUFQ_DRAIN(&group
->send_queue
);
2186 RB_FOREACH(fd_cb
, fd_pcb_tree
, &group
->pcb_tree
) {
2188 SLIST_INSERT_HEAD(&tmp_list
, fd_cb
, tmp_list_entry
);
2191 lck_rw_done(&group
->lck
);
2193 while (!SLIST_EMPTY(&tmp_list
)) {
2194 fd_cb
= SLIST_FIRST(&tmp_list
);
2196 SLIST_REMOVE_HEAD(&tmp_list
, tmp_list_entry
);
2197 if (fd_cb
->so
!= NULL
) {
2198 socket_lock(fd_cb
->so
, 0);
2199 flow_divert_pcb_remove(fd_cb
);
2200 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, TRUE
);
2201 fd_cb
->so
->so_error
= ECONNABORTED
;
2202 socket_unlock(fd_cb
->so
, 0);
2210 flow_divert_detach(struct socket
*so
)
2212 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2214 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2216 so
->so_flags
&= ~SOF_FLOW_DIVERT
;
2217 so
->so_fd_pcb
= NULL
;
2219 FDLOG(LOG_INFO
, fd_cb
, "Detaching, ref count = %d", fd_cb
->ref_count
);
2221 if (fd_cb
->group
!= NULL
) {
2222 /* Last-ditch effort to send any buffered data */
2223 flow_divert_send_buffered_data(fd_cb
, TRUE
);
2225 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, FALSE
);
2226 flow_divert_send_close_if_needed(fd_cb
);
2227 /* Remove from the group */
2228 flow_divert_pcb_remove(fd_cb
);
2231 socket_unlock(so
, 0);
2237 FDRELEASE(fd_cb
); /* Release the socket's reference */
2241 flow_divert_close(struct socket
*so
)
2243 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2245 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2247 FDLOG0(LOG_INFO
, fd_cb
, "Closing");
2249 if (SOCK_TYPE(so
) == SOCK_STREAM
) {
2250 soisdisconnecting(so
);
2251 sbflush(&so
->so_rcv
);
2254 flow_divert_send_buffered_data(fd_cb
, TRUE
);
2255 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, FALSE
);
2256 flow_divert_send_close_if_needed(fd_cb
);
2258 /* Remove from the group */
2259 flow_divert_pcb_remove(fd_cb
);
2265 flow_divert_disconnectx(struct socket
*so
, sae_associd_t aid
,
2266 sae_connid_t cid __unused
)
2268 if (aid
!= SAE_ASSOCID_ANY
&& aid
!= SAE_ASSOCID_ALL
) {
2272 return (flow_divert_close(so
));
2276 flow_divert_shutdown(struct socket
*so
)
2278 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2280 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2282 FDLOG0(LOG_INFO
, fd_cb
, "Can't send more");
2286 flow_divert_update_closed_state(fd_cb
, SHUT_WR
, FALSE
);
2287 flow_divert_send_close_if_needed(fd_cb
);
2293 flow_divert_rcvd(struct socket
*so
, int flags __unused
)
2295 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2296 uint32_t latest_sb_size
;
2297 uint32_t read_count
;
2299 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2301 latest_sb_size
= fd_cb
->so
->so_rcv
.sb_cc
;
2303 if (fd_cb
->sb_size
< latest_sb_size
) {
2304 panic("flow divert rcvd event handler (%u): saved rcv buffer size (%u) is less than latest rcv buffer size (%u)",
2305 fd_cb
->hash
, fd_cb
->sb_size
, latest_sb_size
);
2308 read_count
= fd_cb
->sb_size
- latest_sb_size
;
2310 FDLOG(LOG_DEBUG
, fd_cb
, "app read %u bytes", read_count
);
2312 if (read_count
> 0 && flow_divert_send_read_notification(fd_cb
, read_count
) == 0) {
2313 fd_cb
->bytes_read_by_app
+= read_count
;
2314 fd_cb
->sb_size
= latest_sb_size
;
2321 flow_divert_append_target_endpoint_tlv(mbuf_t connect_packet
, struct sockaddr
*toaddr
)
2326 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_TARGET_ADDRESS
, toaddr
->sa_len
, toaddr
);
2331 if (toaddr
->sa_family
== AF_INET
) {
2332 port
= ntohs((satosin(toaddr
))->sin_port
);
2336 port
= ntohs((satosin6(toaddr
))->sin6_port
);
2340 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_TARGET_PORT
, sizeof(port
), &port
);
2350 flow_divert_get_buffered_target_address(mbuf_t buffer
)
2352 if (buffer
!= NULL
&& buffer
->m_type
== MT_SONAME
) {
2353 struct sockaddr
*toaddr
= mtod(buffer
, struct sockaddr
*);
2354 if (toaddr
!= NULL
&& flow_divert_is_sockaddr_valid(toaddr
)) {
2362 flow_divert_is_sockaddr_valid(struct sockaddr
*addr
)
2364 switch(addr
->sa_family
)
2367 if (addr
->sa_len
!= sizeof(struct sockaddr_in
)) {
2373 if (addr
->sa_len
!= sizeof(struct sockaddr_in6
)) {
2385 flow_divert_inp_to_sockaddr(const struct inpcb
*inp
, struct sockaddr
**local_socket
)
2388 union sockaddr_in_4_6 sin46
;
2390 bzero(&sin46
, sizeof(sin46
));
2391 if (inp
->inp_vflag
& INP_IPV4
) {
2392 struct sockaddr_in
*sin
= &sin46
.sin
;
2394 sin
->sin_family
= AF_INET
;
2395 sin
->sin_len
= sizeof(*sin
);
2396 sin
->sin_port
= inp
->inp_lport
;
2397 sin
->sin_addr
= inp
->inp_laddr
;
2398 } else if (inp
->inp_vflag
& INP_IPV6
) {
2399 struct sockaddr_in6
*sin6
= &sin46
.sin6
;
2401 sin6
->sin6_len
= sizeof(*sin6
);
2402 sin6
->sin6_family
= AF_INET6
;
2403 sin6
->sin6_port
= inp
->inp_lport
;
2404 sin6
->sin6_addr
= inp
->in6p_laddr
;
2406 *local_socket
= dup_sockaddr((struct sockaddr
*)&sin46
, 1);
2407 if (*local_socket
== NULL
) {
2414 flow_divert_has_pcb_local_address(const struct inpcb
*inp
)
2416 return (inp
->inp_lport
!= 0
2417 && (inp
->inp_laddr
.s_addr
!= INADDR_ANY
|| !IN6_IS_ADDR_UNSPECIFIED(&inp
->in6p_laddr
)));
2421 flow_divert_dup_addr(sa_family_t family
, struct sockaddr
*addr
,
2422 struct sockaddr
**dup
)
2425 struct sockaddr
*result
;
2426 struct sockaddr_storage ss
;
2431 memset(&ss
, 0, sizeof(ss
));
2432 ss
.ss_family
= family
;
2433 if (ss
.ss_family
== AF_INET
) {
2434 ss
.ss_len
= sizeof(struct sockaddr_in
);
2437 else if (ss
.ss_family
== AF_INET6
) {
2438 ss
.ss_len
= sizeof(struct sockaddr_in6
);
2444 result
= (struct sockaddr
*)&ss
;
2448 *dup
= dup_sockaddr(result
, 1);
2458 flow_divert_disconnect_socket(struct socket
*so
)
2460 soisdisconnected(so
);
2461 if (SOCK_TYPE(so
) == SOCK_DGRAM
) {
2462 struct inpcb
*inp
= NULL
;
2464 inp
= sotoinpcb(so
);
2467 if (SOCK_CHECK_DOM(so
, PF_INET6
))
2477 flow_divert_getpeername(struct socket
*so
, struct sockaddr
**sa
)
2479 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2481 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2483 return flow_divert_dup_addr(so
->so_proto
->pr_domain
->dom_family
,
2484 fd_cb
->remote_address
,
2489 flow_divert_getsockaddr(struct socket
*so
, struct sockaddr
**sa
)
2491 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2493 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2495 return flow_divert_dup_addr(so
->so_proto
->pr_domain
->dom_family
,
2496 fd_cb
->local_address
,
2501 flow_divert_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
2503 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2505 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2507 if (sopt
->sopt_name
== SO_TRAFFIC_CLASS
) {
2508 if (sopt
->sopt_dir
== SOPT_SET
&& fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
) {
2509 flow_divert_send_traffic_class_update(fd_cb
, so
->so_traffic_class
);
2513 if (SOCK_DOM(so
) == PF_INET
) {
2514 return g_tcp_protosw
->pr_ctloutput(so
, sopt
);
2517 else if (SOCK_DOM(so
) == PF_INET6
) {
2518 return g_tcp6_protosw
->pr_ctloutput(so
, sopt
);
2525 flow_divert_connect_out(struct socket
*so
, struct sockaddr
*to
, proc_t p
)
2527 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2529 struct inpcb
*inp
= sotoinpcb(so
);
2530 struct sockaddr_in
*sinp
;
2531 mbuf_t connect_packet
= NULL
;
2532 char *signing_id
= NULL
;
2533 int free_signing_id
= 0;
2535 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2537 if (fd_cb
->group
== NULL
) {
2538 error
= ENETUNREACH
;
2545 } else if (inp
->inp_state
== INPCB_STATE_DEAD
) {
2547 error
= so
->so_error
;
2555 sinp
= (struct sockaddr_in
*)(void *)to
;
2556 if (sinp
->sin_family
== AF_INET
&& IN_MULTICAST(ntohl(sinp
->sin_addr
.s_addr
))) {
2557 error
= EAFNOSUPPORT
;
2561 if ((fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
) && !(fd_cb
->flags
& FLOW_DIVERT_TRANSFERRED
)) {
2566 if (fd_cb
->flags
& FLOW_DIVERT_TRANSFERRED
) {
2567 FDLOG0(LOG_INFO
, fd_cb
, "fully transferred");
2568 fd_cb
->flags
&= ~FLOW_DIVERT_TRANSFERRED
;
2569 if (fd_cb
->remote_address
!= NULL
) {
2570 soisconnected(fd_cb
->so
);
2575 if (fd_cb
->local_address
!= NULL
) {
2579 if (flow_divert_has_pcb_local_address(inp
)) {
2580 error
= flow_divert_inp_to_sockaddr(inp
, &fd_cb
->local_address
);
2582 FDLOG0(LOG_ERR
, fd_cb
, "failed to get the local socket address.");
2589 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_CONNECT
, &connect_packet
);
2596 if (fd_cb
->connect_token
!= NULL
) {
2597 uint32_t sid_size
= 0;
2598 int find_error
= flow_divert_packet_get_tlv(fd_cb
->connect_token
, 0, FLOW_DIVERT_TLV_SIGNING_ID
, 0, NULL
, &sid_size
);
2599 if (find_error
== 0 && sid_size
> 0) {
2600 MALLOC(signing_id
, char *, sid_size
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
2601 if (signing_id
!= NULL
) {
2602 flow_divert_packet_get_tlv(fd_cb
->connect_token
, 0, FLOW_DIVERT_TLV_SIGNING_ID
, sid_size
, signing_id
, NULL
);
2603 FDLOG(LOG_INFO
, fd_cb
, "Got %s from token", signing_id
);
2604 free_signing_id
= 1;
2609 socket_unlock(so
, 0);
2610 if (g_signing_id_trie
.root
!= NULL_TRIE_IDX
) {
2611 proc_t src_proc
= p
;
2612 int release_proc
= 0;
2614 if (signing_id
== NULL
) {
2615 release_proc
= flow_divert_get_src_proc(so
, &src_proc
, FALSE
);
2616 if (src_proc
!= PROC_NULL
) {
2617 proc_lock(src_proc
);
2618 if (src_proc
->p_csflags
& CS_VALID
) {
2620 cs_id
= cs_identity_get(src_proc
);
2621 signing_id
= __DECONST(char *, cs_id
);
2623 FDLOG0(LOG_WARNING
, fd_cb
, "Signature is invalid");
2626 FDLOG0(LOG_WARNING
, fd_cb
, "Failed to determine the current proc");
2629 src_proc
= PROC_NULL
;
2632 if (signing_id
!= NULL
) {
2633 uint16_t result
= NULL_TRIE_IDX
;
2634 lck_rw_lock_shared(&g_flow_divert_group_lck
);
2635 result
= flow_divert_trie_search(&g_signing_id_trie
, (uint8_t *)signing_id
);
2636 lck_rw_done(&g_flow_divert_group_lck
);
2637 if (result
!= NULL_TRIE_IDX
) {
2639 FDLOG(LOG_INFO
, fd_cb
, "%s matched", signing_id
);
2641 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_SIGNING_ID
, strlen(signing_id
), signing_id
);
2643 if (src_proc
!= PROC_NULL
) {
2644 unsigned char cdhash
[SHA1_RESULTLEN
];
2645 error
= proc_getcdhash(src_proc
, cdhash
);
2647 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_CDHASH
, sizeof(cdhash
), cdhash
);
2649 FDLOG(LOG_ERR
, fd_cb
, "failed to append the cdhash: %d", error
);
2652 FDLOG(LOG_ERR
, fd_cb
, "failed to get the cdhash: %d", error
);
2656 FDLOG(LOG_ERR
, fd_cb
, "failed to append the signing ID: %d", error
);
2659 FDLOG(LOG_WARNING
, fd_cb
, "%s did not match", signing_id
);
2662 FDLOG0(LOG_WARNING
, fd_cb
, "Failed to get the code signing identity");
2665 if (src_proc
!= PROC_NULL
) {
2666 proc_unlock(src_proc
);
2668 proc_rele(src_proc
);
2672 FDLOG0(LOG_WARNING
, fd_cb
, "The signing ID trie is empty");
2676 if (free_signing_id
) {
2677 FREE(signing_id
, M_TEMP
);
2684 FDLOG0(LOG_INFO
, fd_cb
, "Connecting");
2686 error
= flow_divert_send_connect(fd_cb
, to
, connect_packet
);
2691 fd_cb
->flags
|= FLOW_DIVERT_CONNECT_STARTED
;
2696 if (error
&& connect_packet
!= NULL
) {
2697 mbuf_freem(connect_packet
);
2703 flow_divert_connectx_out_common(struct socket
*so
, int af
,
2704 struct sockaddr_list
**src_sl
, struct sockaddr_list
**dst_sl
,
2705 struct proc
*p
, uint32_t ifscope __unused
, sae_associd_t aid __unused
,
2706 sae_connid_t
*pcid
, uint32_t flags __unused
, void *arg __unused
,
2707 uint32_t arglen __unused
)
2709 struct sockaddr_entry
*src_se
= NULL
, *dst_se
= NULL
;
2710 struct inpcb
*inp
= sotoinpcb(so
);
2717 VERIFY(dst_sl
!= NULL
);
2719 /* select source (if specified) and destination addresses */
2720 error
= in_selectaddrs(af
, src_sl
, &src_se
, dst_sl
, &dst_se
);
2725 VERIFY(*dst_sl
!= NULL
&& dst_se
!= NULL
);
2726 VERIFY(src_se
== NULL
|| *src_sl
!= NULL
);
2727 VERIFY(dst_se
->se_addr
->sa_family
== af
);
2728 VERIFY(src_se
== NULL
|| src_se
->se_addr
->sa_family
== af
);
2730 error
= flow_divert_connect_out(so
, dst_se
->se_addr
, p
);
2732 if (error
== 0 && pcid
!= NULL
) {
2733 *pcid
= 1; /* there is only 1 connection for a TCP */
2740 flow_divert_connectx_out(struct socket
*so
, struct sockaddr_list
**src_sl
,
2741 struct sockaddr_list
**dst_sl
, struct proc
*p
, uint32_t ifscope
,
2742 sae_associd_t aid
, sae_connid_t
*pcid
, uint32_t flags
, void *arg
,
2743 uint32_t arglen
, struct uio
*uio
, user_ssize_t
*bytes_written
)
2745 #pragma unused(uio, bytes_written)
2746 return (flow_divert_connectx_out_common(so
, AF_INET
, src_sl
, dst_sl
,
2747 p
, ifscope
, aid
, pcid
, flags
, arg
, arglen
));
2752 flow_divert_connectx6_out(struct socket
*so
, struct sockaddr_list
**src_sl
,
2753 struct sockaddr_list
**dst_sl
, struct proc
*p
, uint32_t ifscope
,
2754 sae_associd_t aid
, sae_connid_t
*pcid
, uint32_t flags
, void *arg
,
2755 uint32_t arglen
, struct uio
*uio
, user_ssize_t
*bytes_written
)
2757 #pragma unused(uio, bytes_written)
2758 return (flow_divert_connectx_out_common(so
, AF_INET6
, src_sl
, dst_sl
,
2759 p
, ifscope
, aid
, pcid
, flags
, arg
, arglen
));
2764 flow_divert_getconninfo(struct socket
*so
, sae_connid_t cid
, uint32_t *flags
,
2765 uint32_t *ifindex
, int32_t *soerror
, user_addr_t src
, socklen_t
*src_len
,
2766 user_addr_t dst
, socklen_t
*dst_len
, uint32_t *aux_type
,
2767 user_addr_t aux_data __unused
, uint32_t *aux_len
)
2770 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2771 struct ifnet
*ifp
= NULL
;
2772 struct inpcb
*inp
= sotoinpcb(so
);
2774 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
));
2776 if (so
->so_fd_pcb
== NULL
|| inp
== NULL
) {
2781 if (cid
!= SAE_CONNID_ANY
&& cid
!= SAE_CONNID_ALL
&& cid
!= 1) {
2786 ifp
= inp
->inp_last_outifp
;
2787 *ifindex
= ((ifp
!= NULL
) ? ifp
->if_index
: 0);
2788 *soerror
= so
->so_error
;
2791 if (so
->so_state
& SS_ISCONNECTED
) {
2792 *flags
|= (CIF_CONNECTED
| CIF_PREFERRED
);
2795 if (fd_cb
->local_address
== NULL
) {
2796 struct sockaddr_in sin
;
2797 bzero(&sin
, sizeof(sin
));
2798 sin
.sin_len
= sizeof(sin
);
2799 sin
.sin_family
= AF_INET
;
2800 *src_len
= sin
.sin_len
;
2801 if (src
!= USER_ADDR_NULL
) {
2802 error
= copyout(&sin
, src
, sin
.sin_len
);
2808 *src_len
= fd_cb
->local_address
->sa_len
;
2809 if (src
!= USER_ADDR_NULL
) {
2810 error
= copyout(fd_cb
->local_address
, src
, fd_cb
->local_address
->sa_len
);
2817 if (fd_cb
->remote_address
== NULL
) {
2818 struct sockaddr_in sin
;
2819 bzero(&sin
, sizeof(sin
));
2820 sin
.sin_len
= sizeof(sin
);
2821 sin
.sin_family
= AF_INET
;
2822 *dst_len
= sin
.sin_len
;
2823 if (dst
!= USER_ADDR_NULL
) {
2824 error
= copyout(&sin
, dst
, sin
.sin_len
);
2830 *dst_len
= fd_cb
->remote_address
->sa_len
;
2831 if (dst
!= USER_ADDR_NULL
) {
2832 error
= copyout(fd_cb
->remote_address
, dst
, fd_cb
->remote_address
->sa_len
);
2847 flow_divert_control(struct socket
*so
, u_long cmd
, caddr_t data
, struct ifnet
*ifp __unused
, struct proc
*p __unused
)
2852 case SIOCGCONNINFO32
: {
2853 struct so_cinforeq32 cifr
;
2854 bcopy(data
, &cifr
, sizeof (cifr
));
2855 error
= flow_divert_getconninfo(so
, cifr
.scir_cid
, &cifr
.scir_flags
,
2856 &cifr
.scir_ifindex
, &cifr
.scir_error
, cifr
.scir_src
,
2857 &cifr
.scir_src_len
, cifr
.scir_dst
, &cifr
.scir_dst_len
,
2858 &cifr
.scir_aux_type
, cifr
.scir_aux_data
,
2859 &cifr
.scir_aux_len
);
2861 bcopy(&cifr
, data
, sizeof (cifr
));
2866 case SIOCGCONNINFO64
: {
2867 struct so_cinforeq64 cifr
;
2868 bcopy(data
, &cifr
, sizeof (cifr
));
2869 error
= flow_divert_getconninfo(so
, cifr
.scir_cid
, &cifr
.scir_flags
,
2870 &cifr
.scir_ifindex
, &cifr
.scir_error
, cifr
.scir_src
,
2871 &cifr
.scir_src_len
, cifr
.scir_dst
, &cifr
.scir_dst_len
,
2872 &cifr
.scir_aux_type
, cifr
.scir_aux_data
,
2873 &cifr
.scir_aux_len
);
2875 bcopy(&cifr
, data
, sizeof (cifr
));
2888 flow_divert_in_control(struct socket
*so
, u_long cmd
, caddr_t data
, struct ifnet
*ifp
, struct proc
*p
)
2890 int error
= flow_divert_control(so
, cmd
, data
, ifp
, p
);
2892 if (error
== EOPNOTSUPP
) {
2893 error
= in_control(so
, cmd
, data
, ifp
, p
);
2900 flow_divert_in6_control(struct socket
*so
, u_long cmd
, caddr_t data
, struct ifnet
*ifp
, struct proc
*p
)
2902 int error
= flow_divert_control(so
, cmd
, data
, ifp
, p
);
2904 if (error
== EOPNOTSUPP
) {
2905 error
= in6_control(so
, cmd
, data
, ifp
, p
);
2912 flow_divert_data_out(struct socket
*so
, int flags
, mbuf_t data
, struct sockaddr
*to
, mbuf_t control
, struct proc
*p __unused
)
2914 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2918 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2920 inp
= sotoinpcb(so
);
2921 if (inp
== NULL
|| inp
->inp_state
== INPCB_STATE_DEAD
) {
2926 if (control
&& mbuf_len(control
) > 0) {
2931 if (flags
& MSG_OOB
) {
2933 goto done
; /* We don't support OOB data */
2936 error
= flow_divert_check_no_cellular(fd_cb
) ||
2937 flow_divert_check_no_expensive(fd_cb
);
2942 /* Implicit connect */
2943 if (!(fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
)) {
2944 FDLOG0(LOG_INFO
, fd_cb
, "implicit connect");
2945 error
= flow_divert_connect_out(so
, to
, NULL
);
2951 FDLOG(LOG_DEBUG
, fd_cb
, "app wrote %lu bytes", mbuf_pkthdr_len(data
));
2953 fd_cb
->bytes_written_by_app
+= mbuf_pkthdr_len(data
);
2954 error
= flow_divert_send_app_data(fd_cb
, data
, to
);
2961 if (flags
& PRUS_EOF
) {
2962 flow_divert_shutdown(so
);
2976 flow_divert_set_protosw(struct socket
*so
)
2978 so
->so_flags
|= SOF_FLOW_DIVERT
;
2979 if (SOCK_DOM(so
) == PF_INET
) {
2980 so
->so_proto
= &g_flow_divert_in_protosw
;
2984 so
->so_proto
= (struct protosw
*)&g_flow_divert_in6_protosw
;
2990 flow_divert_set_udp_protosw(struct socket
*so
)
2992 so
->so_flags
|= SOF_FLOW_DIVERT
;
2993 if (SOCK_DOM(so
) == PF_INET
) {
2994 so
->so_proto
= &g_flow_divert_in_udp_protosw
;
2998 so
->so_proto
= (struct protosw
*)&g_flow_divert_in6_udp_protosw
;
3004 flow_divert_attach(struct socket
*so
, uint32_t flow_id
, uint32_t ctl_unit
)
3007 struct flow_divert_pcb
*fd_cb
= NULL
;
3008 struct ifnet
*ifp
= NULL
;
3009 struct inpcb
*inp
= NULL
;
3010 struct socket
*old_so
;
3011 mbuf_t recv_data
= NULL
;
3013 socket_unlock(so
, 0);
3015 FDLOG(LOG_INFO
, &nil_pcb
, "Attaching socket to flow %u", flow_id
);
3017 /* Find the flow divert control block */
3018 lck_rw_lock_shared(&g_flow_divert_group_lck
);
3019 if (g_flow_divert_groups
!= NULL
&& g_active_group_count
> 0) {
3020 struct flow_divert_group
*group
= g_flow_divert_groups
[ctl_unit
];
3021 if (group
!= NULL
) {
3022 fd_cb
= flow_divert_pcb_lookup(flow_id
, group
);
3025 lck_rw_done(&g_flow_divert_group_lck
);
3027 if (fd_cb
== NULL
) {
3034 /* Dis-associate the flow divert control block from its current socket */
3037 inp
= sotoinpcb(old_so
);
3039 VERIFY(inp
!= NULL
);
3041 socket_lock(old_so
, 0);
3042 flow_divert_disconnect_socket(old_so
);
3043 old_so
->so_flags
&= ~SOF_FLOW_DIVERT
;
3044 old_so
->so_fd_pcb
= NULL
;
3045 if (SOCK_TYPE(old_so
) == SOCK_STREAM
) {
3046 old_so
->so_proto
= pffindproto(SOCK_DOM(old_so
), IPPROTO_TCP
, SOCK_STREAM
);
3047 } else if (SOCK_TYPE(old_so
) == SOCK_DGRAM
) {
3048 old_so
->so_proto
= pffindproto(SOCK_DOM(old_so
), IPPROTO_UDP
, SOCK_DGRAM
);
3051 /* Save the output interface */
3052 ifp
= inp
->inp_last_outifp
;
3053 if (old_so
->so_rcv
.sb_cc
> 0) {
3054 error
= mbuf_dup(old_so
->so_rcv
.sb_mb
, MBUF_DONTWAIT
, &recv_data
);
3055 sbflush(&old_so
->so_rcv
);
3057 socket_unlock(old_so
, 0);
3059 /* Associate the new socket with the flow divert control block */
3061 so
->so_fd_pcb
= fd_cb
;
3062 inp
= sotoinpcb(so
);
3063 inp
->inp_last_outifp
= ifp
;
3064 if (recv_data
!= NULL
) {
3065 if (sbappendstream(&so
->so_rcv
, recv_data
)) {
3069 flow_divert_set_protosw(so
);
3070 socket_unlock(so
, 0);
3073 fd_cb
->flags
|= FLOW_DIVERT_TRANSFERRED
;
3080 if (fd_cb
!= NULL
) {
3081 FDRELEASE(fd_cb
); /* Release the reference obtained via flow_divert_pcb_lookup */
3088 flow_divert_implicit_data_out(struct socket
*so
, int flags
, mbuf_t data
, struct sockaddr
*to
, mbuf_t control
, struct proc
*p
)
3090 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3094 inp
= sotoinpcb(so
);
3099 if (fd_cb
== NULL
) {
3100 uint32_t fd_ctl_unit
= necp_socket_get_flow_divert_control_unit(inp
);
3101 if (fd_ctl_unit
> 0) {
3102 error
= flow_divert_pcb_init(so
, fd_ctl_unit
);
3103 fd_cb
= so
->so_fd_pcb
;
3104 if (error
!= 0 || fd_cb
== NULL
) {
3112 return flow_divert_data_out(so
, flags
, data
, to
, control
, p
);
3126 flow_divert_pcb_init(struct socket
*so
, uint32_t ctl_unit
)
3129 struct flow_divert_pcb
*fd_cb
;
3131 if (so
->so_flags
& SOF_FLOW_DIVERT
) {
3135 fd_cb
= flow_divert_pcb_create(so
);
3136 if (fd_cb
!= NULL
) {
3137 error
= flow_divert_pcb_insert(fd_cb
, ctl_unit
);
3139 FDLOG(LOG_ERR
, fd_cb
, "pcb insert failed: %d", error
);
3142 fd_cb
->control_group_unit
= ctl_unit
;
3143 so
->so_fd_pcb
= fd_cb
;
3145 if (SOCK_TYPE(so
) == SOCK_STREAM
) {
3146 flow_divert_set_protosw(so
);
3147 } else if (SOCK_TYPE(so
) == SOCK_DGRAM
) {
3148 flow_divert_set_udp_protosw(so
);
3151 FDLOG0(LOG_INFO
, fd_cb
, "Created");
3161 flow_divert_token_set(struct socket
*so
, struct sockopt
*sopt
)
3163 uint32_t ctl_unit
= 0;
3164 uint32_t key_unit
= 0;
3165 uint32_t flow_id
= 0;
3167 mbuf_t token
= NULL
;
3169 if (so
->so_flags
& SOF_FLOW_DIVERT
) {
3174 if (g_init_result
) {
3175 FDLOG(LOG_ERR
, &nil_pcb
, "flow_divert_init failed (%d), cannot use flow divert", g_init_result
);
3176 error
= ENOPROTOOPT
;
3180 if ((SOCK_TYPE(so
) != SOCK_STREAM
&& SOCK_TYPE(so
) != SOCK_DGRAM
) ||
3181 (SOCK_PROTO(so
) != IPPROTO_TCP
&& SOCK_PROTO(so
) != IPPROTO_UDP
) ||
3182 (SOCK_DOM(so
) != PF_INET
3184 && SOCK_DOM(so
) != PF_INET6
3191 if (SOCK_TYPE(so
) == SOCK_STREAM
&& SOCK_PROTO(so
) == IPPROTO_TCP
) {
3192 struct tcpcb
*tp
= sototcpcb(so
);
3193 if (tp
== NULL
|| tp
->t_state
!= TCPS_CLOSED
) {
3200 error
= soopt_getm(sopt
, &token
);
3205 error
= soopt_mcopyin(sopt
, token
);
3210 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_KEY_UNIT
, sizeof(key_unit
), (void *)&key_unit
, NULL
);
3212 key_unit
= ntohl(key_unit
);
3213 } else if (error
!= ENOENT
) {
3214 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to get the key unit from the token: %d", error
);
3220 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), (void *)&ctl_unit
, NULL
);
3222 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to get the control socket unit from the token: %d", error
);
3226 /* A valid kernel control unit is required */
3227 ctl_unit
= ntohl(ctl_unit
);
3228 if (ctl_unit
== 0 || ctl_unit
>= GROUP_COUNT_MAX
) {
3229 FDLOG(LOG_ERR
, &nil_pcb
, "Got an invalid control socket unit: %u", ctl_unit
);
3234 socket_unlock(so
, 0);
3235 error
= flow_divert_packet_verify_hmac(token
, (key_unit
!= 0 ? key_unit
: ctl_unit
));
3239 FDLOG(LOG_ERR
, &nil_pcb
, "HMAC verfication failed: %d", error
);
3243 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_FLOW_ID
, sizeof(flow_id
), (void *)&flow_id
, NULL
);
3244 if (error
&& error
!= ENOENT
) {
3245 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to get the flow ID from the token: %d", error
);
3250 error
= flow_divert_pcb_init(so
, ctl_unit
);
3252 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3253 int log_level
= LOG_NOTICE
;
3255 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_LOG_LEVEL
,
3256 sizeof(log_level
), &log_level
, NULL
);
3258 fd_cb
->log_level
= log_level
;
3262 fd_cb
->connect_token
= token
;
3266 error
= flow_divert_attach(so
, flow_id
, ctl_unit
);
3270 if (token
!= NULL
) {
3278 flow_divert_token_get(struct socket
*so
, struct sockopt
*sopt
)
3282 uint8_t hmac
[SHA_DIGEST_LENGTH
];
3283 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3284 mbuf_t token
= NULL
;
3285 struct flow_divert_group
*control_group
= NULL
;
3287 if (!(so
->so_flags
& SOF_FLOW_DIVERT
)) {
3292 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
3294 if (fd_cb
->group
== NULL
) {
3299 error
= mbuf_gethdr(MBUF_DONTWAIT
, MBUF_TYPE_HEADER
, &token
);
3301 FDLOG(LOG_ERR
, fd_cb
, "failed to allocate the header mbuf: %d", error
);
3305 ctl_unit
= htonl(fd_cb
->group
->ctl_unit
);
3307 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), &ctl_unit
);
3312 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_FLOW_ID
, sizeof(fd_cb
->hash
), &fd_cb
->hash
);
3317 socket_unlock(so
, 0);
3318 lck_rw_lock_shared(&g_flow_divert_group_lck
);
3320 if (g_flow_divert_groups
!= NULL
&& g_active_group_count
> 0 &&
3321 fd_cb
->control_group_unit
> 0 && fd_cb
->control_group_unit
< GROUP_COUNT_MAX
)
3323 control_group
= g_flow_divert_groups
[fd_cb
->control_group_unit
];
3326 if (control_group
!= NULL
) {
3327 lck_rw_lock_shared(&control_group
->lck
);
3328 ctl_unit
= htonl(control_group
->ctl_unit
);
3329 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_KEY_UNIT
, sizeof(ctl_unit
), &ctl_unit
);
3331 error
= flow_divert_packet_compute_hmac(token
, control_group
, hmac
);
3333 lck_rw_done(&control_group
->lck
);
3335 error
= ENOPROTOOPT
;
3338 lck_rw_done(&g_flow_divert_group_lck
);
3345 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_HMAC
, sizeof(hmac
), hmac
);
3350 error
= soopt_mcopyout(sopt
, token
);
3352 token
= NULL
; /* For some reason, soopt_mcopyout() frees the mbuf if it fails */
3357 if (token
!= NULL
) {
3365 flow_divert_kctl_connect(kern_ctl_ref kctlref __unused
, struct sockaddr_ctl
*sac
, void **unitinfo
)
3367 struct flow_divert_group
*new_group
= NULL
;
3370 if (sac
->sc_unit
>= GROUP_COUNT_MAX
) {
3377 MALLOC_ZONE(new_group
, struct flow_divert_group
*, sizeof(*new_group
), M_FLOW_DIVERT_GROUP
, M_WAITOK
);
3378 if (new_group
== NULL
) {
3383 memset(new_group
, 0, sizeof(*new_group
));
3385 lck_rw_init(&new_group
->lck
, flow_divert_mtx_grp
, flow_divert_mtx_attr
);
3386 RB_INIT(&new_group
->pcb_tree
);
3387 new_group
->ctl_unit
= sac
->sc_unit
;
3388 MBUFQ_INIT(&new_group
->send_queue
);
3390 lck_rw_lock_exclusive(&g_flow_divert_group_lck
);
3392 if (g_flow_divert_groups
== NULL
) {
3393 MALLOC(g_flow_divert_groups
,
3394 struct flow_divert_group
**,
3395 GROUP_COUNT_MAX
* sizeof(struct flow_divert_group
*),
3400 if (g_flow_divert_groups
== NULL
) {
3402 } else if (g_flow_divert_groups
[sac
->sc_unit
] != NULL
) {
3405 g_flow_divert_groups
[sac
->sc_unit
] = new_group
;
3406 g_active_group_count
++;
3409 lck_rw_done(&g_flow_divert_group_lck
);
3411 *unitinfo
= new_group
;
3414 if (error
!= 0 && new_group
!= NULL
) {
3415 FREE_ZONE(new_group
, sizeof(*new_group
), M_FLOW_DIVERT_GROUP
);
3421 flow_divert_kctl_disconnect(kern_ctl_ref kctlref __unused
, uint32_t unit
, void *unitinfo
)
3423 struct flow_divert_group
*group
= NULL
;
3427 if (unit
>= GROUP_COUNT_MAX
) {
3431 FDLOG(LOG_INFO
, &nil_pcb
, "disconnecting group %d", unit
);
3433 lck_rw_lock_exclusive(&g_flow_divert_group_lck
);
3435 if (g_flow_divert_groups
== NULL
|| g_active_group_count
== 0) {
3436 panic("flow divert group %u is disconnecting, but no groups are active (groups = %p, active count = %u", unit
,
3437 g_flow_divert_groups
, g_active_group_count
);
3440 group
= g_flow_divert_groups
[unit
];
3442 if (group
!= (struct flow_divert_group
*)unitinfo
) {
3443 panic("group with unit %d (%p) != unit info (%p)", unit
, group
, unitinfo
);
3446 if (group
!= NULL
) {
3447 flow_divert_close_all(group
);
3448 if (group
->token_key
!= NULL
) {
3449 memset(group
->token_key
, 0, group
->token_key_size
);
3450 FREE(group
->token_key
, M_TEMP
);
3451 group
->token_key
= NULL
;
3452 group
->token_key_size
= 0;
3454 FREE_ZONE(group
, sizeof(*group
), M_FLOW_DIVERT_GROUP
);
3455 g_flow_divert_groups
[unit
] = NULL
;
3456 g_active_group_count
--;
3461 if (g_active_group_count
== 0) {
3462 FREE(g_flow_divert_groups
, M_TEMP
);
3463 g_flow_divert_groups
= NULL
;
3466 /* Remove all signing IDs that point to this unit */
3467 for (node
= 0; node
< g_signing_id_trie
.nodes_count
; node
++) {
3468 if (TRIE_NODE(&g_signing_id_trie
, node
).group_unit
== unit
) {
3469 TRIE_NODE(&g_signing_id_trie
, node
).group_unit
= 0;
3473 lck_rw_done(&g_flow_divert_group_lck
);
3479 flow_divert_kctl_send(kern_ctl_ref kctlref __unused
, uint32_t unit __unused
, void *unitinfo
, mbuf_t m
, int flags __unused
)
3481 return flow_divert_input(m
, (struct flow_divert_group
*)unitinfo
);
3485 flow_divert_kctl_rcvd(kern_ctl_ref kctlref __unused
, uint32_t unit __unused
, void *unitinfo
, int flags __unused
)
3487 struct flow_divert_group
*group
= (struct flow_divert_group
*)unitinfo
;
3489 if (!OSTestAndClear(GROUP_BIT_CTL_ENQUEUE_BLOCKED
, &group
->atomic_bits
)) {
3490 struct flow_divert_pcb
*fd_cb
;
3491 SLIST_HEAD(, flow_divert_pcb
) tmp_list
;
3493 lck_rw_lock_shared(&g_flow_divert_group_lck
);
3494 lck_rw_lock_exclusive(&group
->lck
);
3496 while (!MBUFQ_EMPTY(&group
->send_queue
)) {
3498 FDLOG0(LOG_DEBUG
, &nil_pcb
, "trying ctl_enqueuembuf again");
3499 next_packet
= MBUFQ_FIRST(&group
->send_queue
);
3500 int error
= ctl_enqueuembuf(g_flow_divert_kctl_ref
, group
->ctl_unit
, next_packet
, CTL_DATA_EOR
);
3502 FDLOG(LOG_DEBUG
, &nil_pcb
, "ctl_enqueuembuf returned an error: %d", error
);
3503 OSTestAndSet(GROUP_BIT_CTL_ENQUEUE_BLOCKED
, &group
->atomic_bits
);
3504 lck_rw_done(&group
->lck
);
3505 lck_rw_done(&g_flow_divert_group_lck
);
3508 MBUFQ_DEQUEUE(&group
->send_queue
, next_packet
);
3511 SLIST_INIT(&tmp_list
);
3513 RB_FOREACH(fd_cb
, fd_pcb_tree
, &group
->pcb_tree
) {
3515 SLIST_INSERT_HEAD(&tmp_list
, fd_cb
, tmp_list_entry
);
3518 lck_rw_done(&group
->lck
);
3520 SLIST_FOREACH(fd_cb
, &tmp_list
, tmp_list_entry
) {
3522 if (fd_cb
->so
!= NULL
) {
3523 socket_lock(fd_cb
->so
, 0);
3524 if (fd_cb
->group
!= NULL
) {
3525 flow_divert_send_buffered_data(fd_cb
, FALSE
);
3527 socket_unlock(fd_cb
->so
, 0);
3533 lck_rw_done(&g_flow_divert_group_lck
);
3538 flow_divert_kctl_init(void)
3540 struct kern_ctl_reg ctl_reg
;
3543 memset(&ctl_reg
, 0, sizeof(ctl_reg
));
3545 strlcpy(ctl_reg
.ctl_name
, FLOW_DIVERT_CONTROL_NAME
, sizeof(ctl_reg
.ctl_name
));
3546 ctl_reg
.ctl_name
[sizeof(ctl_reg
.ctl_name
)-1] = '\0';
3547 ctl_reg
.ctl_flags
= CTL_FLAG_PRIVILEGED
| CTL_FLAG_REG_EXTENDED
;
3548 ctl_reg
.ctl_sendsize
= FD_CTL_SENDBUFF_SIZE
;
3549 ctl_reg
.ctl_recvsize
= FD_CTL_RCVBUFF_SIZE
;
3551 ctl_reg
.ctl_connect
= flow_divert_kctl_connect
;
3552 ctl_reg
.ctl_disconnect
= flow_divert_kctl_disconnect
;
3553 ctl_reg
.ctl_send
= flow_divert_kctl_send
;
3554 ctl_reg
.ctl_rcvd
= flow_divert_kctl_rcvd
;
3556 result
= ctl_register(&ctl_reg
, &g_flow_divert_kctl_ref
);
3559 FDLOG(LOG_ERR
, &nil_pcb
, "flow_divert_kctl_init - ctl_register failed: %d\n", result
);
3567 flow_divert_init(void)
3569 memset(&nil_pcb
, 0, sizeof(nil_pcb
));
3570 nil_pcb
.log_level
= LOG_NOTICE
;
3572 g_tcp_protosw
= pffindproto(AF_INET
, IPPROTO_TCP
, SOCK_STREAM
);
3574 VERIFY(g_tcp_protosw
!= NULL
);
3576 memcpy(&g_flow_divert_in_protosw
, g_tcp_protosw
, sizeof(g_flow_divert_in_protosw
));
3577 memcpy(&g_flow_divert_in_usrreqs
, g_tcp_protosw
->pr_usrreqs
, sizeof(g_flow_divert_in_usrreqs
));
3579 g_flow_divert_in_usrreqs
.pru_connect
= flow_divert_connect_out
;
3580 g_flow_divert_in_usrreqs
.pru_connectx
= flow_divert_connectx_out
;
3581 g_flow_divert_in_usrreqs
.pru_control
= flow_divert_in_control
;
3582 g_flow_divert_in_usrreqs
.pru_disconnect
= flow_divert_close
;
3583 g_flow_divert_in_usrreqs
.pru_disconnectx
= flow_divert_disconnectx
;
3584 g_flow_divert_in_usrreqs
.pru_peeraddr
= flow_divert_getpeername
;
3585 g_flow_divert_in_usrreqs
.pru_rcvd
= flow_divert_rcvd
;
3586 g_flow_divert_in_usrreqs
.pru_send
= flow_divert_data_out
;
3587 g_flow_divert_in_usrreqs
.pru_shutdown
= flow_divert_shutdown
;
3588 g_flow_divert_in_usrreqs
.pru_sockaddr
= flow_divert_getsockaddr
;
3590 g_flow_divert_in_protosw
.pr_usrreqs
= &g_flow_divert_in_usrreqs
;
3591 g_flow_divert_in_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
3594 * Socket filters shouldn't attach/detach to/from this protosw
3595 * since pr_protosw is to be used instead, which points to the
3596 * real protocol; if they do, it is a bug and we should panic.
3598 g_flow_divert_in_protosw
.pr_filter_head
.tqh_first
=
3599 (struct socket_filter
*)(uintptr_t)0xdeadbeefdeadbeef;
3600 g_flow_divert_in_protosw
.pr_filter_head
.tqh_last
=
3601 (struct socket_filter
**)(uintptr_t)0xdeadbeefdeadbeef;
3604 g_udp_protosw
= pffindproto(AF_INET
, IPPROTO_UDP
, SOCK_DGRAM
);
3605 VERIFY(g_udp_protosw
!= NULL
);
3607 memcpy(&g_flow_divert_in_udp_protosw
, g_udp_protosw
, sizeof(g_flow_divert_in_udp_protosw
));
3608 memcpy(&g_flow_divert_in_udp_usrreqs
, g_udp_protosw
->pr_usrreqs
, sizeof(g_flow_divert_in_udp_usrreqs
));
3610 g_flow_divert_in_udp_usrreqs
.pru_connect
= flow_divert_connect_out
;
3611 g_flow_divert_in_udp_usrreqs
.pru_connectx
= flow_divert_connectx_out
;
3612 g_flow_divert_in_udp_usrreqs
.pru_control
= flow_divert_in_control
;
3613 g_flow_divert_in_udp_usrreqs
.pru_disconnect
= flow_divert_close
;
3614 g_flow_divert_in_udp_usrreqs
.pru_disconnectx
= flow_divert_disconnectx
;
3615 g_flow_divert_in_udp_usrreqs
.pru_peeraddr
= flow_divert_getpeername
;
3616 g_flow_divert_in_udp_usrreqs
.pru_rcvd
= flow_divert_rcvd
;
3617 g_flow_divert_in_udp_usrreqs
.pru_send
= flow_divert_data_out
;
3618 g_flow_divert_in_udp_usrreqs
.pru_shutdown
= flow_divert_shutdown
;
3619 g_flow_divert_in_udp_usrreqs
.pru_sockaddr
= flow_divert_getsockaddr
;
3620 g_flow_divert_in_udp_usrreqs
.pru_sosend_list
= pru_sosend_list_notsupp
;
3621 g_flow_divert_in_udp_usrreqs
.pru_soreceive_list
= pru_soreceive_list_notsupp
;
3623 g_flow_divert_in_udp_protosw
.pr_usrreqs
= &g_flow_divert_in_usrreqs
;
3624 g_flow_divert_in_udp_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
3627 * Socket filters shouldn't attach/detach to/from this protosw
3628 * since pr_protosw is to be used instead, which points to the
3629 * real protocol; if they do, it is a bug and we should panic.
3631 g_flow_divert_in_udp_protosw
.pr_filter_head
.tqh_first
=
3632 (struct socket_filter
*)(uintptr_t)0xdeadbeefdeadbeef;
3633 g_flow_divert_in_udp_protosw
.pr_filter_head
.tqh_last
=
3634 (struct socket_filter
**)(uintptr_t)0xdeadbeefdeadbeef;
3637 g_tcp6_protosw
= (struct ip6protosw
*)pffindproto(AF_INET6
, IPPROTO_TCP
, SOCK_STREAM
);
3639 VERIFY(g_tcp6_protosw
!= NULL
);
3641 memcpy(&g_flow_divert_in6_protosw
, g_tcp6_protosw
, sizeof(g_flow_divert_in6_protosw
));
3642 memcpy(&g_flow_divert_in6_usrreqs
, g_tcp6_protosw
->pr_usrreqs
, sizeof(g_flow_divert_in6_usrreqs
));
3644 g_flow_divert_in6_usrreqs
.pru_connect
= flow_divert_connect_out
;
3645 g_flow_divert_in6_usrreqs
.pru_connectx
= flow_divert_connectx6_out
;
3646 g_flow_divert_in6_usrreqs
.pru_control
= flow_divert_in6_control
;
3647 g_flow_divert_in6_usrreqs
.pru_disconnect
= flow_divert_close
;
3648 g_flow_divert_in6_usrreqs
.pru_disconnectx
= flow_divert_disconnectx
;
3649 g_flow_divert_in6_usrreqs
.pru_peeraddr
= flow_divert_getpeername
;
3650 g_flow_divert_in6_usrreqs
.pru_rcvd
= flow_divert_rcvd
;
3651 g_flow_divert_in6_usrreqs
.pru_send
= flow_divert_data_out
;
3652 g_flow_divert_in6_usrreqs
.pru_shutdown
= flow_divert_shutdown
;
3653 g_flow_divert_in6_usrreqs
.pru_sockaddr
= flow_divert_getsockaddr
;
3655 g_flow_divert_in6_protosw
.pr_usrreqs
= &g_flow_divert_in6_usrreqs
;
3656 g_flow_divert_in6_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
3658 * Socket filters shouldn't attach/detach to/from this protosw
3659 * since pr_protosw is to be used instead, which points to the
3660 * real protocol; if they do, it is a bug and we should panic.
3662 g_flow_divert_in6_protosw
.pr_filter_head
.tqh_first
=
3663 (struct socket_filter
*)(uintptr_t)0xdeadbeefdeadbeef;
3664 g_flow_divert_in6_protosw
.pr_filter_head
.tqh_last
=
3665 (struct socket_filter
**)(uintptr_t)0xdeadbeefdeadbeef;
3668 g_udp6_protosw
= (struct ip6protosw
*)pffindproto(AF_INET6
, IPPROTO_UDP
, SOCK_DGRAM
);
3670 VERIFY(g_udp6_protosw
!= NULL
);
3672 memcpy(&g_flow_divert_in6_udp_protosw
, g_udp6_protosw
, sizeof(g_flow_divert_in6_udp_protosw
));
3673 memcpy(&g_flow_divert_in6_udp_usrreqs
, g_udp6_protosw
->pr_usrreqs
, sizeof(g_flow_divert_in6_udp_usrreqs
));
3675 g_flow_divert_in6_udp_usrreqs
.pru_connect
= flow_divert_connect_out
;
3676 g_flow_divert_in6_udp_usrreqs
.pru_connectx
= flow_divert_connectx6_out
;
3677 g_flow_divert_in6_udp_usrreqs
.pru_control
= flow_divert_in6_control
;
3678 g_flow_divert_in6_udp_usrreqs
.pru_disconnect
= flow_divert_close
;
3679 g_flow_divert_in6_udp_usrreqs
.pru_disconnectx
= flow_divert_disconnectx
;
3680 g_flow_divert_in6_udp_usrreqs
.pru_peeraddr
= flow_divert_getpeername
;
3681 g_flow_divert_in6_udp_usrreqs
.pru_rcvd
= flow_divert_rcvd
;
3682 g_flow_divert_in6_udp_usrreqs
.pru_send
= flow_divert_data_out
;
3683 g_flow_divert_in6_udp_usrreqs
.pru_shutdown
= flow_divert_shutdown
;
3684 g_flow_divert_in6_udp_usrreqs
.pru_sockaddr
= flow_divert_getsockaddr
;
3685 g_flow_divert_in6_udp_usrreqs
.pru_sosend_list
= pru_sosend_list_notsupp
;
3686 g_flow_divert_in6_udp_usrreqs
.pru_soreceive_list
= pru_soreceive_list_notsupp
;
3688 g_flow_divert_in6_udp_protosw
.pr_usrreqs
= &g_flow_divert_in6_udp_usrreqs
;
3689 g_flow_divert_in6_udp_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
3691 * Socket filters shouldn't attach/detach to/from this protosw
3692 * since pr_protosw is to be used instead, which points to the
3693 * real protocol; if they do, it is a bug and we should panic.
3695 g_flow_divert_in6_udp_protosw
.pr_filter_head
.tqh_first
=
3696 (struct socket_filter
*)(uintptr_t)0xdeadbeefdeadbeef;
3697 g_flow_divert_in6_udp_protosw
.pr_filter_head
.tqh_last
=
3698 (struct socket_filter
**)(uintptr_t)0xdeadbeefdeadbeef;
3701 flow_divert_grp_attr
= lck_grp_attr_alloc_init();
3702 if (flow_divert_grp_attr
== NULL
) {
3703 FDLOG0(LOG_ERR
, &nil_pcb
, "lck_grp_attr_alloc_init failed");
3704 g_init_result
= ENOMEM
;
3708 flow_divert_mtx_grp
= lck_grp_alloc_init(FLOW_DIVERT_CONTROL_NAME
, flow_divert_grp_attr
);
3709 if (flow_divert_mtx_grp
== NULL
) {
3710 FDLOG0(LOG_ERR
, &nil_pcb
, "lck_grp_alloc_init failed");
3711 g_init_result
= ENOMEM
;
3715 flow_divert_mtx_attr
= lck_attr_alloc_init();
3716 if (flow_divert_mtx_attr
== NULL
) {
3717 FDLOG0(LOG_ERR
, &nil_pcb
, "lck_attr_alloc_init failed");
3718 g_init_result
= ENOMEM
;
3722 g_init_result
= flow_divert_kctl_init();
3723 if (g_init_result
) {
3727 lck_rw_init(&g_flow_divert_group_lck
, flow_divert_mtx_grp
, flow_divert_mtx_attr
);
3729 memset(&g_signing_id_trie
, 0, sizeof(g_signing_id_trie
));
3730 g_signing_id_trie
.root
= NULL_TRIE_IDX
;
3733 if (g_init_result
!= 0) {
3734 if (flow_divert_mtx_attr
!= NULL
) {
3735 lck_attr_free(flow_divert_mtx_attr
);
3736 flow_divert_mtx_attr
= NULL
;
3738 if (flow_divert_mtx_grp
!= NULL
) {
3739 lck_grp_free(flow_divert_mtx_grp
);
3740 flow_divert_mtx_grp
= NULL
;
3742 if (flow_divert_grp_attr
!= NULL
) {
3743 lck_grp_attr_free(flow_divert_grp_attr
);
3744 flow_divert_grp_attr
= NULL
;
3747 if (g_flow_divert_kctl_ref
!= NULL
) {
3748 ctl_deregister(g_flow_divert_kctl_ref
);
3749 g_flow_divert_kctl_ref
= NULL
;