2 * Copyright (c) 2012-2017, 2020, 2021 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 <kern/task.h>
49 #include <mach/task_info.h>
50 #include <net/if_var.h>
51 #include <net/route.h>
52 #include <net/flowhash.h>
53 #include <net/ntstat.h>
54 #include <net/content_filter.h>
56 #include <netinet/in.h>
57 #include <netinet/in_var.h>
58 #include <netinet/tcp.h>
59 #include <netinet/tcp_var.h>
60 #include <netinet/tcp_fsm.h>
61 #include <netinet/flow_divert.h>
62 #include <netinet/flow_divert_proto.h>
63 #include <netinet6/in6_pcb.h>
64 #include <netinet6/ip6protosw.h>
65 #include <dev/random/randomdev.h>
66 #include <libkern/crypto/sha1.h>
67 #include <libkern/crypto/crypto_internal.h>
69 #include <corecrypto/cc.h>
71 #include <net/content_filter.h>
72 #endif /* CONTENT_FILTER */
74 #define FLOW_DIVERT_CONNECT_STARTED 0x00000001
75 #define FLOW_DIVERT_READ_CLOSED 0x00000002
76 #define FLOW_DIVERT_WRITE_CLOSED 0x00000004
77 #define FLOW_DIVERT_TUNNEL_RD_CLOSED 0x00000008
78 #define FLOW_DIVERT_TUNNEL_WR_CLOSED 0x00000010
79 #define FLOW_DIVERT_HAS_HMAC 0x00000040
80 #define FLOW_DIVERT_NOTIFY_ON_RECEIVED 0x00000080
81 #define FLOW_DIVERT_IMPLICIT_CONNECT 0x00000100
82 #define FLOW_DIVERT_DID_SET_LOCAL_ADDR 0x00000200
83 #define FLOW_DIVERT_HAS_TOKEN 0x00000400
84 #define FLOW_DIVERT_SHOULD_SET_LOCAL_ADDR 0x00000800
86 #define FDLOG(level, pcb, format, ...) \
87 os_log_with_type(OS_LOG_DEFAULT, flow_divert_syslog_type_to_oslog_type(level), "(%u): " format "\n", (pcb)->hash, __VA_ARGS__)
89 #define FDLOG0(level, pcb, msg) \
90 os_log_with_type(OS_LOG_DEFAULT, flow_divert_syslog_type_to_oslog_type(level), "(%u): " msg "\n", (pcb)->hash)
92 #define FDRETAIN(pcb) if ((pcb) != NULL) OSIncrementAtomic(&(pcb)->ref_count)
93 #define FDRELEASE(pcb) \
95 if ((pcb) != NULL && 1 == OSDecrementAtomic(&(pcb)->ref_count)) { \
96 flow_divert_pcb_destroy(pcb); \
100 #define FDLOCK(pcb) lck_mtx_lock(&(pcb)->mtx)
101 #define FDUNLOCK(pcb) lck_mtx_unlock(&(pcb)->mtx)
103 #define FD_CTL_SENDBUFF_SIZE (128 * 1024)
104 #define FD_CTL_RCVBUFF_SIZE (128 * 1024)
106 #define GROUP_BIT_CTL_ENQUEUE_BLOCKED 0
108 #define GROUP_COUNT_MAX 31
109 #define FLOW_DIVERT_MAX_NAME_SIZE 4096
110 #define FLOW_DIVERT_MAX_KEY_SIZE 1024
111 #define FLOW_DIVERT_MAX_TRIE_MEMORY (1024 * 1024)
113 struct flow_divert_trie_node
{
119 #define CHILD_MAP_SIZE 256
120 #define NULL_TRIE_IDX 0xffff
121 #define TRIE_NODE(t, i) ((t)->nodes[(i)])
122 #define TRIE_CHILD(t, i, b) (((t)->child_maps + (CHILD_MAP_SIZE * TRIE_NODE(t, i).child_map))[(b)])
123 #define TRIE_BYTE(t, i) ((t)->bytes[(i)])
125 static struct flow_divert_pcb nil_pcb
;
127 decl_lck_rw_data(static, g_flow_divert_group_lck
);
128 static struct flow_divert_group
**g_flow_divert_groups
= NULL
;
129 static uint32_t g_active_group_count
= 0;
131 static lck_grp_attr_t
*flow_divert_grp_attr
= NULL
;
132 static lck_attr_t
*flow_divert_mtx_attr
= NULL
;
133 static lck_grp_t
*flow_divert_mtx_grp
= NULL
;
134 static errno_t g_init_result
= 0;
136 static kern_ctl_ref g_flow_divert_kctl_ref
= NULL
;
138 static struct protosw g_flow_divert_in_protosw
;
139 static struct pr_usrreqs g_flow_divert_in_usrreqs
;
140 static struct protosw g_flow_divert_in_udp_protosw
;
141 static struct pr_usrreqs g_flow_divert_in_udp_usrreqs
;
142 static struct ip6protosw g_flow_divert_in6_protosw
;
143 static struct pr_usrreqs g_flow_divert_in6_usrreqs
;
144 static struct ip6protosw g_flow_divert_in6_udp_protosw
;
145 static struct pr_usrreqs g_flow_divert_in6_udp_usrreqs
;
147 static struct protosw
*g_tcp_protosw
= NULL
;
148 static struct ip6protosw
*g_tcp6_protosw
= NULL
;
149 static struct protosw
*g_udp_protosw
= NULL
;
150 static struct ip6protosw
*g_udp6_protosw
= NULL
;
152 ZONE_DECLARE(flow_divert_group_zone
, "flow_divert_group",
153 sizeof(struct flow_divert_group
), ZC_ZFREE_CLEARMEM
| ZC_NOENCRYPT
);
154 ZONE_DECLARE(flow_divert_pcb_zone
, "flow_divert_pcb",
155 sizeof(struct flow_divert_pcb
), ZC_ZFREE_CLEARMEM
| ZC_NOENCRYPT
);
158 flow_divert_dup_addr(sa_family_t family
, struct sockaddr
*addr
, struct sockaddr
**dup
);
161 flow_divert_is_sockaddr_valid(struct sockaddr
*addr
);
164 flow_divert_append_target_endpoint_tlv(mbuf_t connect_packet
, struct sockaddr
*toaddr
);
167 flow_divert_get_buffered_target_address(mbuf_t buffer
);
170 flow_divert_disconnect_socket(struct socket
*so
);
172 static inline uint8_t
173 flow_divert_syslog_type_to_oslog_type(int syslog_type
)
175 switch (syslog_type
) {
176 case LOG_ERR
: return OS_LOG_TYPE_ERROR
;
177 case LOG_INFO
: return OS_LOG_TYPE_INFO
;
178 case LOG_DEBUG
: return OS_LOG_TYPE_DEBUG
;
179 default: return OS_LOG_TYPE_DEFAULT
;
184 flow_divert_pcb_cmp(const struct flow_divert_pcb
*pcb_a
, const struct flow_divert_pcb
*pcb_b
)
186 return memcmp(&pcb_a
->hash
, &pcb_b
->hash
, sizeof(pcb_a
->hash
));
189 RB_PROTOTYPE(fd_pcb_tree
, flow_divert_pcb
, rb_link
, flow_divert_pcb_cmp
);
190 RB_GENERATE(fd_pcb_tree
, flow_divert_pcb
, rb_link
, flow_divert_pcb_cmp
);
193 flow_divert_packet_type2str(uint8_t packet_type
)
195 switch (packet_type
) {
196 case FLOW_DIVERT_PKT_CONNECT
:
198 case FLOW_DIVERT_PKT_CONNECT_RESULT
:
199 return "connect result";
200 case FLOW_DIVERT_PKT_DATA
:
202 case FLOW_DIVERT_PKT_CLOSE
:
204 case FLOW_DIVERT_PKT_READ_NOTIFY
:
205 return "read notification";
206 case FLOW_DIVERT_PKT_PROPERTIES_UPDATE
:
207 return "properties update";
208 case FLOW_DIVERT_PKT_APP_MAP_CREATE
:
209 return "app map create";
215 static struct flow_divert_pcb
*
216 flow_divert_pcb_lookup(uint32_t hash
, struct flow_divert_group
*group
)
218 struct flow_divert_pcb key_item
;
219 struct flow_divert_pcb
*fd_cb
= NULL
;
221 key_item
.hash
= hash
;
223 lck_rw_lock_shared(&group
->lck
);
224 fd_cb
= RB_FIND(fd_pcb_tree
, &group
->pcb_tree
, &key_item
);
226 lck_rw_done(&group
->lck
);
232 flow_divert_pcb_insert(struct flow_divert_pcb
*fd_cb
, uint32_t ctl_unit
)
235 struct flow_divert_pcb
*exist
= NULL
;
236 struct flow_divert_group
*group
;
237 static uint32_t g_nextkey
= 1;
238 static uint32_t g_hash_seed
= 0;
241 if (ctl_unit
== 0 || ctl_unit
>= GROUP_COUNT_MAX
) {
245 socket_unlock(fd_cb
->so
, 0);
246 lck_rw_lock_shared(&g_flow_divert_group_lck
);
248 if (g_flow_divert_groups
== NULL
|| g_active_group_count
== 0) {
249 FDLOG0(LOG_ERR
, &nil_pcb
, "No active groups, flow divert cannot be used for this socket");
254 group
= g_flow_divert_groups
[ctl_unit
];
256 FDLOG(LOG_ERR
, &nil_pcb
, "Group for control unit %u is NULL, flow divert cannot be used for this socket", ctl_unit
);
261 socket_lock(fd_cb
->so
, 0);
267 key
[0] = g_nextkey
++;
268 key
[1] = RandomULong();
270 if (g_hash_seed
== 0) {
271 g_hash_seed
= RandomULong();
274 fd_cb
->hash
= net_flowhash(key
, sizeof(key
), g_hash_seed
);
276 for (idx
= 1; idx
< GROUP_COUNT_MAX
; idx
++) {
277 struct flow_divert_group
*curr_group
= g_flow_divert_groups
[idx
];
278 if (curr_group
!= NULL
&& curr_group
!= group
) {
279 lck_rw_lock_shared(&curr_group
->lck
);
280 exist
= RB_FIND(fd_pcb_tree
, &curr_group
->pcb_tree
, fd_cb
);
281 lck_rw_done(&curr_group
->lck
);
289 lck_rw_lock_exclusive(&group
->lck
);
290 exist
= RB_INSERT(fd_pcb_tree
, &group
->pcb_tree
, fd_cb
);
291 lck_rw_done(&group
->lck
);
293 } while (exist
!= NULL
&& try_count
++ < 3);
296 fd_cb
->group
= group
;
297 FDRETAIN(fd_cb
); /* The group now has a reference */
303 socket_unlock(fd_cb
->so
, 0);
306 lck_rw_done(&g_flow_divert_group_lck
);
307 socket_lock(fd_cb
->so
, 0);
312 static struct flow_divert_pcb
*
313 flow_divert_pcb_create(socket_t so
)
315 struct flow_divert_pcb
*new_pcb
= NULL
;
317 new_pcb
= zalloc_flags(flow_divert_pcb_zone
, Z_WAITOK
| Z_ZERO
);
318 lck_mtx_init(&new_pcb
->mtx
, flow_divert_mtx_grp
, flow_divert_mtx_attr
);
320 new_pcb
->log_level
= nil_pcb
.log_level
;
322 FDRETAIN(new_pcb
); /* Represents the socket's reference */
328 flow_divert_pcb_destroy(struct flow_divert_pcb
*fd_cb
)
330 FDLOG(LOG_INFO
, fd_cb
, "Destroying, app tx %u, tunnel tx %u, tunnel rx %u",
331 fd_cb
->bytes_written_by_app
, fd_cb
->bytes_sent
, fd_cb
->bytes_received
);
333 if (fd_cb
->connect_token
!= NULL
) {
334 mbuf_freem(fd_cb
->connect_token
);
336 if (fd_cb
->connect_packet
!= NULL
) {
337 mbuf_freem(fd_cb
->connect_packet
);
339 if (fd_cb
->app_data
!= NULL
) {
340 FREE(fd_cb
->app_data
, M_TEMP
);
342 if (fd_cb
->original_remote_endpoint
!= NULL
) {
343 FREE(fd_cb
->original_remote_endpoint
, M_SONAME
);
345 zfree(flow_divert_pcb_zone
, fd_cb
);
349 flow_divert_pcb_remove(struct flow_divert_pcb
*fd_cb
)
351 if (fd_cb
->group
!= NULL
) {
352 struct flow_divert_group
*group
= fd_cb
->group
;
353 lck_rw_lock_exclusive(&group
->lck
);
354 FDLOG(LOG_INFO
, fd_cb
, "Removing from group %d, ref count = %d", group
->ctl_unit
, fd_cb
->ref_count
);
355 RB_REMOVE(fd_pcb_tree
, &group
->pcb_tree
, fd_cb
);
357 FDRELEASE(fd_cb
); /* Release the group's reference */
358 lck_rw_done(&group
->lck
);
363 flow_divert_packet_init(struct flow_divert_pcb
*fd_cb
, uint8_t packet_type
, mbuf_t
*packet
)
365 struct flow_divert_packet_header hdr
;
368 error
= mbuf_gethdr(MBUF_DONTWAIT
, MBUF_TYPE_HEADER
, packet
);
370 FDLOG(LOG_ERR
, fd_cb
, "failed to allocate the header mbuf: %d", error
);
374 hdr
.packet_type
= packet_type
;
375 hdr
.conn_id
= htonl(fd_cb
->hash
);
377 /* Lay down the header */
378 error
= mbuf_copyback(*packet
, 0, sizeof(hdr
), &hdr
, MBUF_DONTWAIT
);
380 FDLOG(LOG_ERR
, fd_cb
, "mbuf_copyback(hdr) failed: %d", error
);
390 flow_divert_packet_append_tlv(mbuf_t packet
, uint8_t type
, uint32_t length
, const void *value
)
392 uint32_t net_length
= htonl(length
);
395 error
= mbuf_copyback(packet
, mbuf_pkthdr_len(packet
), sizeof(type
), &type
, MBUF_DONTWAIT
);
397 FDLOG(LOG_ERR
, &nil_pcb
, "failed to append the type (%d)", type
);
401 error
= mbuf_copyback(packet
, mbuf_pkthdr_len(packet
), sizeof(net_length
), &net_length
, MBUF_DONTWAIT
);
403 FDLOG(LOG_ERR
, &nil_pcb
, "failed to append the length (%u)", length
);
407 error
= mbuf_copyback(packet
, mbuf_pkthdr_len(packet
), length
, value
, MBUF_DONTWAIT
);
409 FDLOG0(LOG_ERR
, &nil_pcb
, "failed to append the value");
417 flow_divert_packet_find_tlv(mbuf_t packet
, int offset
, uint8_t type
, int *err
, int next
)
419 size_t cursor
= offset
;
421 uint32_t curr_length
;
428 error
= mbuf_copydata(packet
, cursor
, sizeof(curr_type
), &curr_type
);
435 curr_type
= FLOW_DIVERT_TLV_NIL
;
438 if (curr_type
!= type
) {
439 cursor
+= sizeof(curr_type
);
440 error
= mbuf_copydata(packet
, cursor
, sizeof(curr_length
), &curr_length
);
446 cursor
+= (sizeof(curr_length
) + ntohl(curr_length
));
448 } while (curr_type
!= type
);
454 flow_divert_packet_get_tlv(mbuf_t packet
, int offset
, uint8_t type
, size_t buff_len
, void *buff
, uint32_t *val_size
)
460 tlv_offset
= flow_divert_packet_find_tlv(packet
, offset
, type
, &error
, 0);
461 if (tlv_offset
< 0) {
465 error
= mbuf_copydata(packet
, tlv_offset
+ sizeof(type
), sizeof(length
), &length
);
470 length
= ntohl(length
);
472 uint32_t data_offset
= tlv_offset
+ sizeof(type
) + sizeof(length
);
474 if (length
> (mbuf_pkthdr_len(packet
) - data_offset
)) {
475 FDLOG(LOG_ERR
, &nil_pcb
, "Length of %u TLV (%u) is larger than remaining packet data (%lu)", type
, length
, (mbuf_pkthdr_len(packet
) - data_offset
));
479 if (val_size
!= NULL
) {
483 if (buff
!= NULL
&& buff_len
> 0) {
484 memset(buff
, 0, buff_len
);
485 size_t to_copy
= (length
< buff_len
) ? length
: buff_len
;
486 error
= mbuf_copydata(packet
, data_offset
, to_copy
, buff
);
496 flow_divert_packet_compute_hmac(mbuf_t packet
, struct flow_divert_group
*group
, uint8_t *hmac
)
498 mbuf_t curr_mbuf
= packet
;
500 if (g_crypto_funcs
== NULL
|| group
->token_key
== NULL
) {
504 cchmac_di_decl(g_crypto_funcs
->ccsha1_di
, hmac_ctx
);
505 g_crypto_funcs
->cchmac_init_fn(g_crypto_funcs
->ccsha1_di
, hmac_ctx
, group
->token_key_size
, group
->token_key
);
507 while (curr_mbuf
!= NULL
) {
508 g_crypto_funcs
->cchmac_update_fn(g_crypto_funcs
->ccsha1_di
, hmac_ctx
, mbuf_len(curr_mbuf
), mbuf_data(curr_mbuf
));
509 curr_mbuf
= mbuf_next(curr_mbuf
);
512 g_crypto_funcs
->cchmac_final_fn(g_crypto_funcs
->ccsha1_di
, hmac_ctx
, hmac
);
518 flow_divert_packet_verify_hmac(mbuf_t packet
, uint32_t ctl_unit
)
521 struct flow_divert_group
*group
= NULL
;
523 uint8_t packet_hmac
[SHA_DIGEST_LENGTH
];
524 uint8_t computed_hmac
[SHA_DIGEST_LENGTH
];
527 lck_rw_lock_shared(&g_flow_divert_group_lck
);
529 if (g_flow_divert_groups
!= NULL
&& g_active_group_count
> 0) {
530 group
= g_flow_divert_groups
[ctl_unit
];
534 lck_rw_done(&g_flow_divert_group_lck
);
538 lck_rw_lock_shared(&group
->lck
);
540 if (group
->token_key
== NULL
) {
545 hmac_offset
= flow_divert_packet_find_tlv(packet
, 0, FLOW_DIVERT_TLV_HMAC
, &error
, 0);
546 if (hmac_offset
< 0) {
550 error
= flow_divert_packet_get_tlv(packet
, hmac_offset
, FLOW_DIVERT_TLV_HMAC
, sizeof(packet_hmac
), packet_hmac
, NULL
);
555 /* Chop off the HMAC TLV */
556 error
= mbuf_split(packet
, hmac_offset
, MBUF_WAITOK
, &tail
);
563 error
= flow_divert_packet_compute_hmac(packet
, group
, computed_hmac
);
568 if (cc_cmp_safe(sizeof(packet_hmac
), packet_hmac
, computed_hmac
)) {
569 FDLOG0(LOG_WARNING
, &nil_pcb
, "HMAC in token does not match computed HMAC");
575 lck_rw_done(&group
->lck
);
576 lck_rw_done(&g_flow_divert_group_lck
);
581 flow_divert_add_data_statistics(struct flow_divert_pcb
*fd_cb
, size_t data_len
, Boolean send
)
583 struct inpcb
*inp
= NULL
;
584 struct ifnet
*ifp
= NULL
;
585 Boolean cell
= FALSE
;
586 Boolean wifi
= FALSE
;
587 Boolean wired
= FALSE
;
589 inp
= sotoinpcb(fd_cb
->so
);
594 if (inp
->inp_vflag
& INP_IPV4
) {
595 ifp
= inp
->inp_last_outifp
;
596 } else if (inp
->inp_vflag
& INP_IPV6
) {
597 ifp
= inp
->in6p_last_outifp
;
600 cell
= IFNET_IS_CELLULAR(ifp
);
601 wifi
= (!cell
&& IFNET_IS_WIFI(ifp
));
602 wired
= (!wifi
&& IFNET_IS_WIRED(ifp
));
606 INP_ADD_STAT(inp
, cell
, wifi
, wired
, txpackets
, 1);
607 INP_ADD_STAT(inp
, cell
, wifi
, wired
, txbytes
, data_len
);
609 INP_ADD_STAT(inp
, cell
, wifi
, wired
, rxpackets
, 1);
610 INP_ADD_STAT(inp
, cell
, wifi
, wired
, rxbytes
, data_len
);
612 inp_set_activity_bitmap(inp
);
616 flow_divert_check_no_cellular(struct flow_divert_pcb
*fd_cb
)
618 struct inpcb
*inp
= sotoinpcb(fd_cb
->so
);
619 if (INP_NO_CELLULAR(inp
)) {
620 struct ifnet
*ifp
= NULL
;
621 if (inp
->inp_vflag
& INP_IPV4
) {
622 ifp
= inp
->inp_last_outifp
;
623 } else if (inp
->inp_vflag
& INP_IPV6
) {
624 ifp
= inp
->in6p_last_outifp
;
626 if (ifp
!= NULL
&& IFNET_IS_CELLULAR(ifp
)) {
627 FDLOG0(LOG_ERR
, fd_cb
, "Cellular is denied");
635 flow_divert_check_no_expensive(struct flow_divert_pcb
*fd_cb
)
637 struct inpcb
*inp
= sotoinpcb(fd_cb
->so
);
638 if (INP_NO_EXPENSIVE(inp
)) {
639 struct ifnet
*ifp
= NULL
;
640 if (inp
->inp_vflag
& INP_IPV4
) {
641 ifp
= inp
->inp_last_outifp
;
642 } else if (inp
->inp_vflag
& INP_IPV6
) {
643 ifp
= inp
->in6p_last_outifp
;
645 if (ifp
!= NULL
&& IFNET_IS_EXPENSIVE(ifp
)) {
646 FDLOG0(LOG_ERR
, fd_cb
, "Expensive is denied");
654 flow_divert_check_no_constrained(struct flow_divert_pcb
*fd_cb
)
656 struct inpcb
*inp
= sotoinpcb(fd_cb
->so
);
657 if (INP_NO_CONSTRAINED(inp
)) {
658 struct ifnet
*ifp
= NULL
;
659 if (inp
->inp_vflag
& INP_IPV4
) {
660 ifp
= inp
->inp_last_outifp
;
661 } else if (inp
->inp_vflag
& INP_IPV6
) {
662 ifp
= inp
->in6p_last_outifp
;
664 if (ifp
!= NULL
&& IFNET_IS_CONSTRAINED(ifp
)) {
665 FDLOG0(LOG_ERR
, fd_cb
, "Constrained is denied");
673 flow_divert_update_closed_state(struct flow_divert_pcb
*fd_cb
, int how
, Boolean tunnel
)
675 if (how
!= SHUT_RD
) {
676 fd_cb
->flags
|= FLOW_DIVERT_WRITE_CLOSED
;
677 if (tunnel
|| !(fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
)) {
678 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_WR_CLOSED
;
679 /* If the tunnel is not accepting writes any more, then flush the send buffer */
680 sbflush(&fd_cb
->so
->so_snd
);
683 if (how
!= SHUT_WR
) {
684 fd_cb
->flags
|= FLOW_DIVERT_READ_CLOSED
;
685 if (tunnel
|| !(fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
)) {
686 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_RD_CLOSED
;
692 trie_node_alloc(struct flow_divert_trie
*trie
)
694 if (trie
->nodes_free_next
< trie
->nodes_count
) {
695 uint16_t node_idx
= trie
->nodes_free_next
++;
696 TRIE_NODE(trie
, node_idx
).child_map
= NULL_TRIE_IDX
;
699 return NULL_TRIE_IDX
;
704 trie_child_map_alloc(struct flow_divert_trie
*trie
)
706 if (trie
->child_maps_free_next
< trie
->child_maps_count
) {
707 return trie
->child_maps_free_next
++;
709 return NULL_TRIE_IDX
;
714 trie_bytes_move(struct flow_divert_trie
*trie
, uint16_t bytes_idx
, size_t bytes_size
)
716 uint16_t start
= trie
->bytes_free_next
;
717 if (start
+ bytes_size
<= trie
->bytes_count
) {
718 if (start
!= bytes_idx
) {
719 memmove(&TRIE_BYTE(trie
, start
), &TRIE_BYTE(trie
, bytes_idx
), bytes_size
);
721 trie
->bytes_free_next
+= bytes_size
;
724 return NULL_TRIE_IDX
;
729 flow_divert_trie_insert(struct flow_divert_trie
*trie
, uint16_t string_start
, size_t string_len
)
731 uint16_t current
= trie
->root
;
732 uint16_t child
= trie
->root
;
733 uint16_t string_end
= string_start
+ (uint16_t)string_len
;
734 uint16_t string_idx
= string_start
;
735 uint16_t string_remainder
= (uint16_t)string_len
;
737 while (child
!= NULL_TRIE_IDX
) {
738 uint16_t parent
= current
;
740 uint16_t current_end
;
743 child
= NULL_TRIE_IDX
;
745 current_end
= TRIE_NODE(trie
, current
).start
+ TRIE_NODE(trie
, current
).length
;
747 for (node_idx
= TRIE_NODE(trie
, current
).start
;
748 node_idx
< current_end
&&
749 string_idx
< string_end
&&
750 TRIE_BYTE(trie
, node_idx
) == TRIE_BYTE(trie
, string_idx
);
751 node_idx
++, string_idx
++) {
755 string_remainder
= string_end
- string_idx
;
757 if (node_idx
< (TRIE_NODE(trie
, current
).start
+ TRIE_NODE(trie
, current
).length
)) {
759 * We did not reach the end of the current node's string.
760 * We need to split the current node into two:
761 * 1. A new node that contains the prefix of the node that matches
762 * the prefix of the string being inserted.
763 * 2. The current node modified to point to the remainder
764 * of the current node's string.
766 uint16_t prefix
= trie_node_alloc(trie
);
767 if (prefix
== NULL_TRIE_IDX
) {
768 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of trie nodes while splitting an existing node");
769 return NULL_TRIE_IDX
;
773 * Prefix points to the portion of the current nodes's string that has matched
774 * the input string thus far.
776 TRIE_NODE(trie
, prefix
).start
= TRIE_NODE(trie
, current
).start
;
777 TRIE_NODE(trie
, prefix
).length
= (node_idx
- TRIE_NODE(trie
, current
).start
);
780 * Prefix has the current node as the child corresponding to the first byte
783 TRIE_NODE(trie
, prefix
).child_map
= trie_child_map_alloc(trie
);
784 if (TRIE_NODE(trie
, prefix
).child_map
== NULL_TRIE_IDX
) {
785 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of child maps while splitting an existing node");
786 return NULL_TRIE_IDX
;
788 TRIE_CHILD(trie
, prefix
, TRIE_BYTE(trie
, node_idx
)) = current
;
790 /* Parent has the prefix as the child correspoding to the first byte in the prefix */
791 TRIE_CHILD(trie
, parent
, TRIE_BYTE(trie
, TRIE_NODE(trie
, prefix
).start
)) = prefix
;
793 /* Current node is adjusted to point to the remainder */
794 TRIE_NODE(trie
, current
).start
= node_idx
;
795 TRIE_NODE(trie
, current
).length
-= TRIE_NODE(trie
, prefix
).length
;
797 /* We want to insert the new leaf (if any) as a child of the prefix */
801 if (string_remainder
> 0) {
803 * We still have bytes in the string that have not been matched yet.
804 * If the current node has children, iterate to the child corresponding
805 * to the next byte in the string.
807 if (TRIE_NODE(trie
, current
).child_map
!= NULL_TRIE_IDX
) {
808 child
= TRIE_CHILD(trie
, current
, TRIE_BYTE(trie
, string_idx
));
811 } /* while (child != NULL_TRIE_IDX) */
813 if (string_remainder
> 0) {
814 /* Add a new leaf containing the remainder of the string */
815 uint16_t leaf
= trie_node_alloc(trie
);
816 if (leaf
== NULL_TRIE_IDX
) {
817 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of trie nodes while inserting a new leaf");
818 return NULL_TRIE_IDX
;
821 TRIE_NODE(trie
, leaf
).start
= trie_bytes_move(trie
, string_idx
, string_remainder
);
822 if (TRIE_NODE(trie
, leaf
).start
== NULL_TRIE_IDX
) {
823 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of bytes while inserting a new leaf");
824 return NULL_TRIE_IDX
;
826 TRIE_NODE(trie
, leaf
).length
= string_remainder
;
828 /* Set the new leaf as the child of the current node */
829 if (TRIE_NODE(trie
, current
).child_map
== NULL_TRIE_IDX
) {
830 TRIE_NODE(trie
, current
).child_map
= trie_child_map_alloc(trie
);
831 if (TRIE_NODE(trie
, current
).child_map
== NULL_TRIE_IDX
) {
832 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of child maps while inserting a new leaf");
833 return NULL_TRIE_IDX
;
836 TRIE_CHILD(trie
, current
, TRIE_BYTE(trie
, TRIE_NODE(trie
, leaf
).start
)) = leaf
;
838 } /* else duplicate or this string is a prefix of one of the existing strings */
843 #define APPLE_WEBCLIP_ID_PREFIX "com.apple.webapp"
845 flow_divert_trie_search(struct flow_divert_trie
*trie
, const uint8_t *string_bytes
)
847 uint16_t current
= trie
->root
;
848 uint16_t string_idx
= 0;
850 while (current
!= NULL_TRIE_IDX
) {
851 uint16_t next
= NULL_TRIE_IDX
;
852 uint16_t node_end
= TRIE_NODE(trie
, current
).start
+ TRIE_NODE(trie
, current
).length
;
855 for (node_idx
= TRIE_NODE(trie
, current
).start
;
856 node_idx
< node_end
&& string_bytes
[string_idx
] != '\0' && string_bytes
[string_idx
] == TRIE_BYTE(trie
, node_idx
);
857 node_idx
++, string_idx
++) {
861 if (node_idx
== node_end
) {
862 if (string_bytes
[string_idx
] == '\0') {
863 return current
; /* Got an exact match */
864 } else if (string_idx
== strlen(APPLE_WEBCLIP_ID_PREFIX
) &&
865 0 == strncmp((const char *)string_bytes
, APPLE_WEBCLIP_ID_PREFIX
, string_idx
)) {
866 return current
; /* Got an apple webclip id prefix match */
867 } else if (TRIE_NODE(trie
, current
).child_map
!= NULL_TRIE_IDX
) {
868 next
= TRIE_CHILD(trie
, current
, string_bytes
[string_idx
]);
874 return NULL_TRIE_IDX
;
877 struct uuid_search_info
{
879 char *found_signing_id
;
880 boolean_t found_multiple_signing_ids
;
885 flow_divert_find_proc_by_uuid_callout(proc_t p
, void *arg
)
887 struct uuid_search_info
*info
= (struct uuid_search_info
*)arg
;
888 int result
= PROC_RETURNED_DONE
; /* By default, we didn't find the process */
890 if (info
->found_signing_id
!= NULL
) {
891 if (!info
->found_multiple_signing_ids
) {
892 /* All processes that were found had the same signing identifier, so just claim this first one and be done. */
893 info
->found_proc
= p
;
894 result
= PROC_CLAIMED_DONE
;
896 uuid_string_t uuid_str
;
897 uuid_unparse(info
->target_uuid
, uuid_str
);
898 FDLOG(LOG_WARNING
, &nil_pcb
, "Found multiple processes with UUID %s with different signing identifiers", uuid_str
);
900 FREE(info
->found_signing_id
, M_TEMP
);
901 info
->found_signing_id
= NULL
;
904 if (result
== PROC_RETURNED_DONE
) {
905 uuid_string_t uuid_str
;
906 uuid_unparse(info
->target_uuid
, uuid_str
);
907 FDLOG(LOG_WARNING
, &nil_pcb
, "Failed to find a process with UUID %s", uuid_str
);
914 flow_divert_find_proc_by_uuid_filter(proc_t p
, void *arg
)
916 struct uuid_search_info
*info
= (struct uuid_search_info
*)arg
;
919 if (info
->found_multiple_signing_ids
) {
923 include
= (uuid_compare(p
->p_uuid
, info
->target_uuid
) == 0);
925 const char *signing_id
= cs_identity_get(p
);
926 if (signing_id
!= NULL
) {
927 FDLOG(LOG_INFO
, &nil_pcb
, "Found process %d with signing identifier %s", p
->p_pid
, signing_id
);
928 size_t signing_id_size
= strlen(signing_id
) + 1;
929 if (info
->found_signing_id
== NULL
) {
930 MALLOC(info
->found_signing_id
, char *, signing_id_size
, M_TEMP
, M_WAITOK
);
931 memcpy(info
->found_signing_id
, signing_id
, signing_id_size
);
932 } else if (memcmp(signing_id
, info
->found_signing_id
, signing_id_size
)) {
933 info
->found_multiple_signing_ids
= TRUE
;
936 info
->found_multiple_signing_ids
= TRUE
;
938 include
= !info
->found_multiple_signing_ids
;
945 flow_divert_find_proc_by_uuid(uuid_t uuid
)
947 struct uuid_search_info info
;
949 if (LOG_INFO
<= nil_pcb
.log_level
) {
950 uuid_string_t uuid_str
;
951 uuid_unparse(uuid
, uuid_str
);
952 FDLOG(LOG_INFO
, &nil_pcb
, "Looking for process with UUID %s", uuid_str
);
955 memset(&info
, 0, sizeof(info
));
956 info
.found_proc
= PROC_NULL
;
957 uuid_copy(info
.target_uuid
, uuid
);
959 proc_iterate(PROC_ALLPROCLIST
, flow_divert_find_proc_by_uuid_callout
, &info
, flow_divert_find_proc_by_uuid_filter
, &info
);
961 return info
.found_proc
;
965 flow_divert_add_proc_info(struct flow_divert_pcb
*fd_cb
, proc_t proc
, const char *signing_id
, mbuf_t connect_packet
, bool is_effective
)
968 uint8_t *cdhash
= NULL
;
969 audit_token_t audit_token
= {};
970 const char *proc_cs_id
= signing_id
;
974 if (proc_cs_id
== NULL
) {
975 if (proc
->p_csflags
& (CS_VALID
| CS_DEBUGGED
)) {
976 proc_cs_id
= cs_identity_get(proc
);
978 FDLOG0(LOG_ERR
, fd_cb
, "Signature of proc is invalid");
983 lck_rw_lock_shared(&fd_cb
->group
->lck
);
984 if (!(fd_cb
->group
->flags
& FLOW_DIVERT_GROUP_FLAG_NO_APP_MAP
)) {
985 if (proc_cs_id
!= NULL
) {
986 uint16_t result
= flow_divert_trie_search(&fd_cb
->group
->signing_id_trie
, (const uint8_t *)proc_cs_id
);
987 if (result
== NULL_TRIE_IDX
) {
988 FDLOG(LOG_WARNING
, fd_cb
, "%s did not match", proc_cs_id
);
991 FDLOG(LOG_INFO
, fd_cb
, "%s matched", proc_cs_id
);
997 lck_rw_done(&fd_cb
->group
->lck
);
1005 * If signing_id is not NULL then it came from the flow divert token and will be added
1006 * as part of the token, so there is no need to add it here.
1008 if (signing_id
== NULL
&& proc_cs_id
!= NULL
) {
1009 error
= flow_divert_packet_append_tlv(connect_packet
,
1010 (is_effective
? FLOW_DIVERT_TLV_SIGNING_ID
: FLOW_DIVERT_TLV_APP_REAL_SIGNING_ID
),
1011 (uint32_t)strlen(proc_cs_id
),
1014 FDLOG(LOG_ERR
, fd_cb
, "failed to append the signing ID: %d", error
);
1019 cdhash
= cs_get_cdhash(proc
);
1020 if (cdhash
!= NULL
) {
1021 error
= flow_divert_packet_append_tlv(connect_packet
,
1022 (is_effective
? FLOW_DIVERT_TLV_CDHASH
: FLOW_DIVERT_TLV_APP_REAL_CDHASH
),
1026 FDLOG(LOG_ERR
, fd_cb
, "failed to append the cdhash: %d", error
);
1030 FDLOG0(LOG_ERR
, fd_cb
, "failed to get the cdhash");
1033 task_t task
= proc_task(proc
);
1034 if (task
!= TASK_NULL
) {
1035 mach_msg_type_number_t count
= TASK_AUDIT_TOKEN_COUNT
;
1036 kern_return_t rc
= task_info(task
, TASK_AUDIT_TOKEN
, (task_info_t
)&audit_token
, &count
);
1037 if (rc
== KERN_SUCCESS
) {
1038 int append_error
= flow_divert_packet_append_tlv(connect_packet
,
1039 (is_effective
? FLOW_DIVERT_TLV_APP_AUDIT_TOKEN
: FLOW_DIVERT_TLV_APP_REAL_AUDIT_TOKEN
),
1040 sizeof(audit_token_t
),
1043 FDLOG(LOG_ERR
, fd_cb
, "failed to append app audit token: %d", append_error
);
1055 flow_divert_add_all_proc_info(struct flow_divert_pcb
*fd_cb
, struct socket
*so
, proc_t proc
, const char *signing_id
, mbuf_t connect_packet
)
1058 proc_t effective_proc
= PROC_NULL
;
1059 proc_t responsible_proc
= PROC_NULL
;
1060 proc_t real_proc
= proc_find(so
->last_pid
);
1061 bool release_real_proc
= true;
1063 proc_t src_proc
= PROC_NULL
;
1064 proc_t real_src_proc
= PROC_NULL
;
1066 if (real_proc
== PROC_NULL
) {
1067 FDLOG(LOG_ERR
, fd_cb
, "failed to find the real proc record for %d", so
->last_pid
);
1068 release_real_proc
= false;
1070 if (real_proc
== PROC_NULL
) {
1071 real_proc
= current_proc();
1075 if (so
->so_flags
& SOF_DELEGATED
) {
1076 if (real_proc
->p_pid
!= so
->e_pid
) {
1077 effective_proc
= proc_find(so
->e_pid
);
1078 } else if (uuid_compare(real_proc
->p_uuid
, so
->e_uuid
)) {
1079 effective_proc
= flow_divert_find_proc_by_uuid(so
->e_uuid
);
1083 #if defined(XNU_TARGET_OS_OSX)
1084 lck_rw_lock_shared(&fd_cb
->group
->lck
);
1085 if (!(fd_cb
->group
->flags
& FLOW_DIVERT_GROUP_FLAG_NO_APP_MAP
)) {
1086 if (so
->so_rpid
> 0) {
1087 responsible_proc
= proc_find(so
->so_rpid
);
1090 lck_rw_done(&fd_cb
->group
->lck
);
1093 real_src_proc
= real_proc
;
1095 if (responsible_proc
!= PROC_NULL
) {
1096 src_proc
= responsible_proc
;
1097 if (effective_proc
!= NULL
) {
1098 real_src_proc
= effective_proc
;
1100 } else if (effective_proc
!= PROC_NULL
) {
1101 src_proc
= effective_proc
;
1103 src_proc
= real_proc
;
1106 error
= flow_divert_add_proc_info(fd_cb
, src_proc
, signing_id
, connect_packet
, true);
1111 if (real_src_proc
!= NULL
&& real_src_proc
!= src_proc
) {
1112 error
= flow_divert_add_proc_info(fd_cb
, real_src_proc
, NULL
, connect_packet
, false);
1119 if (responsible_proc
!= PROC_NULL
) {
1120 proc_rele(responsible_proc
);
1123 if (effective_proc
!= PROC_NULL
) {
1124 proc_rele(effective_proc
);
1127 if (real_proc
!= PROC_NULL
&& release_real_proc
) {
1128 proc_rele(real_proc
);
1135 flow_divert_send_packet(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, Boolean enqueue
)
1139 if (fd_cb
->group
== NULL
) {
1140 fd_cb
->so
->so_error
= ECONNABORTED
;
1141 flow_divert_disconnect_socket(fd_cb
->so
);
1142 return ECONNABORTED
;
1145 lck_rw_lock_shared(&fd_cb
->group
->lck
);
1147 if (MBUFQ_EMPTY(&fd_cb
->group
->send_queue
)) {
1148 error
= ctl_enqueuembuf(g_flow_divert_kctl_ref
, fd_cb
->group
->ctl_unit
, packet
, CTL_DATA_EOR
);
1153 if (error
== ENOBUFS
) {
1155 if (!lck_rw_lock_shared_to_exclusive(&fd_cb
->group
->lck
)) {
1156 lck_rw_lock_exclusive(&fd_cb
->group
->lck
);
1158 MBUFQ_ENQUEUE(&fd_cb
->group
->send_queue
, packet
);
1161 OSTestAndSet(GROUP_BIT_CTL_ENQUEUE_BLOCKED
, &fd_cb
->group
->atomic_bits
);
1164 lck_rw_done(&fd_cb
->group
->lck
);
1170 flow_divert_create_connect_packet(struct flow_divert_pcb
*fd_cb
, struct sockaddr
*to
, struct socket
*so
, proc_t p
, mbuf_t
*out_connect_packet
)
1174 char *signing_id
= NULL
;
1175 mbuf_t connect_packet
= NULL
;
1176 cfil_sock_id_t cfil_sock_id
= CFIL_SOCK_ID_NONE
;
1177 const void *cfil_id
= NULL
;
1178 size_t cfil_id_size
= 0;
1179 struct inpcb
*inp
= sotoinpcb(so
);
1180 struct ifnet
*ifp
= NULL
;
1183 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_CONNECT
, &connect_packet
);
1188 if (fd_cb
->connect_token
!= NULL
&& (fd_cb
->flags
& FLOW_DIVERT_HAS_HMAC
)) {
1189 uint32_t sid_size
= 0;
1190 int find_error
= flow_divert_packet_get_tlv(fd_cb
->connect_token
, 0, FLOW_DIVERT_TLV_SIGNING_ID
, 0, NULL
, &sid_size
);
1191 if (find_error
== 0 && sid_size
> 0) {
1192 MALLOC(signing_id
, char *, sid_size
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
1193 if (signing_id
!= NULL
) {
1194 flow_divert_packet_get_tlv(fd_cb
->connect_token
, 0, FLOW_DIVERT_TLV_SIGNING_ID
, sid_size
, signing_id
, NULL
);
1195 FDLOG(LOG_INFO
, fd_cb
, "Got %s from token", signing_id
);
1200 socket_unlock(so
, 0);
1202 error
= flow_divert_add_all_proc_info(fd_cb
, so
, p
, signing_id
, connect_packet
);
1206 if (signing_id
!= NULL
) {
1207 FREE(signing_id
, M_TEMP
);
1211 FDLOG(LOG_ERR
, fd_cb
, "Failed to add source proc info: %d", error
);
1215 error
= flow_divert_packet_append_tlv(connect_packet
,
1216 FLOW_DIVERT_TLV_TRAFFIC_CLASS
,
1217 sizeof(fd_cb
->so
->so_traffic_class
),
1218 &fd_cb
->so
->so_traffic_class
);
1223 if (SOCK_TYPE(fd_cb
->so
) == SOCK_STREAM
) {
1224 flow_type
= FLOW_DIVERT_FLOW_TYPE_TCP
;
1225 } else if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
1226 flow_type
= FLOW_DIVERT_FLOW_TYPE_UDP
;
1231 error
= flow_divert_packet_append_tlv(connect_packet
,
1232 FLOW_DIVERT_TLV_FLOW_TYPE
,
1240 if (fd_cb
->connect_token
!= NULL
) {
1241 unsigned int token_len
= m_length(fd_cb
->connect_token
);
1242 mbuf_concatenate(connect_packet
, fd_cb
->connect_token
);
1243 mbuf_pkthdr_adjustlen(connect_packet
, token_len
);
1244 fd_cb
->connect_token
= NULL
;
1246 error
= flow_divert_append_target_endpoint_tlv(connect_packet
, to
);
1252 if (fd_cb
->local_endpoint
.sa
.sa_family
== AF_INET
|| fd_cb
->local_endpoint
.sa
.sa_family
== AF_INET6
) {
1253 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_LOCAL_ADDR
, fd_cb
->local_endpoint
.sa
.sa_len
, &(fd_cb
->local_endpoint
.sa
));
1259 if (inp
->inp_vflag
& INP_IPV4
) {
1260 ifp
= inp
->inp_last_outifp
;
1261 } else if (inp
->inp_vflag
& INP_IPV6
) {
1262 ifp
= inp
->in6p_last_outifp
;
1265 uint32_t flow_if_index
= ifp
->if_index
;
1266 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_OUT_IF_INDEX
,
1267 sizeof(flow_if_index
), &flow_if_index
);
1273 if (so
->so_flags1
& SOF1_DATA_IDEMPOTENT
) {
1274 flags
|= FLOW_DIVERT_TOKEN_FLAG_TFO
;
1277 if ((inp
->inp_flags
& INP_BOUND_IF
) ||
1278 ((inp
->inp_vflag
& INP_IPV6
) && !IN6_IS_ADDR_UNSPECIFIED(&inp
->in6p_laddr
)) ||
1279 ((inp
->inp_vflag
& INP_IPV4
) && inp
->inp_laddr
.s_addr
!= INADDR_ANY
)) {
1280 flags
|= FLOW_DIVERT_TOKEN_FLAG_BOUND
;
1284 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_FLAGS
, sizeof(flags
), &flags
);
1290 if (SOCK_TYPE(so
) == SOCK_DGRAM
) {
1291 cfil_sock_id
= cfil_sock_id_from_datagram_socket(so
, NULL
, to
);
1293 cfil_sock_id
= cfil_sock_id_from_socket(so
);
1296 if (cfil_sock_id
!= CFIL_SOCK_ID_NONE
) {
1297 cfil_id
= &cfil_sock_id
;
1298 cfil_id_size
= sizeof(cfil_sock_id
);
1299 } else if (so
->so_flags1
& SOF1_CONTENT_FILTER_SKIP
) {
1300 cfil_id
= &inp
->necp_client_uuid
;
1301 cfil_id_size
= sizeof(inp
->necp_client_uuid
);
1304 if (cfil_id
!= NULL
&& cfil_id_size
> 0 && cfil_id_size
<= sizeof(uuid_t
)) {
1305 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_CFIL_ID
, (uint32_t)cfil_id_size
, cfil_id
);
1313 *out_connect_packet
= connect_packet
;
1314 } else if (connect_packet
!= NULL
) {
1315 mbuf_freem(connect_packet
);
1322 flow_divert_send_connect_packet(struct flow_divert_pcb
*fd_cb
)
1325 mbuf_t connect_packet
= fd_cb
->connect_packet
;
1326 mbuf_t saved_connect_packet
= NULL
;
1328 if (connect_packet
!= NULL
) {
1329 error
= mbuf_copym(connect_packet
, 0, mbuf_pkthdr_len(connect_packet
), MBUF_DONTWAIT
, &saved_connect_packet
);
1331 FDLOG0(LOG_ERR
, fd_cb
, "Failed to copy the connect packet");
1335 error
= flow_divert_send_packet(fd_cb
, connect_packet
, TRUE
);
1340 fd_cb
->connect_packet
= saved_connect_packet
;
1341 saved_connect_packet
= NULL
;
1346 if (saved_connect_packet
!= NULL
) {
1347 mbuf_freem(saved_connect_packet
);
1354 flow_divert_send_connect_result(struct flow_divert_pcb
*fd_cb
)
1357 mbuf_t packet
= NULL
;
1358 int rbuff_space
= 0;
1360 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_CONNECT_RESULT
, &packet
);
1362 FDLOG(LOG_ERR
, fd_cb
, "failed to create a connect result packet: %d", error
);
1366 rbuff_space
= fd_cb
->so
->so_rcv
.sb_hiwat
;
1367 if (rbuff_space
< 0) {
1370 rbuff_space
= htonl(rbuff_space
);
1371 error
= flow_divert_packet_append_tlv(packet
,
1372 FLOW_DIVERT_TLV_SPACE_AVAILABLE
,
1373 sizeof(rbuff_space
),
1379 if (fd_cb
->local_endpoint
.sa
.sa_family
== AF_INET
|| fd_cb
->local_endpoint
.sa
.sa_family
== AF_INET6
) {
1380 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_LOCAL_ADDR
, fd_cb
->local_endpoint
.sa
.sa_len
, &(fd_cb
->local_endpoint
.sa
));
1386 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1392 if (error
&& packet
!= NULL
) {
1400 flow_divert_send_close(struct flow_divert_pcb
*fd_cb
, int how
)
1403 mbuf_t packet
= NULL
;
1406 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_CLOSE
, &packet
);
1408 FDLOG(LOG_ERR
, fd_cb
, "failed to create a close packet: %d", error
);
1412 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_ERROR_CODE
, sizeof(zero
), &zero
);
1414 FDLOG(LOG_ERR
, fd_cb
, "failed to add the error code TLV: %d", error
);
1419 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_HOW
, sizeof(how
), &how
);
1421 FDLOG(LOG_ERR
, fd_cb
, "failed to add the how flag: %d", error
);
1425 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1431 if (error
&& packet
!= NULL
) {
1439 flow_divert_tunnel_how_closed(struct flow_divert_pcb
*fd_cb
)
1441 if ((fd_cb
->flags
& (FLOW_DIVERT_TUNNEL_RD_CLOSED
| FLOW_DIVERT_TUNNEL_WR_CLOSED
)) ==
1442 (FLOW_DIVERT_TUNNEL_RD_CLOSED
| FLOW_DIVERT_TUNNEL_WR_CLOSED
)) {
1444 } else if (fd_cb
->flags
& FLOW_DIVERT_TUNNEL_RD_CLOSED
) {
1446 } else if (fd_cb
->flags
& FLOW_DIVERT_TUNNEL_WR_CLOSED
) {
1454 * Determine what close messages if any need to be sent to the tunnel. Returns TRUE if the tunnel is closed for both reads and
1455 * writes. Returns FALSE otherwise.
1458 flow_divert_send_close_if_needed(struct flow_divert_pcb
*fd_cb
)
1462 /* Do not send any close messages if there is still data in the send buffer */
1463 if (fd_cb
->so
->so_snd
.sb_cc
== 0) {
1464 if ((fd_cb
->flags
& (FLOW_DIVERT_READ_CLOSED
| FLOW_DIVERT_TUNNEL_RD_CLOSED
)) == FLOW_DIVERT_READ_CLOSED
) {
1465 /* Socket closed reads, but tunnel did not. Tell tunnel to close reads */
1468 if ((fd_cb
->flags
& (FLOW_DIVERT_WRITE_CLOSED
| FLOW_DIVERT_TUNNEL_WR_CLOSED
)) == FLOW_DIVERT_WRITE_CLOSED
) {
1469 /* Socket closed writes, but tunnel did not. Tell tunnel to close writes */
1470 if (how
== SHUT_RD
) {
1479 FDLOG(LOG_INFO
, fd_cb
, "sending close, how = %d", how
);
1480 if (flow_divert_send_close(fd_cb
, how
) != ENOBUFS
) {
1481 /* Successfully sent the close packet. Record the ways in which the tunnel has been closed */
1482 if (how
!= SHUT_RD
) {
1483 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_WR_CLOSED
;
1485 if (how
!= SHUT_WR
) {
1486 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_RD_CLOSED
;
1491 if (flow_divert_tunnel_how_closed(fd_cb
) == SHUT_RDWR
) {
1492 flow_divert_disconnect_socket(fd_cb
->so
);
1497 flow_divert_send_data_packet(struct flow_divert_pcb
*fd_cb
, mbuf_t data
, size_t data_len
, struct sockaddr
*toaddr
, Boolean force
)
1499 mbuf_t packet
= NULL
;
1503 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_DATA
, &packet
);
1504 if (error
|| packet
== NULL
) {
1505 FDLOG(LOG_ERR
, fd_cb
, "flow_divert_packet_init failed: %d", error
);
1509 if (toaddr
!= NULL
) {
1510 error
= flow_divert_append_target_endpoint_tlv(packet
, toaddr
);
1512 FDLOG(LOG_ERR
, fd_cb
, "flow_divert_append_target_endpoint_tlv() failed: %d", error
);
1517 if (data_len
> 0 && data_len
<= INT_MAX
&& data
!= NULL
) {
1518 last
= m_last(packet
);
1519 mbuf_setnext(last
, data
);
1520 mbuf_pkthdr_adjustlen(packet
, (int)data_len
);
1524 error
= flow_divert_send_packet(fd_cb
, packet
, force
);
1525 if (error
== 0 && data_len
> 0) {
1526 fd_cb
->bytes_sent
+= data_len
;
1527 flow_divert_add_data_statistics(fd_cb
, data_len
, TRUE
);
1533 mbuf_setnext(last
, NULL
);
1535 if (packet
!= NULL
) {
1544 flow_divert_send_buffered_data(struct flow_divert_pcb
*fd_cb
, Boolean force
)
1551 to_send
= fd_cb
->so
->so_snd
.sb_cc
;
1552 buffer
= fd_cb
->so
->so_snd
.sb_mb
;
1554 if (buffer
== NULL
&& to_send
> 0) {
1555 FDLOG(LOG_ERR
, fd_cb
, "Send buffer is NULL, but size is supposed to be %lu", to_send
);
1559 /* Ignore the send window if force is enabled */
1560 if (!force
&& (to_send
> fd_cb
->send_window
)) {
1561 to_send
= fd_cb
->send_window
;
1564 if (SOCK_TYPE(fd_cb
->so
) == SOCK_STREAM
) {
1565 while (sent
< to_send
) {
1569 data_len
= to_send
- sent
;
1570 if (data_len
> FLOW_DIVERT_CHUNK_SIZE
) {
1571 data_len
= FLOW_DIVERT_CHUNK_SIZE
;
1574 error
= mbuf_copym(buffer
, sent
, data_len
, MBUF_DONTWAIT
, &data
);
1576 FDLOG(LOG_ERR
, fd_cb
, "mbuf_copym failed: %d", error
);
1580 error
= flow_divert_send_data_packet(fd_cb
, data
, data_len
, NULL
, force
);
1590 sbdrop(&fd_cb
->so
->so_snd
, (int)sent
);
1591 sowwakeup(fd_cb
->so
);
1592 } else if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
1598 struct sockaddr
*toaddr
= flow_divert_get_buffered_target_address(buffer
);
1601 if (toaddr
!= NULL
) {
1602 /* look for data in the chain */
1605 if (m
!= NULL
&& m
->m_type
== MT_DATA
) {
1611 FDLOG0(LOG_ERR
, fd_cb
, "failed to find type MT_DATA in the mbuf chain.");
1615 data_len
= mbuf_pkthdr_len(m
);
1617 FDLOG(LOG_DEBUG
, fd_cb
, "mbuf_copym() data_len = %lu", data_len
);
1618 error
= mbuf_copym(m
, 0, data_len
, MBUF_DONTWAIT
, &data
);
1620 FDLOG(LOG_ERR
, fd_cb
, "mbuf_copym failed: %d", error
);
1626 error
= flow_divert_send_data_packet(fd_cb
, data
, data_len
, toaddr
, force
);
1635 buffer
= buffer
->m_nextpkt
;
1636 (void) sbdroprecord(&(fd_cb
->so
->so_snd
));
1641 FDLOG(LOG_DEBUG
, fd_cb
, "sent %lu bytes of buffered data", sent
);
1642 if (fd_cb
->send_window
>= sent
) {
1643 fd_cb
->send_window
-= sent
;
1645 fd_cb
->send_window
= 0;
1651 flow_divert_send_app_data(struct flow_divert_pcb
*fd_cb
, mbuf_t data
, struct sockaddr
*toaddr
)
1653 size_t to_send
= mbuf_pkthdr_len(data
);
1656 if (to_send
> fd_cb
->send_window
) {
1657 to_send
= fd_cb
->send_window
;
1660 if (fd_cb
->so
->so_snd
.sb_cc
> 0) {
1661 to_send
= 0; /* If the send buffer is non-empty, then we can't send anything */
1664 if (SOCK_TYPE(fd_cb
->so
) == SOCK_STREAM
) {
1666 mbuf_t remaining_data
= data
;
1667 mbuf_t pkt_data
= NULL
;
1668 while (sent
< to_send
&& remaining_data
!= NULL
) {
1669 size_t pkt_data_len
;
1671 pkt_data
= remaining_data
;
1673 if ((to_send
- sent
) > FLOW_DIVERT_CHUNK_SIZE
) {
1674 pkt_data_len
= FLOW_DIVERT_CHUNK_SIZE
;
1676 pkt_data_len
= to_send
- sent
;
1679 if (pkt_data_len
< mbuf_pkthdr_len(pkt_data
)) {
1680 error
= mbuf_split(pkt_data
, pkt_data_len
, MBUF_DONTWAIT
, &remaining_data
);
1682 FDLOG(LOG_ERR
, fd_cb
, "mbuf_split failed: %d", error
);
1687 remaining_data
= NULL
;
1690 error
= flow_divert_send_data_packet(fd_cb
, pkt_data
, pkt_data_len
, NULL
, FALSE
);
1697 sent
+= pkt_data_len
;
1700 fd_cb
->send_window
-= sent
;
1704 if (pkt_data
!= NULL
) {
1705 if (sbspace(&fd_cb
->so
->so_snd
) > 0) {
1706 if (!sbappendstream(&fd_cb
->so
->so_snd
, pkt_data
)) {
1707 FDLOG(LOG_ERR
, fd_cb
, "sbappendstream failed with pkt_data, send buffer size = %u, send_window = %u\n",
1708 fd_cb
->so
->so_snd
.sb_cc
, fd_cb
->send_window
);
1711 mbuf_freem(pkt_data
);
1716 if (remaining_data
!= NULL
) {
1717 if (sbspace(&fd_cb
->so
->so_snd
) > 0) {
1718 if (!sbappendstream(&fd_cb
->so
->so_snd
, remaining_data
)) {
1719 FDLOG(LOG_ERR
, fd_cb
, "sbappendstream failed with remaining_data, send buffer size = %u, send_window = %u\n",
1720 fd_cb
->so
->so_snd
.sb_cc
, fd_cb
->send_window
);
1723 mbuf_freem(remaining_data
);
1727 } else if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
1728 if (to_send
|| mbuf_pkthdr_len(data
) == 0) {
1729 error
= flow_divert_send_data_packet(fd_cb
, data
, to_send
, toaddr
, FALSE
);
1731 FDLOG(LOG_ERR
, fd_cb
, "flow_divert_send_data_packet failed. send data size = %lu", to_send
);
1736 fd_cb
->send_window
-= to_send
;
1740 if (sbspace(&fd_cb
->so
->so_snd
) >= (int)mbuf_pkthdr_len(data
)) {
1741 if (toaddr
!= NULL
) {
1742 if (!sbappendaddr(&fd_cb
->so
->so_snd
, toaddr
, data
, NULL
, &error
)) {
1743 FDLOG(LOG_ERR
, fd_cb
,
1744 "sbappendaddr failed. send buffer size = %u, send_window = %u, error = %d\n",
1745 fd_cb
->so
->so_snd
.sb_cc
, fd_cb
->send_window
, error
);
1749 if (!sbappendrecord(&fd_cb
->so
->so_snd
, data
)) {
1750 FDLOG(LOG_ERR
, fd_cb
,
1751 "sbappendrecord failed. send buffer size = %u, send_window = %u, error = %d\n",
1752 fd_cb
->so
->so_snd
.sb_cc
, fd_cb
->send_window
, error
);
1768 flow_divert_send_read_notification(struct flow_divert_pcb
*fd_cb
)
1771 mbuf_t packet
= NULL
;
1773 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_READ_NOTIFY
, &packet
);
1775 FDLOG(LOG_ERR
, fd_cb
, "failed to create a read notification packet: %d", error
);
1779 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1785 if (error
&& packet
!= NULL
) {
1793 flow_divert_send_traffic_class_update(struct flow_divert_pcb
*fd_cb
, int traffic_class
)
1796 mbuf_t packet
= NULL
;
1798 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_PROPERTIES_UPDATE
, &packet
);
1800 FDLOG(LOG_ERR
, fd_cb
, "failed to create a properties update packet: %d", error
);
1804 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_TRAFFIC_CLASS
, sizeof(traffic_class
), &traffic_class
);
1806 FDLOG(LOG_ERR
, fd_cb
, "failed to add the traffic class: %d", error
);
1810 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1816 if (error
&& packet
!= NULL
) {
1824 flow_divert_set_local_endpoint(struct flow_divert_pcb
*fd_cb
, struct sockaddr
*local_endpoint
)
1826 struct inpcb
*inp
= sotoinpcb(fd_cb
->so
);
1828 if (local_endpoint
->sa_family
== AF_INET6
) {
1829 if (IN6_IS_ADDR_UNSPECIFIED(&inp
->in6p_laddr
) && (fd_cb
->flags
& FLOW_DIVERT_SHOULD_SET_LOCAL_ADDR
)) {
1830 fd_cb
->flags
|= FLOW_DIVERT_DID_SET_LOCAL_ADDR
;
1831 inp
->in6p_laddr
= (satosin6(local_endpoint
))->sin6_addr
;
1833 if (inp
->inp_lport
== 0) {
1834 inp
->inp_lport
= (satosin6(local_endpoint
))->sin6_port
;
1836 } else if (local_endpoint
->sa_family
== AF_INET
) {
1837 if (inp
->inp_laddr
.s_addr
== INADDR_ANY
&& (fd_cb
->flags
& FLOW_DIVERT_SHOULD_SET_LOCAL_ADDR
)) {
1838 fd_cb
->flags
|= FLOW_DIVERT_DID_SET_LOCAL_ADDR
;
1839 inp
->inp_laddr
= (satosin(local_endpoint
))->sin_addr
;
1841 if (inp
->inp_lport
== 0) {
1842 inp
->inp_lport
= (satosin(local_endpoint
))->sin_port
;
1848 flow_divert_set_remote_endpoint(struct flow_divert_pcb
*fd_cb
, struct sockaddr
*remote_endpoint
)
1850 struct inpcb
*inp
= sotoinpcb(fd_cb
->so
);
1852 if (remote_endpoint
->sa_family
== AF_INET6
) {
1853 if (IN6_IS_ADDR_UNSPECIFIED(&inp
->in6p_faddr
)) {
1854 inp
->in6p_faddr
= (satosin6(remote_endpoint
))->sin6_addr
;
1856 if (inp
->inp_fport
== 0) {
1857 inp
->inp_fport
= (satosin6(remote_endpoint
))->sin6_port
;
1859 } else if (remote_endpoint
->sa_family
== AF_INET
) {
1860 if (inp
->inp_laddr
.s_addr
== INADDR_ANY
) {
1861 inp
->inp_faddr
= (satosin(remote_endpoint
))->sin_addr
;
1863 if (inp
->inp_fport
== 0) {
1864 inp
->inp_fport
= (satosin(remote_endpoint
))->sin_port
;
1870 flow_divert_derive_kernel_control_unit(uint32_t ctl_unit
, uint32_t *aggregate_unit
)
1872 if (aggregate_unit
!= NULL
&& *aggregate_unit
!= 0) {
1874 for (counter
= 0; counter
< (GROUP_COUNT_MAX
- 1); counter
++) {
1875 if ((*aggregate_unit
) & (1 << counter
)) {
1879 if (counter
< (GROUP_COUNT_MAX
- 1)) {
1880 *aggregate_unit
&= ~(1 << counter
);
1891 flow_divert_try_next(struct flow_divert_pcb
*fd_cb
)
1893 uint32_t current_ctl_unit
= 0;
1894 uint32_t next_ctl_unit
= 0;
1895 struct flow_divert_group
*current_group
= NULL
;
1896 struct flow_divert_group
*next_group
= NULL
;
1899 next_ctl_unit
= flow_divert_derive_kernel_control_unit(fd_cb
->policy_control_unit
, &(fd_cb
->aggregate_unit
));
1900 current_ctl_unit
= fd_cb
->control_group_unit
;
1902 if (current_ctl_unit
== next_ctl_unit
) {
1903 FDLOG0(LOG_NOTICE
, fd_cb
, "Next control unit is the same as the current control unit, disabling flow divert");
1908 if (next_ctl_unit
== 0 || next_ctl_unit
>= GROUP_COUNT_MAX
) {
1909 FDLOG0(LOG_NOTICE
, fd_cb
, "No more valid control units, disabling flow divert");
1914 if (g_flow_divert_groups
== NULL
|| g_active_group_count
== 0) {
1915 FDLOG0(LOG_NOTICE
, fd_cb
, "No active groups, disabling flow divert");
1920 next_group
= g_flow_divert_groups
[next_ctl_unit
];
1921 if (next_group
== NULL
) {
1922 FDLOG(LOG_NOTICE
, fd_cb
, "Group for control unit %u does not exist", next_ctl_unit
);
1927 current_group
= fd_cb
->group
;
1929 lck_rw_lock_exclusive(&(current_group
->lck
));
1930 lck_rw_lock_exclusive(&(next_group
->lck
));
1932 FDLOG(LOG_NOTICE
, fd_cb
, "Moving from %u to %u", current_ctl_unit
, next_ctl_unit
);
1934 RB_REMOVE(fd_pcb_tree
, &(current_group
->pcb_tree
), fd_cb
);
1935 if (RB_INSERT(fd_pcb_tree
, &(next_group
->pcb_tree
), fd_cb
) != NULL
) {
1936 panic("group with unit %u already contains a connection with hash %u", next_ctl_unit
, fd_cb
->hash
);
1939 fd_cb
->group
= next_group
;
1940 fd_cb
->control_group_unit
= next_ctl_unit
;
1942 lck_rw_done(&(next_group
->lck
));
1943 lck_rw_done(&(current_group
->lck
));
1945 error
= flow_divert_send_connect_packet(fd_cb
);
1947 FDLOG(LOG_NOTICE
, fd_cb
, "Failed to send the connect packet to %u, disabling flow divert", next_ctl_unit
);
1957 flow_divert_disable(struct flow_divert_pcb
*fd_cb
)
1959 struct socket
*so
= NULL
;
1962 proc_t last_proc
= NULL
;
1963 struct sockaddr
*remote_endpoint
= fd_cb
->original_remote_endpoint
;
1964 bool do_connect
= !(fd_cb
->flags
& FLOW_DIVERT_IMPLICIT_CONNECT
);
1965 struct inpcb
*inp
= NULL
;
1972 FDLOG0(LOG_NOTICE
, fd_cb
, "Skipped all flow divert services, disabling flow divert");
1974 /* Restore the IP state */
1975 inp
= sotoinpcb(so
);
1976 inp
->inp_vflag
= fd_cb
->original_vflag
;
1977 inp
->inp_faddr
.s_addr
= INADDR_ANY
;
1979 memset(&(inp
->in6p_faddr
), 0, sizeof(inp
->in6p_faddr
));
1980 inp
->in6p_fport
= 0;
1981 /* If flow divert set the local address, clear it out */
1982 if (fd_cb
->flags
& FLOW_DIVERT_DID_SET_LOCAL_ADDR
) {
1983 inp
->inp_laddr
.s_addr
= INADDR_ANY
;
1984 memset(&(inp
->in6p_laddr
), 0, sizeof(inp
->in6p_laddr
));
1986 inp
->inp_last_outifp
= fd_cb
->original_last_outifp
;
1987 inp
->in6p_last_outifp
= fd_cb
->original_last_outifp6
;
1989 /* Dis-associate the socket */
1990 so
->so_flags
&= ~SOF_FLOW_DIVERT
;
1991 so
->so_flags1
|= SOF1_FLOW_DIVERT_SKIP
;
1992 so
->so_fd_pcb
= NULL
;
1995 /* Remove from the group */
1996 flow_divert_pcb_remove(fd_cb
);
1998 FDRELEASE(fd_cb
); /* Release the socket's reference */
2000 /* Revert back to the original protocol */
2001 so
->so_proto
= pffindproto(SOCK_DOM(so
), SOCK_PROTO(so
), SOCK_TYPE(so
));
2003 last_proc
= proc_find(so
->last_pid
);
2006 /* Connect using the original protocol */
2007 error
= (*so
->so_proto
->pr_usrreqs
->pru_connect
)(so
, remote_endpoint
, (last_proc
!= NULL
? last_proc
: current_proc()));
2009 FDLOG(LOG_ERR
, fd_cb
, "Failed to connect using the socket's original protocol: %d", error
);
2014 buffer
= so
->so_snd
.sb_mb
;
2015 if (buffer
== NULL
) {
2016 /* No buffered data, done */
2020 /* Send any buffered data using the original protocol */
2021 if (SOCK_TYPE(so
) == SOCK_STREAM
) {
2022 mbuf_t data_to_send
= NULL
;
2023 size_t data_len
= so
->so_snd
.sb_cc
;
2025 error
= mbuf_copym(buffer
, 0, data_len
, MBUF_DONTWAIT
, &data_to_send
);
2027 FDLOG0(LOG_ERR
, fd_cb
, "Failed to copy the mbuf chain in the socket's send buffer");
2031 sbflush(&so
->so_snd
);
2033 if (data_to_send
->m_flags
& M_PKTHDR
) {
2034 mbuf_pkthdr_setlen(data_to_send
, data_len
);
2037 error
= (*so
->so_proto
->pr_usrreqs
->pru_send
)(so
,
2042 (last_proc
!= NULL
? last_proc
: current_proc()));
2044 if (error
&& error
!= EWOULDBLOCK
) {
2045 FDLOG(LOG_ERR
, fd_cb
, "Failed to send queued data using the socket's original protocol: %d", error
);
2049 } else if (SOCK_TYPE(so
) == SOCK_DGRAM
) {
2050 struct sockbuf
*sb
= &so
->so_snd
;
2051 MBUFQ_HEAD(send_queue_head
) send_queue
;
2052 MBUFQ_INIT(&send_queue
);
2054 /* Flush the send buffer, moving all records to a temporary queue */
2055 while (sb
->sb_mb
!= NULL
) {
2056 mbuf_t record
= sb
->sb_mb
;
2058 sb
->sb_mb
= sb
->sb_mb
->m_nextpkt
;
2063 record
->m_nextpkt
= NULL
;
2064 MBUFQ_ENQUEUE(&send_queue
, record
);
2068 while (!MBUFQ_EMPTY(&send_queue
)) {
2069 mbuf_t next_record
= MBUFQ_FIRST(&send_queue
);
2071 mbuf_t control
= NULL
;
2072 mbuf_t last_control
= NULL
;
2074 mbuf_t m
= next_record
;
2075 struct sockaddr
*to_endpoint
= NULL
;
2077 MBUFQ_DEQUEUE(&send_queue
, next_record
);
2080 if (m
->m_type
== MT_SONAME
) {
2082 } else if (m
->m_type
== MT_CONTROL
) {
2083 if (control
== NULL
) {
2087 } else if (m
->m_type
== MT_DATA
) {
2095 to_endpoint
= flow_divert_get_buffered_target_address(addr
);
2096 if (to_endpoint
== NULL
) {
2097 FDLOG0(LOG_NOTICE
, fd_cb
, "Failed to get the remote address from the buffer");
2102 FDLOG0(LOG_ERR
, fd_cb
, "Buffered record does not contain any data");
2103 mbuf_freem(next_record
);
2107 if (!(data
->m_flags
& M_PKTHDR
)) {
2108 FDLOG0(LOG_ERR
, fd_cb
, "Buffered data does not have a packet header");
2109 mbuf_freem(next_record
);
2114 addr
->m_next
= NULL
;
2117 if (last_control
!= NULL
) {
2118 last_control
->m_next
= NULL
;
2121 error
= (*so
->so_proto
->pr_usrreqs
->pru_send
)(so
,
2126 (last_proc
!= NULL
? last_proc
: current_proc()));
2133 FDLOG(LOG_ERR
, fd_cb
, "Failed to send queued data using the socket's original protocol: %d", error
);
2138 if (last_proc
!= NULL
) {
2139 proc_rele(last_proc
);
2143 so
->so_error
= (uint16_t)error
;
2144 flow_divert_disconnect_socket(so
);
2149 flow_divert_scope(struct flow_divert_pcb
*fd_cb
, int out_if_index
, bool derive_new_address
)
2151 struct socket
*so
= NULL
;
2152 struct inpcb
*inp
= NULL
;
2153 struct ifnet
*current_ifp
= NULL
;
2154 struct ifnet
*new_ifp
= NULL
;
2162 inp
= sotoinpcb(so
);
2164 if (out_if_index
<= 0) {
2168 if (inp
->inp_vflag
& INP_IPV6
) {
2169 current_ifp
= inp
->in6p_last_outifp
;
2171 current_ifp
= inp
->inp_last_outifp
;
2174 if (current_ifp
!= NULL
) {
2175 if (current_ifp
->if_index
== out_if_index
) {
2180 /* Scope the socket to the given interface */
2181 error
= inp_bindif(inp
, out_if_index
, &new_ifp
);
2183 FDLOG(LOG_ERR
, fd_cb
, "failed to scope to %d because inp_bindif returned %d", out_if_index
, error
);
2187 if (derive_new_address
&& fd_cb
->original_remote_endpoint
!= NULL
) {
2188 /* Get the appropriate address for the given interface */
2189 if (inp
->inp_vflag
& INP_IPV6
) {
2190 inp
->in6p_laddr
= sa6_any
.sin6_addr
;
2191 error
= in6_pcbladdr(inp
, fd_cb
->original_remote_endpoint
, &(fd_cb
->local_endpoint
.sin6
.sin6_addr
), NULL
);
2193 inp
->inp_laddr
.s_addr
= INADDR_ANY
;
2194 error
= in_pcbladdr(inp
, fd_cb
->original_remote_endpoint
, &(fd_cb
->local_endpoint
.sin
.sin_addr
), IFSCOPE_NONE
, NULL
, 0);
2198 FDLOG(LOG_WARNING
, fd_cb
, "failed to derive a new local address from %d because in_pcbladdr returned %d", out_if_index
, error
);
2202 ifnet_head_lock_shared();
2203 if (out_if_index
<= if_index
) {
2204 new_ifp
= ifindex2ifnet
[out_if_index
];
2209 /* Update the "last interface" of the socket */
2210 if (new_ifp
!= NULL
) {
2211 if (inp
->inp_vflag
& INP_IPV6
) {
2212 inp
->in6p_last_outifp
= new_ifp
;
2214 inp
->inp_last_outifp
= new_ifp
;
2221 flow_divert_handle_connect_result(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
2223 uint32_t connect_error
= 0;
2224 uint32_t ctl_unit
= 0;
2226 struct flow_divert_group
*grp
= NULL
;
2227 union sockaddr_in_4_6 local_endpoint
= {};
2228 union sockaddr_in_4_6 remote_endpoint
= {};
2229 int out_if_index
= 0;
2230 uint32_t send_window
;
2231 uint32_t app_data_length
= 0;
2233 memset(&local_endpoint
, 0, sizeof(local_endpoint
));
2234 memset(&remote_endpoint
, 0, sizeof(remote_endpoint
));
2236 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_ERROR_CODE
, sizeof(connect_error
), &connect_error
, NULL
);
2238 FDLOG(LOG_ERR
, fd_cb
, "failed to get the connect result: %d", error
);
2242 connect_error
= ntohl(connect_error
);
2243 FDLOG(LOG_INFO
, fd_cb
, "received connect result %u", connect_error
);
2245 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_SPACE_AVAILABLE
, sizeof(send_window
), &send_window
, NULL
);
2247 FDLOG(LOG_ERR
, fd_cb
, "failed to get the send window: %d", error
);
2251 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), &ctl_unit
, NULL
);
2253 FDLOG0(LOG_INFO
, fd_cb
, "No control unit provided in the connect result");
2256 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_LOCAL_ADDR
, sizeof(local_endpoint
), &(local_endpoint
.sa
), NULL
);
2258 FDLOG0(LOG_INFO
, fd_cb
, "No local address provided");
2261 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_REMOTE_ADDR
, sizeof(remote_endpoint
), &(remote_endpoint
.sa
), NULL
);
2263 FDLOG0(LOG_INFO
, fd_cb
, "No remote address provided");
2266 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_OUT_IF_INDEX
, sizeof(out_if_index
), &out_if_index
, NULL
);
2268 FDLOG0(LOG_INFO
, fd_cb
, "No output if index provided");
2271 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_APP_DATA
, 0, NULL
, &app_data_length
);
2273 FDLOG0(LOG_INFO
, fd_cb
, "No application data provided in connect result");
2277 ctl_unit
= ntohl(ctl_unit
);
2279 lck_rw_lock_shared(&g_flow_divert_group_lck
);
2281 if (connect_error
== 0 && ctl_unit
> 0) {
2282 if (ctl_unit
>= GROUP_COUNT_MAX
) {
2283 FDLOG(LOG_ERR
, fd_cb
, "Connect result contains an invalid control unit: %u", ctl_unit
);
2285 } else if (g_flow_divert_groups
== NULL
|| g_active_group_count
== 0) {
2286 FDLOG0(LOG_ERR
, fd_cb
, "No active groups, dropping connection");
2289 grp
= g_flow_divert_groups
[ctl_unit
];
2297 if (fd_cb
->so
!= NULL
) {
2298 struct inpcb
*inp
= NULL
;
2299 struct flow_divert_group
*old_group
;
2300 struct socket
*so
= fd_cb
->so
;
2301 bool local_address_is_valid
= false;
2305 if (!(so
->so_flags
& SOF_FLOW_DIVERT
)) {
2306 FDLOG0(LOG_NOTICE
, fd_cb
, "socket is not attached any more, ignoring connect result");
2310 if (SOCK_TYPE(so
) == SOCK_STREAM
&& !(so
->so_state
& SS_ISCONNECTING
)) {
2311 FDLOG0(LOG_ERR
, fd_cb
, "TCP socket is not in the connecting state, ignoring connect result");
2315 inp
= sotoinpcb(so
);
2317 if (connect_error
|| error
) {
2318 goto set_socket_state
;
2321 if (flow_divert_is_sockaddr_valid(&(local_endpoint
.sa
))) {
2322 if (local_endpoint
.sa
.sa_family
== AF_INET
) {
2323 local_endpoint
.sa
.sa_len
= sizeof(struct sockaddr_in
);
2324 if ((inp
->inp_vflag
& INP_IPV4
) && local_endpoint
.sin
.sin_addr
.s_addr
!= INADDR_ANY
) {
2325 local_address_is_valid
= true;
2326 fd_cb
->local_endpoint
= local_endpoint
;
2327 inp
->inp_laddr
.s_addr
= INADDR_ANY
;
2329 fd_cb
->local_endpoint
.sin
.sin_port
= local_endpoint
.sin
.sin_port
;
2331 } else if (local_endpoint
.sa
.sa_family
== AF_INET6
) {
2332 local_endpoint
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
2333 if ((inp
->inp_vflag
& INP_IPV6
) && !IN6_IS_ADDR_UNSPECIFIED(&local_endpoint
.sin6
.sin6_addr
)) {
2334 local_address_is_valid
= true;
2335 fd_cb
->local_endpoint
= local_endpoint
;
2336 inp
->in6p_laddr
= sa6_any
.sin6_addr
;
2338 fd_cb
->local_endpoint
.sin6
.sin6_port
= local_endpoint
.sin6
.sin6_port
;
2343 flow_divert_scope(fd_cb
, out_if_index
, !local_address_is_valid
);
2344 flow_divert_set_local_endpoint(fd_cb
, &(fd_cb
->local_endpoint
.sa
));
2346 if (flow_divert_is_sockaddr_valid(&(remote_endpoint
.sa
)) && SOCK_TYPE(so
) == SOCK_STREAM
) {
2347 if (remote_endpoint
.sa
.sa_family
== AF_INET
) {
2348 remote_endpoint
.sa
.sa_len
= sizeof(struct sockaddr_in
);
2349 } else if (remote_endpoint
.sa
.sa_family
== AF_INET6
) {
2350 remote_endpoint
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
2352 flow_divert_set_remote_endpoint(fd_cb
, &(remote_endpoint
.sa
));
2355 if (app_data_length
> 0) {
2356 uint8_t *app_data
= NULL
;
2357 MALLOC(app_data
, uint8_t *, app_data_length
, M_TEMP
, M_WAITOK
);
2358 if (app_data
!= NULL
) {
2359 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_APP_DATA
, app_data_length
, app_data
, NULL
);
2361 FDLOG(LOG_INFO
, fd_cb
, "Got %u bytes of app data from the connect result", app_data_length
);
2362 if (fd_cb
->app_data
!= NULL
) {
2363 FREE(fd_cb
->app_data
, M_TEMP
);
2365 fd_cb
->app_data
= app_data
;
2366 fd_cb
->app_data_length
= app_data_length
;
2368 FDLOG(LOG_ERR
, fd_cb
, "Failed to copy %u bytes of application data from the connect result packet", app_data_length
);
2369 FREE(app_data
, M_TEMP
);
2372 FDLOG(LOG_ERR
, fd_cb
, "Failed to allocate a buffer of size %u to hold the application data from the connect result", app_data_length
);
2377 goto set_socket_state
;
2380 if (fd_cb
->group
== NULL
) {
2382 goto set_socket_state
;
2386 old_group
= fd_cb
->group
;
2388 lck_rw_lock_exclusive(&old_group
->lck
);
2389 lck_rw_lock_exclusive(&grp
->lck
);
2391 RB_REMOVE(fd_pcb_tree
, &old_group
->pcb_tree
, fd_cb
);
2392 if (RB_INSERT(fd_pcb_tree
, &grp
->pcb_tree
, fd_cb
) != NULL
) {
2393 panic("group with unit %u already contains a connection with hash %u", grp
->ctl_unit
, fd_cb
->hash
);
2398 lck_rw_done(&grp
->lck
);
2399 lck_rw_done(&old_group
->lck
);
2402 fd_cb
->send_window
= ntohl(send_window
);
2405 if (!connect_error
&& !error
) {
2406 FDLOG0(LOG_INFO
, fd_cb
, "sending connect result");
2407 error
= flow_divert_send_connect_result(fd_cb
);
2410 if (connect_error
|| error
) {
2411 if (connect_error
&& fd_cb
->control_group_unit
!= fd_cb
->policy_control_unit
) {
2412 error
= flow_divert_try_next(fd_cb
);
2414 flow_divert_disable(fd_cb
);
2419 if (!connect_error
) {
2420 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, FALSE
);
2421 so
->so_error
= (uint16_t)error
;
2422 flow_divert_send_close_if_needed(fd_cb
);
2424 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, TRUE
);
2425 so
->so_error
= (uint16_t)connect_error
;
2427 flow_divert_disconnect_socket(so
);
2430 /* Update NECP client with connected five-tuple */
2431 if (!uuid_is_null(inp
->necp_client_uuid
)) {
2432 socket_unlock(so
, 0);
2433 necp_client_assign_from_socket(so
->last_pid
, inp
->necp_client_uuid
, inp
);
2438 flow_divert_send_buffered_data(fd_cb
, FALSE
);
2442 /* We don't need the connect packet any more */
2443 if (fd_cb
->connect_packet
!= NULL
) {
2444 mbuf_freem(fd_cb
->connect_packet
);
2445 fd_cb
->connect_packet
= NULL
;
2448 /* We don't need the original remote endpoint any more */
2449 if (fd_cb
->original_remote_endpoint
!= NULL
) {
2450 FREE(fd_cb
->original_remote_endpoint
, M_SONAME
);
2451 fd_cb
->original_remote_endpoint
= NULL
;
2454 socket_unlock(so
, 0);
2458 lck_rw_done(&g_flow_divert_group_lck
);
2462 flow_divert_handle_close(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
2464 uint32_t close_error
;
2468 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_ERROR_CODE
, sizeof(close_error
), &close_error
, NULL
);
2470 FDLOG(LOG_ERR
, fd_cb
, "failed to get the close error: %d", error
);
2474 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_HOW
, sizeof(how
), &how
, NULL
);
2476 FDLOG(LOG_ERR
, fd_cb
, "failed to get the close how flag: %d", error
);
2482 FDLOG(LOG_INFO
, fd_cb
, "close received, how = %d", how
);
2485 if (fd_cb
->so
!= NULL
) {
2486 socket_lock(fd_cb
->so
, 0);
2488 if (!(fd_cb
->so
->so_flags
& SOF_FLOW_DIVERT
)) {
2489 FDLOG0(LOG_NOTICE
, fd_cb
, "socket is not attached any more, ignoring close from provider");
2493 fd_cb
->so
->so_error
= (uint16_t)ntohl(close_error
);
2495 flow_divert_update_closed_state(fd_cb
, how
, TRUE
);
2497 how
= flow_divert_tunnel_how_closed(fd_cb
);
2498 if (how
== SHUT_RDWR
) {
2499 flow_divert_disconnect_socket(fd_cb
->so
);
2500 } else if (how
== SHUT_RD
) {
2501 socantrcvmore(fd_cb
->so
);
2502 } else if (how
== SHUT_WR
) {
2503 socantsendmore(fd_cb
->so
);
2506 socket_unlock(fd_cb
->so
, 0);
2512 flow_divert_create_control_mbuf(struct flow_divert_pcb
*fd_cb
)
2514 struct inpcb
*inp
= sotoinpcb(fd_cb
->so
);
2515 bool is_cfil_enabled
= false;
2517 /* Content Filter needs to see the local address */
2518 is_cfil_enabled
= (inp
->inp_socket
&& inp
->inp_socket
->so_cfil_db
!= NULL
);
2520 if ((inp
->inp_vflag
& INP_IPV4
) &&
2521 fd_cb
->local_endpoint
.sa
.sa_family
== AF_INET
&&
2522 ((inp
->inp_flags
& INP_RECVDSTADDR
) || is_cfil_enabled
)) {
2523 return sbcreatecontrol((caddr_t
)&(fd_cb
->local_endpoint
.sin
.sin_addr
), sizeof(struct in_addr
), IP_RECVDSTADDR
, IPPROTO_IP
);
2524 } else if ((inp
->inp_vflag
& INP_IPV6
) &&
2525 fd_cb
->local_endpoint
.sa
.sa_family
== AF_INET6
&&
2526 ((inp
->inp_flags
& IN6P_PKTINFO
) || is_cfil_enabled
)) {
2527 struct in6_pktinfo pi6
;
2528 memset(&pi6
, 0, sizeof(pi6
));
2529 pi6
.ipi6_addr
= fd_cb
->local_endpoint
.sin6
.sin6_addr
;
2531 return sbcreatecontrol((caddr_t
)&pi6
, sizeof(pi6
), IPV6_PKTINFO
, IPPROTO_IPV6
);
2537 flow_divert_handle_data(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, size_t offset
)
2542 if (fd_cb
->so
!= NULL
) {
2545 struct sockaddr_storage remote_address
;
2546 boolean_t got_remote_sa
= FALSE
;
2547 boolean_t appended
= FALSE
;
2548 boolean_t append_success
= FALSE
;
2550 socket_lock(fd_cb
->so
, 0);
2552 if (!(fd_cb
->so
->so_flags
& SOF_FLOW_DIVERT
)) {
2553 FDLOG0(LOG_NOTICE
, fd_cb
, "socket is not attached any more, ignoring inbound data");
2557 if (sbspace(&fd_cb
->so
->so_rcv
) == 0) {
2559 fd_cb
->flags
|= FLOW_DIVERT_NOTIFY_ON_RECEIVED
;
2560 FDLOG0(LOG_INFO
, fd_cb
, "Receive buffer is full, will send read notification when app reads some data");
2564 if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
2565 uint32_t val_size
= 0;
2567 /* check if we got remote address with data */
2568 memset(&remote_address
, 0, sizeof(remote_address
));
2569 error
= flow_divert_packet_get_tlv(packet
, (int)offset
, FLOW_DIVERT_TLV_REMOTE_ADDR
, sizeof(remote_address
), &remote_address
, &val_size
);
2570 if (error
|| val_size
> sizeof(remote_address
)) {
2571 FDLOG0(LOG_INFO
, fd_cb
, "No remote address provided");
2574 if (remote_address
.ss_len
> sizeof(remote_address
)) {
2575 remote_address
.ss_len
= sizeof(remote_address
);
2577 /* validate the address */
2578 if (flow_divert_is_sockaddr_valid((struct sockaddr
*)&remote_address
)) {
2579 got_remote_sa
= TRUE
;
2581 FDLOG0(LOG_INFO
, fd_cb
, "Remote address is invalid");
2583 offset
+= (sizeof(uint8_t) + sizeof(uint32_t) + val_size
);
2587 data_size
= (mbuf_pkthdr_len(packet
) - offset
);
2589 if (fd_cb
->so
->so_state
& SS_CANTRCVMORE
) {
2590 FDLOG(LOG_NOTICE
, fd_cb
, "app cannot receive any more data, dropping %lu bytes of data", data_size
);
2594 if (SOCK_TYPE(fd_cb
->so
) != SOCK_STREAM
&& SOCK_TYPE(fd_cb
->so
) != SOCK_DGRAM
) {
2595 FDLOG(LOG_ERR
, fd_cb
, "socket has an unsupported type: %d", SOCK_TYPE(fd_cb
->so
));
2599 FDLOG(LOG_DEBUG
, fd_cb
, "received %lu bytes of data", data_size
);
2601 error
= mbuf_split(packet
, offset
, MBUF_DONTWAIT
, &data
);
2602 if (error
|| data
== NULL
) {
2603 FDLOG(LOG_ERR
, fd_cb
, "mbuf_split failed: %d", error
);
2607 if (SOCK_TYPE(fd_cb
->so
) == SOCK_STREAM
) {
2608 appended
= (sbappendstream(&fd_cb
->so
->so_rcv
, data
) != 0);
2609 append_success
= TRUE
;
2611 struct sockaddr
*append_sa
= NULL
;
2614 if (got_remote_sa
== TRUE
) {
2615 error
= flow_divert_dup_addr(remote_address
.ss_family
, (struct sockaddr
*)&remote_address
, &append_sa
);
2617 if (fd_cb
->so
->so_proto
->pr_domain
->dom_family
== AF_INET6
) {
2618 error
= in6_mapped_peeraddr(fd_cb
->so
, &append_sa
);
2620 error
= in_getpeeraddr(fd_cb
->so
, &append_sa
);
2624 FDLOG0(LOG_ERR
, fd_cb
, "failed to dup the socket address.");
2627 mctl
= flow_divert_create_control_mbuf(fd_cb
);
2628 int append_error
= 0;
2629 if (sbappendaddr(&fd_cb
->so
->so_rcv
, append_sa
, data
, mctl
, &append_error
) || append_error
== EJUSTRETURN
) {
2630 append_success
= TRUE
;
2631 appended
= (append_error
== 0);
2633 FDLOG(LOG_ERR
, fd_cb
, "failed to append %lu bytes of data: %d", data_size
, append_error
);
2636 if (append_sa
!= NULL
) {
2637 FREE(append_sa
, M_SONAME
);
2641 if (append_success
) {
2642 fd_cb
->bytes_received
+= data_size
;
2643 flow_divert_add_data_statistics(fd_cb
, data_size
, FALSE
);
2647 sorwakeup(fd_cb
->so
);
2650 socket_unlock(fd_cb
->so
, 0);
2658 flow_divert_handle_read_notification(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
2660 uint32_t read_count
;
2663 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_READ_COUNT
, sizeof(read_count
), &read_count
, NULL
);
2665 FDLOG(LOG_ERR
, fd_cb
, "failed to get the read count: %d", error
);
2669 FDLOG(LOG_DEBUG
, fd_cb
, "received a read notification for %u bytes", ntohl(read_count
));
2672 if (fd_cb
->so
!= NULL
) {
2673 socket_lock(fd_cb
->so
, 0);
2675 if (!(fd_cb
->so
->so_flags
& SOF_FLOW_DIVERT
)) {
2676 FDLOG0(LOG_NOTICE
, fd_cb
, "socket is not attached any more, ignoring read notification");
2680 fd_cb
->send_window
+= ntohl(read_count
);
2681 flow_divert_send_buffered_data(fd_cb
, FALSE
);
2683 socket_unlock(fd_cb
->so
, 0);
2689 flow_divert_handle_group_init(struct flow_divert_group
*group
, mbuf_t packet
, int offset
)
2692 uint32_t key_size
= 0;
2696 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_TOKEN_KEY
, 0, NULL
, &key_size
);
2698 FDLOG(LOG_ERR
, &nil_pcb
, "failed to get the key size: %d", error
);
2702 if (key_size
== 0 || key_size
> FLOW_DIVERT_MAX_KEY_SIZE
) {
2703 FDLOG(LOG_ERR
, &nil_pcb
, "Invalid key size: %u", key_size
);
2707 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_LOG_LEVEL
, sizeof(log_level
), &log_level
, NULL
);
2709 nil_pcb
.log_level
= (uint8_t)log_level
;
2712 lck_rw_lock_exclusive(&group
->lck
);
2714 if (group
->token_key
!= NULL
) {
2715 FREE(group
->token_key
, M_TEMP
);
2716 group
->token_key
= NULL
;
2719 MALLOC(group
->token_key
, uint8_t *, key_size
, M_TEMP
, M_WAITOK
);
2720 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_TOKEN_KEY
, key_size
, group
->token_key
, NULL
);
2722 FDLOG(LOG_ERR
, &nil_pcb
, "failed to get the token key: %d", error
);
2723 FREE(group
->token_key
, M_TEMP
);
2724 group
->token_key
= NULL
;
2725 lck_rw_done(&group
->lck
);
2729 group
->token_key_size
= key_size
;
2731 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_FLAGS
, sizeof(flags
), &flags
, NULL
);
2733 group
->flags
= flags
;
2736 lck_rw_done(&group
->lck
);
2740 flow_divert_handle_properties_update(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
2743 int out_if_index
= 0;
2744 uint32_t app_data_length
= 0;
2746 FDLOG0(LOG_INFO
, fd_cb
, "received a properties update");
2748 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_OUT_IF_INDEX
, sizeof(out_if_index
), &out_if_index
, NULL
);
2750 FDLOG0(LOG_INFO
, fd_cb
, "No output if index provided in properties update");
2753 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_APP_DATA
, 0, NULL
, &app_data_length
);
2755 FDLOG0(LOG_INFO
, fd_cb
, "No application data provided in properties update");
2759 if (fd_cb
->so
!= NULL
) {
2760 socket_lock(fd_cb
->so
, 0);
2762 if (!(fd_cb
->so
->so_flags
& SOF_FLOW_DIVERT
)) {
2763 FDLOG0(LOG_NOTICE
, fd_cb
, "socket is not attached any more, ignoring properties update");
2767 if (out_if_index
> 0) {
2768 flow_divert_scope(fd_cb
, out_if_index
, true);
2769 flow_divert_set_local_endpoint(fd_cb
, &(fd_cb
->local_endpoint
.sa
));
2772 if (app_data_length
> 0) {
2773 uint8_t *app_data
= NULL
;
2774 MALLOC(app_data
, uint8_t *, app_data_length
, M_TEMP
, M_WAITOK
);
2775 if (app_data
!= NULL
) {
2776 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_APP_DATA
, app_data_length
, app_data
, NULL
);
2778 if (fd_cb
->app_data
!= NULL
) {
2779 FREE(fd_cb
->app_data
, M_TEMP
);
2781 fd_cb
->app_data
= app_data
;
2782 fd_cb
->app_data_length
= app_data_length
;
2784 FDLOG(LOG_ERR
, fd_cb
, "Failed to copy %u bytes of application data from the properties update packet", app_data_length
);
2785 FREE(app_data
, M_TEMP
);
2788 FDLOG(LOG_ERR
, fd_cb
, "Failed to allocate a buffer of size %u to hold the application data from the properties update", app_data_length
);
2792 socket_unlock(fd_cb
->so
, 0);
2798 flow_divert_handle_app_map_create(struct flow_divert_group
*group
, mbuf_t packet
, int offset
)
2800 size_t bytes_mem_size
;
2801 size_t child_maps_mem_size
;
2802 size_t nodes_mem_size
;
2803 size_t trie_memory_size
= 0;
2806 struct flow_divert_trie new_trie
;
2807 int insert_error
= 0;
2808 int prefix_count
= -1;
2809 int signing_id_count
= 0;
2810 size_t bytes_count
= 0;
2811 size_t nodes_count
= 0;
2812 size_t maps_count
= 0;
2814 lck_rw_lock_exclusive(&group
->lck
);
2816 /* Re-set the current trie */
2817 if (group
->signing_id_trie
.memory
!= NULL
) {
2818 FREE(group
->signing_id_trie
.memory
, M_TEMP
);
2820 memset(&group
->signing_id_trie
, 0, sizeof(group
->signing_id_trie
));
2821 group
->signing_id_trie
.root
= NULL_TRIE_IDX
;
2823 memset(&new_trie
, 0, sizeof(new_trie
));
2825 /* Get the number of shared prefixes in the new set of signing ID strings */
2826 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_PREFIX_COUNT
, sizeof(prefix_count
), &prefix_count
, NULL
);
2828 if (prefix_count
< 0 || error
) {
2829 FDLOG(LOG_ERR
, &nil_pcb
, "Invalid prefix count (%d) or an error occurred while reading the prefix count: %d", prefix_count
, error
);
2830 lck_rw_done(&group
->lck
);
2834 /* Compute the number of signing IDs and the total amount of bytes needed to store them */
2835 for (cursor
= flow_divert_packet_find_tlv(packet
, offset
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 0);
2837 cursor
= flow_divert_packet_find_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 1)) {
2838 uint32_t sid_size
= 0;
2839 error
= flow_divert_packet_get_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, 0, NULL
, &sid_size
);
2840 if (error
|| sid_size
== 0) {
2841 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to get the length of the signing identifier at offset %d: %d", cursor
, error
);
2842 signing_id_count
= 0;
2845 if (os_add_overflow(bytes_count
, sid_size
, &bytes_count
)) {
2846 FDLOG0(LOG_ERR
, &nil_pcb
, "Overflow while incrementing number of bytes");
2847 signing_id_count
= 0;
2853 if (signing_id_count
== 0) {
2854 lck_rw_done(&group
->lck
);
2855 FDLOG0(LOG_NOTICE
, &nil_pcb
, "No signing identifiers");
2859 if (os_add3_overflow(prefix_count
, signing_id_count
, 1, &nodes_count
)) { /* + 1 for the root node */
2860 lck_rw_done(&group
->lck
);
2861 FDLOG0(LOG_ERR
, &nil_pcb
, "Overflow while computing the number of nodes");
2865 if (os_add_overflow(prefix_count
, 1, &maps_count
)) { /* + 1 for the root node */
2866 lck_rw_done(&group
->lck
);
2867 FDLOG0(LOG_ERR
, &nil_pcb
, "Overflow while computing the number of maps");
2871 if (bytes_count
> UINT16_MAX
|| nodes_count
> UINT16_MAX
|| maps_count
> UINT16_MAX
) {
2872 lck_rw_done(&group
->lck
);
2873 FDLOG(LOG_NOTICE
, &nil_pcb
, "Invalid bytes count (%lu), nodes count (%lu) or maps count (%lu)", bytes_count
, nodes_count
, maps_count
);
2877 FDLOG(LOG_INFO
, &nil_pcb
, "Nodes count = %lu, child maps count = %lu, bytes_count = %lu",
2878 nodes_count
, maps_count
, bytes_count
);
2880 if (os_mul_overflow(sizeof(*new_trie
.nodes
), (size_t)nodes_count
, &nodes_mem_size
) ||
2881 os_mul3_overflow(sizeof(*new_trie
.child_maps
), CHILD_MAP_SIZE
, (size_t)maps_count
, &child_maps_mem_size
) ||
2882 os_mul_overflow(sizeof(*new_trie
.bytes
), (size_t)bytes_count
, &bytes_mem_size
) ||
2883 os_add3_overflow(nodes_mem_size
, child_maps_mem_size
, bytes_mem_size
, &trie_memory_size
)) {
2884 FDLOG0(LOG_ERR
, &nil_pcb
, "Overflow while computing trie memory sizes");
2885 lck_rw_done(&group
->lck
);
2889 if (trie_memory_size
> FLOW_DIVERT_MAX_TRIE_MEMORY
) {
2890 FDLOG(LOG_ERR
, &nil_pcb
, "Trie memory size (%lu) is too big (maximum is %u)", trie_memory_size
, FLOW_DIVERT_MAX_TRIE_MEMORY
);
2891 lck_rw_done(&group
->lck
);
2895 MALLOC(new_trie
.memory
, void *, trie_memory_size
, M_TEMP
, M_WAITOK
);
2896 if (new_trie
.memory
== NULL
) {
2897 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to allocate %lu bytes of memory for the signing ID trie",
2898 nodes_mem_size
+ child_maps_mem_size
+ bytes_mem_size
);
2899 lck_rw_done(&group
->lck
);
2903 new_trie
.bytes_count
= (uint16_t)bytes_count
;
2904 new_trie
.nodes_count
= (uint16_t)nodes_count
;
2905 new_trie
.child_maps_count
= (uint16_t)maps_count
;
2907 /* Initialize the free lists */
2908 new_trie
.nodes
= (struct flow_divert_trie_node
*)new_trie
.memory
;
2909 new_trie
.nodes_free_next
= 0;
2910 memset(new_trie
.nodes
, 0, nodes_mem_size
);
2912 new_trie
.child_maps
= (uint16_t *)(void *)((uint8_t *)new_trie
.memory
+ nodes_mem_size
);
2913 new_trie
.child_maps_free_next
= 0;
2914 memset(new_trie
.child_maps
, 0xff, child_maps_mem_size
);
2916 new_trie
.bytes
= (uint8_t *)(void *)((uint8_t *)new_trie
.memory
+ nodes_mem_size
+ child_maps_mem_size
);
2917 new_trie
.bytes_free_next
= 0;
2918 memset(new_trie
.bytes
, 0, bytes_mem_size
);
2920 /* The root is an empty node */
2921 new_trie
.root
= trie_node_alloc(&new_trie
);
2923 /* Add each signing ID to the trie */
2924 for (cursor
= flow_divert_packet_find_tlv(packet
, offset
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 0);
2926 cursor
= flow_divert_packet_find_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 1)) {
2927 uint32_t sid_size
= 0;
2928 error
= flow_divert_packet_get_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, 0, NULL
, &sid_size
);
2929 if (error
|| sid_size
== 0) {
2930 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to get the length of the signing identifier at offset %d while building: %d", cursor
, error
);
2931 insert_error
= EINVAL
;
2934 if (sid_size
<= UINT16_MAX
&& new_trie
.bytes_free_next
+ (uint16_t)sid_size
<= new_trie
.bytes_count
) {
2935 uint16_t new_node_idx
;
2936 error
= flow_divert_packet_get_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, sid_size
, &TRIE_BYTE(&new_trie
, new_trie
.bytes_free_next
), NULL
);
2938 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to read the signing identifier at offset %d: %d", cursor
, error
);
2939 insert_error
= EINVAL
;
2942 new_node_idx
= flow_divert_trie_insert(&new_trie
, new_trie
.bytes_free_next
, sid_size
);
2943 if (new_node_idx
== NULL_TRIE_IDX
) {
2944 insert_error
= EINVAL
;
2948 FDLOG0(LOG_ERR
, &nil_pcb
, "No place to put signing ID for insertion");
2949 insert_error
= ENOBUFS
;
2954 if (!insert_error
) {
2955 group
->signing_id_trie
= new_trie
;
2957 FREE(new_trie
.memory
, M_TEMP
);
2960 lck_rw_done(&group
->lck
);
2964 flow_divert_input(mbuf_t packet
, struct flow_divert_group
*group
)
2966 struct flow_divert_packet_header hdr
;
2968 struct flow_divert_pcb
*fd_cb
;
2970 if (mbuf_pkthdr_len(packet
) < sizeof(hdr
)) {
2971 FDLOG(LOG_ERR
, &nil_pcb
, "got a bad packet, length (%lu) < sizeof hdr (%lu)", mbuf_pkthdr_len(packet
), sizeof(hdr
));
2976 if (mbuf_pkthdr_len(packet
) > FD_CTL_RCVBUFF_SIZE
) {
2977 FDLOG(LOG_ERR
, &nil_pcb
, "got a bad packet, length (%lu) > %d", mbuf_pkthdr_len(packet
), FD_CTL_RCVBUFF_SIZE
);
2982 error
= mbuf_copydata(packet
, 0, sizeof(hdr
), &hdr
);
2984 FDLOG(LOG_ERR
, &nil_pcb
, "mbuf_copydata failed for the header: %d", error
);
2989 hdr
.conn_id
= ntohl(hdr
.conn_id
);
2991 if (hdr
.conn_id
== 0) {
2992 switch (hdr
.packet_type
) {
2993 case FLOW_DIVERT_PKT_GROUP_INIT
:
2994 flow_divert_handle_group_init(group
, packet
, sizeof(hdr
));
2996 case FLOW_DIVERT_PKT_APP_MAP_CREATE
:
2997 flow_divert_handle_app_map_create(group
, packet
, sizeof(hdr
));
3000 FDLOG(LOG_WARNING
, &nil_pcb
, "got an unknown message type: %d", hdr
.packet_type
);
3006 fd_cb
= flow_divert_pcb_lookup(hdr
.conn_id
, group
); /* This retains the PCB */
3007 if (fd_cb
== NULL
) {
3008 if (hdr
.packet_type
!= FLOW_DIVERT_PKT_CLOSE
&& hdr
.packet_type
!= FLOW_DIVERT_PKT_READ_NOTIFY
) {
3009 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
);
3014 switch (hdr
.packet_type
) {
3015 case FLOW_DIVERT_PKT_CONNECT_RESULT
:
3016 flow_divert_handle_connect_result(fd_cb
, packet
, sizeof(hdr
));
3018 case FLOW_DIVERT_PKT_CLOSE
:
3019 flow_divert_handle_close(fd_cb
, packet
, sizeof(hdr
));
3021 case FLOW_DIVERT_PKT_DATA
:
3022 error
= flow_divert_handle_data(fd_cb
, packet
, sizeof(hdr
));
3024 case FLOW_DIVERT_PKT_READ_NOTIFY
:
3025 flow_divert_handle_read_notification(fd_cb
, packet
, sizeof(hdr
));
3027 case FLOW_DIVERT_PKT_PROPERTIES_UPDATE
:
3028 flow_divert_handle_properties_update(fd_cb
, packet
, sizeof(hdr
));
3031 FDLOG(LOG_WARNING
, fd_cb
, "got an unknown message type: %d", hdr
.packet_type
);
3043 flow_divert_close_all(struct flow_divert_group
*group
)
3045 struct flow_divert_pcb
*fd_cb
;
3046 SLIST_HEAD(, flow_divert_pcb
) tmp_list
;
3048 SLIST_INIT(&tmp_list
);
3050 lck_rw_lock_exclusive(&group
->lck
);
3052 MBUFQ_DRAIN(&group
->send_queue
);
3054 RB_FOREACH(fd_cb
, fd_pcb_tree
, &group
->pcb_tree
) {
3056 SLIST_INSERT_HEAD(&tmp_list
, fd_cb
, tmp_list_entry
);
3059 lck_rw_done(&group
->lck
);
3061 while (!SLIST_EMPTY(&tmp_list
)) {
3062 fd_cb
= SLIST_FIRST(&tmp_list
);
3064 SLIST_REMOVE_HEAD(&tmp_list
, tmp_list_entry
);
3065 if (fd_cb
->so
!= NULL
) {
3066 socket_lock(fd_cb
->so
, 0);
3067 flow_divert_pcb_remove(fd_cb
);
3068 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, TRUE
);
3069 fd_cb
->so
->so_error
= ECONNABORTED
;
3070 flow_divert_disconnect_socket(fd_cb
->so
);
3071 socket_unlock(fd_cb
->so
, 0);
3079 flow_divert_detach(struct socket
*so
)
3081 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3083 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
3085 so
->so_flags
&= ~SOF_FLOW_DIVERT
;
3086 so
->so_fd_pcb
= NULL
;
3088 FDLOG(LOG_INFO
, fd_cb
, "Detaching, ref count = %d", fd_cb
->ref_count
);
3090 if (fd_cb
->group
!= NULL
) {
3091 /* Last-ditch effort to send any buffered data */
3092 flow_divert_send_buffered_data(fd_cb
, TRUE
);
3094 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, FALSE
);
3095 flow_divert_send_close_if_needed(fd_cb
);
3096 /* Remove from the group */
3097 flow_divert_pcb_remove(fd_cb
);
3100 socket_unlock(so
, 0);
3106 FDRELEASE(fd_cb
); /* Release the socket's reference */
3110 flow_divert_close(struct socket
*so
)
3112 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3114 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
3116 FDLOG0(LOG_INFO
, fd_cb
, "Closing");
3118 if (SOCK_TYPE(so
) == SOCK_STREAM
) {
3119 soisdisconnecting(so
);
3120 sbflush(&so
->so_rcv
);
3123 flow_divert_send_buffered_data(fd_cb
, TRUE
);
3124 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, FALSE
);
3125 flow_divert_send_close_if_needed(fd_cb
);
3127 /* Remove from the group */
3128 flow_divert_pcb_remove(fd_cb
);
3134 flow_divert_disconnectx(struct socket
*so
, sae_associd_t aid
,
3135 sae_connid_t cid __unused
)
3137 if (aid
!= SAE_ASSOCID_ANY
&& aid
!= SAE_ASSOCID_ALL
) {
3141 return flow_divert_close(so
);
3145 flow_divert_shutdown(struct socket
*so
)
3147 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3149 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
3151 FDLOG0(LOG_INFO
, fd_cb
, "Can't send more");
3155 flow_divert_update_closed_state(fd_cb
, SHUT_WR
, FALSE
);
3156 flow_divert_send_close_if_needed(fd_cb
);
3162 flow_divert_rcvd(struct socket
*so
, int flags __unused
)
3164 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3165 int space
= sbspace(&so
->so_rcv
);
3167 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
3169 FDLOG(LOG_DEBUG
, fd_cb
, "app read bytes, space = %d", space
);
3170 if ((fd_cb
->flags
& FLOW_DIVERT_NOTIFY_ON_RECEIVED
) &&
3172 flow_divert_send_read_notification(fd_cb
) == 0) {
3173 FDLOG0(LOG_INFO
, fd_cb
, "Sent a read notification");
3174 fd_cb
->flags
&= ~FLOW_DIVERT_NOTIFY_ON_RECEIVED
;
3181 flow_divert_append_target_endpoint_tlv(mbuf_t connect_packet
, struct sockaddr
*toaddr
)
3186 if (!flow_divert_is_sockaddr_valid(toaddr
)) {
3187 FDLOG(LOG_ERR
, &nil_pcb
, "Invalid target address, family = %u, length = %u", toaddr
->sa_family
, toaddr
->sa_len
);
3192 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_TARGET_ADDRESS
, toaddr
->sa_len
, toaddr
);
3197 if (toaddr
->sa_family
== AF_INET
) {
3198 port
= ntohs((satosin(toaddr
))->sin_port
);
3200 port
= ntohs((satosin6(toaddr
))->sin6_port
);
3203 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_TARGET_PORT
, sizeof(port
), &port
);
3213 flow_divert_get_buffered_target_address(mbuf_t buffer
)
3215 if (buffer
!= NULL
&& buffer
->m_type
== MT_SONAME
) {
3216 struct sockaddr
*toaddr
= mtod(buffer
, struct sockaddr
*);
3217 if (toaddr
!= NULL
&& flow_divert_is_sockaddr_valid(toaddr
)) {
3225 flow_divert_is_sockaddr_valid(struct sockaddr
*addr
)
3227 switch (addr
->sa_family
) {
3229 if (addr
->sa_len
< sizeof(struct sockaddr_in
)) {
3234 if (addr
->sa_len
< sizeof(struct sockaddr_in6
)) {
3245 flow_divert_dup_addr(sa_family_t family
, struct sockaddr
*addr
,
3246 struct sockaddr
**dup
)
3249 struct sockaddr
*result
;
3250 struct sockaddr_storage ss
;
3255 memset(&ss
, 0, sizeof(ss
));
3256 ss
.ss_family
= family
;
3257 if (ss
.ss_family
== AF_INET
) {
3258 ss
.ss_len
= sizeof(struct sockaddr_in
);
3259 } else if (ss
.ss_family
== AF_INET6
) {
3260 ss
.ss_len
= sizeof(struct sockaddr_in6
);
3264 result
= (struct sockaddr
*)&ss
;
3268 *dup
= dup_sockaddr(result
, 1);
3278 flow_divert_disconnect_socket(struct socket
*so
)
3280 soisdisconnected(so
);
3281 if (SOCK_TYPE(so
) == SOCK_DGRAM
) {
3282 struct inpcb
*inp
= NULL
;
3284 inp
= sotoinpcb(so
);
3286 if (SOCK_CHECK_DOM(so
, PF_INET6
)) {
3296 flow_divert_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
3298 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3300 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
3302 if (sopt
->sopt_name
== SO_TRAFFIC_CLASS
) {
3303 if (sopt
->sopt_dir
== SOPT_SET
&& fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
) {
3304 flow_divert_send_traffic_class_update(fd_cb
, so
->so_traffic_class
);
3308 if (SOCK_DOM(so
) == PF_INET
) {
3309 return g_tcp_protosw
->pr_ctloutput(so
, sopt
);
3310 } else if (SOCK_DOM(so
) == PF_INET6
) {
3311 return g_tcp6_protosw
->pr_ctloutput(so
, sopt
);
3317 flow_divert_connect_out_internal(struct socket
*so
, struct sockaddr
*to
, proc_t p
, bool implicit
)
3319 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3321 struct inpcb
*inp
= sotoinpcb(so
);
3322 struct sockaddr_in
*sinp
;
3323 mbuf_t connect_packet
= NULL
;
3326 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
3328 if (fd_cb
->group
== NULL
) {
3329 error
= ENETUNREACH
;
3336 } else if (inp
->inp_state
== INPCB_STATE_DEAD
) {
3338 error
= so
->so_error
;
3346 if (fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
) {
3351 FDLOG0(LOG_INFO
, fd_cb
, "Connecting");
3353 if (fd_cb
->connect_packet
== NULL
) {
3354 struct sockaddr_in sin
= {};
3355 struct ifnet
*ifp
= NULL
;
3358 FDLOG0(LOG_ERR
, fd_cb
, "No destination address available when creating connect packet");
3363 fd_cb
->original_remote_endpoint
= dup_sockaddr(to
, 0);
3364 if (fd_cb
->original_remote_endpoint
== NULL
) {
3365 FDLOG0(LOG_ERR
, fd_cb
, "Failed to dup the remote endpoint");
3369 fd_cb
->original_vflag
= inp
->inp_vflag
;
3370 fd_cb
->original_last_outifp
= inp
->inp_last_outifp
;
3371 fd_cb
->original_last_outifp6
= inp
->in6p_last_outifp
;
3373 sinp
= (struct sockaddr_in
*)(void *)to
;
3374 if (sinp
->sin_family
== AF_INET
&& IN_MULTICAST(ntohl(sinp
->sin_addr
.s_addr
))) {
3375 error
= EAFNOSUPPORT
;
3379 if (to
->sa_family
== AF_INET6
&& !(inp
->inp_flags
& IN6P_IPV6_V6ONLY
)) {
3380 struct sockaddr_in6 sin6
= {};
3381 sin6
.sin6_family
= AF_INET6
;
3382 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
3383 sin6
.sin6_port
= satosin6(to
)->sin6_port
;
3384 sin6
.sin6_addr
= satosin6(to
)->sin6_addr
;
3385 if (IN6_IS_ADDR_V4MAPPED(&(sin6
.sin6_addr
))) {
3386 in6_sin6_2_sin(&sin
, &sin6
);
3387 to
= (struct sockaddr
*)&sin
;
3391 if (to
->sa_family
== AF_INET6
) {
3392 inp
->inp_vflag
&= ~INP_IPV4
;
3393 inp
->inp_vflag
|= INP_IPV6
;
3394 fd_cb
->local_endpoint
.sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
3395 fd_cb
->local_endpoint
.sin6
.sin6_family
= AF_INET6
;
3396 fd_cb
->local_endpoint
.sin6
.sin6_port
= inp
->inp_lport
;
3397 error
= in6_pcbladdr(inp
, to
, &(fd_cb
->local_endpoint
.sin6
.sin6_addr
), &ifp
);
3399 FDLOG(LOG_WARNING
, fd_cb
, "failed to get a local IPv6 address: %d", error
);
3403 inp
->in6p_last_outifp
= ifp
;
3406 } else if (to
->sa_family
== AF_INET
) {
3407 inp
->inp_vflag
|= INP_IPV4
;
3408 inp
->inp_vflag
&= ~INP_IPV6
;
3409 fd_cb
->local_endpoint
.sin
.sin_len
= sizeof(struct sockaddr_in
);
3410 fd_cb
->local_endpoint
.sin
.sin_family
= AF_INET
;
3411 fd_cb
->local_endpoint
.sin
.sin_port
= inp
->inp_lport
;
3412 error
= in_pcbladdr(inp
, to
, &(fd_cb
->local_endpoint
.sin
.sin_addr
), IFSCOPE_NONE
, &ifp
, 0);
3414 FDLOG(LOG_WARNING
, fd_cb
, "failed to get a local IPv4 address: %d", error
);
3418 inp
->inp_last_outifp
= ifp
;
3422 FDLOG(LOG_WARNING
, fd_cb
, "target address has an unsupported family: %d", to
->sa_family
);
3425 error
= flow_divert_check_no_cellular(fd_cb
) ||
3426 flow_divert_check_no_expensive(fd_cb
) ||
3427 flow_divert_check_no_constrained(fd_cb
);
3432 if (SOCK_TYPE(so
) == SOCK_STREAM
|| /* TCP or */
3433 !implicit
|| /* connect() was called or */
3434 ((inp
->inp_vflag
& INP_IPV6
) && !IN6_IS_ADDR_UNSPECIFIED(&inp
->in6p_laddr
)) || /* local address is not un-specified */
3435 ((inp
->inp_vflag
& INP_IPV4
) && inp
->inp_laddr
.s_addr
!= INADDR_ANY
)) {
3436 fd_cb
->flags
|= FLOW_DIVERT_SHOULD_SET_LOCAL_ADDR
;
3439 error
= flow_divert_create_connect_packet(fd_cb
, to
, so
, p
, &connect_packet
);
3444 if (!implicit
|| SOCK_TYPE(so
) == SOCK_STREAM
) {
3445 flow_divert_set_remote_endpoint(fd_cb
, to
);
3446 flow_divert_set_local_endpoint(fd_cb
, &(fd_cb
->local_endpoint
.sa
));
3450 fd_cb
->flags
|= FLOW_DIVERT_IMPLICIT_CONNECT
;
3453 if (so
->so_flags1
& SOF1_PRECONNECT_DATA
) {
3454 FDLOG0(LOG_INFO
, fd_cb
, "Delaying sending the connect packet until send or receive");
3458 fd_cb
->connect_packet
= connect_packet
;
3459 connect_packet
= NULL
;
3461 FDLOG0(LOG_INFO
, fd_cb
, "Sending saved connect packet");
3465 error
= flow_divert_send_connect_packet(fd_cb
);
3470 fd_cb
->flags
|= FLOW_DIVERT_CONNECT_STARTED
;
3473 if (SOCK_TYPE(so
) == SOCK_DGRAM
&& !(fd_cb
->flags
& FLOW_DIVERT_HAS_TOKEN
)) {
3484 flow_divert_connect_out(struct socket
*so
, struct sockaddr
*to
, proc_t p
)
3487 if (SOCK_TYPE(so
) == SOCK_STREAM
&& !(so
->so_flags
& SOF_CONTENT_FILTER
)) {
3488 int error
= cfil_sock_attach(so
, NULL
, to
, CFS_CONNECTION_DIR_OUT
);
3490 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3491 FDLOG(LOG_ERR
, fd_cb
, "Failed to attach cfil: %d", error
);
3495 #endif /* CONTENT_FILTER */
3497 return flow_divert_connect_out_internal(so
, to
, p
, false);
3501 flow_divert_connectx_out_common(struct socket
*so
, struct sockaddr
*dst
,
3502 struct proc
*p
, sae_connid_t
*pcid
, struct uio
*auio
, user_ssize_t
*bytes_written
)
3504 struct inpcb
*inp
= sotoinpcb(so
);
3511 VERIFY(dst
!= NULL
);
3513 error
= flow_divert_connect_out(so
, dst
, p
);
3519 /* if there is data, send it */
3521 user_ssize_t datalen
= 0;
3523 socket_unlock(so
, 0);
3525 VERIFY(bytes_written
!= NULL
);
3527 datalen
= uio_resid(auio
);
3528 error
= so
->so_proto
->pr_usrreqs
->pru_sosend(so
, NULL
, (uio_t
)auio
, NULL
, NULL
, 0);
3531 if (error
== 0 || error
== EWOULDBLOCK
) {
3532 *bytes_written
= datalen
- uio_resid(auio
);
3536 * sosend returns EWOULDBLOCK if it's a non-blocking
3537 * socket or a timeout occured (this allows to return
3538 * the amount of queued data through sendit()).
3540 * However, connectx() returns EINPROGRESS in case of a
3541 * blocking socket. So we change the return value here.
3543 if (error
== EWOULDBLOCK
) {
3544 error
= EINPROGRESS
;
3548 if (error
== 0 && pcid
!= NULL
) {
3549 *pcid
= 1; /* there is only 1 connection for a TCP */
3556 flow_divert_connectx_out(struct socket
*so
, struct sockaddr
*src __unused
,
3557 struct sockaddr
*dst
, struct proc
*p
, uint32_t ifscope __unused
,
3558 sae_associd_t aid __unused
, sae_connid_t
*pcid
, uint32_t flags __unused
, void *arg __unused
,
3559 uint32_t arglen __unused
, struct uio
*uio
, user_ssize_t
*bytes_written
)
3561 return flow_divert_connectx_out_common(so
, dst
, p
, pcid
, uio
, bytes_written
);
3565 flow_divert_connectx6_out(struct socket
*so
, struct sockaddr
*src __unused
,
3566 struct sockaddr
*dst
, struct proc
*p
, uint32_t ifscope __unused
,
3567 sae_associd_t aid __unused
, sae_connid_t
*pcid
, uint32_t flags __unused
, void *arg __unused
,
3568 uint32_t arglen __unused
, struct uio
*uio
, user_ssize_t
*bytes_written
)
3570 return flow_divert_connectx_out_common(so
, dst
, p
, pcid
, uio
, bytes_written
);
3574 flow_divert_data_out(struct socket
*so
, int flags
, mbuf_t data
, struct sockaddr
*to
, mbuf_t control
, struct proc
*p
)
3576 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3580 struct m_tag
*cfil_tag
= NULL
;
3583 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
3585 inp
= sotoinpcb(so
);
3586 if (inp
== NULL
|| inp
->inp_state
== INPCB_STATE_DEAD
) {
3591 if (control
&& mbuf_len(control
) > 0) {
3596 if (flags
& MSG_OOB
) {
3598 goto done
; /* We don't support OOB data */
3603 * If the socket is subject to a UDP Content Filter and no remote address is passed in,
3604 * retrieve the CFIL saved remote address from the mbuf and use it.
3606 if (to
== NULL
&& so
->so_cfil_db
) {
3607 struct sockaddr
*cfil_faddr
= NULL
;
3608 cfil_tag
= cfil_dgram_get_socket_state(data
, NULL
, NULL
, &cfil_faddr
, NULL
);
3610 to
= (struct sockaddr
*)(void *)cfil_faddr
;
3612 FDLOG(LOG_INFO
, fd_cb
, "Using remote address from CFIL saved state: %p", to
);
3616 /* Implicit connect */
3617 if (!(fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
)) {
3618 FDLOG0(LOG_INFO
, fd_cb
, "implicit connect");
3620 error
= flow_divert_connect_out_internal(so
, to
, p
, true);
3625 error
= flow_divert_check_no_cellular(fd_cb
) ||
3626 flow_divert_check_no_expensive(fd_cb
) ||
3627 flow_divert_check_no_constrained(fd_cb
);
3633 FDLOG(LOG_DEBUG
, fd_cb
, "app wrote %lu bytes", mbuf_pkthdr_len(data
));
3635 fd_cb
->bytes_written_by_app
+= mbuf_pkthdr_len(data
);
3636 error
= flow_divert_send_app_data(fd_cb
, data
, to
);
3644 if (flags
& PRUS_EOF
) {
3645 flow_divert_shutdown(so
);
3657 m_tag_free(cfil_tag
);
3665 flow_divert_preconnect(struct socket
*so
)
3668 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3670 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
3672 if (!(fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
)) {
3673 FDLOG0(LOG_INFO
, fd_cb
, "Pre-connect read: sending saved connect packet");
3674 error
= flow_divert_send_connect_packet(so
->so_fd_pcb
);
3679 fd_cb
->flags
|= FLOW_DIVERT_CONNECT_STARTED
;
3682 soclearfastopen(so
);
3688 flow_divert_set_protosw(struct socket
*so
)
3690 if (SOCK_DOM(so
) == PF_INET
) {
3691 so
->so_proto
= &g_flow_divert_in_protosw
;
3693 so
->so_proto
= (struct protosw
*)&g_flow_divert_in6_protosw
;
3698 flow_divert_set_udp_protosw(struct socket
*so
)
3700 if (SOCK_DOM(so
) == PF_INET
) {
3701 so
->so_proto
= &g_flow_divert_in_udp_protosw
;
3703 so
->so_proto
= (struct protosw
*)&g_flow_divert_in6_udp_protosw
;
3708 flow_divert_implicit_data_out(struct socket
*so
, int flags
, mbuf_t data
, struct sockaddr
*to
, mbuf_t control
, struct proc
*p
)
3710 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3714 inp
= sotoinpcb(so
);
3719 if (fd_cb
== NULL
) {
3720 error
= flow_divert_pcb_init(so
);
3721 fd_cb
= so
->so_fd_pcb
;
3722 if (error
!= 0 || fd_cb
== NULL
) {
3726 return flow_divert_data_out(so
, flags
, data
, to
, control
, p
);
3740 flow_divert_pcb_init_internal(struct socket
*so
, uint32_t ctl_unit
, uint32_t aggregate_unit
)
3743 struct flow_divert_pcb
*fd_cb
;
3744 uint32_t agg_unit
= aggregate_unit
;
3745 uint32_t group_unit
= flow_divert_derive_kernel_control_unit(ctl_unit
, &agg_unit
);
3747 if (group_unit
== 0) {
3751 if (so
->so_flags
& SOF_FLOW_DIVERT
) {
3755 fd_cb
= flow_divert_pcb_create(so
);
3756 if (fd_cb
!= NULL
) {
3757 so
->so_fd_pcb
= fd_cb
;
3758 so
->so_flags
|= SOF_FLOW_DIVERT
;
3759 fd_cb
->control_group_unit
= group_unit
;
3760 fd_cb
->policy_control_unit
= ctl_unit
;
3761 fd_cb
->aggregate_unit
= agg_unit
;
3763 error
= flow_divert_pcb_insert(fd_cb
, group_unit
);
3765 FDLOG(LOG_ERR
, fd_cb
, "pcb insert failed: %d", error
);
3766 so
->so_fd_pcb
= NULL
;
3767 so
->so_flags
&= ~SOF_FLOW_DIVERT
;
3770 if (SOCK_TYPE(so
) == SOCK_STREAM
) {
3771 flow_divert_set_protosw(so
);
3772 } else if (SOCK_TYPE(so
) == SOCK_DGRAM
) {
3773 flow_divert_set_udp_protosw(so
);
3776 FDLOG0(LOG_INFO
, fd_cb
, "Created");
3786 flow_divert_pcb_init(struct socket
*so
)
3788 struct inpcb
*inp
= sotoinpcb(so
);
3789 uint32_t aggregate_units
= 0;
3790 uint32_t ctl_unit
= necp_socket_get_flow_divert_control_unit(inp
, &aggregate_units
);
3791 return flow_divert_pcb_init_internal(so
, ctl_unit
, aggregate_units
);
3795 flow_divert_token_set(struct socket
*so
, struct sockopt
*sopt
)
3797 uint32_t ctl_unit
= 0;
3798 uint32_t key_unit
= 0;
3799 uint32_t aggregate_unit
= 0;
3802 mbuf_t token
= NULL
;
3804 if (so
->so_flags
& SOF_FLOW_DIVERT
) {
3809 if (g_init_result
) {
3810 FDLOG(LOG_ERR
, &nil_pcb
, "flow_divert_init failed (%d), cannot use flow divert", g_init_result
);
3811 error
= ENOPROTOOPT
;
3815 if ((SOCK_TYPE(so
) != SOCK_STREAM
&& SOCK_TYPE(so
) != SOCK_DGRAM
) ||
3816 (SOCK_PROTO(so
) != IPPROTO_TCP
&& SOCK_PROTO(so
) != IPPROTO_UDP
) ||
3817 (SOCK_DOM(so
) != PF_INET
&& SOCK_DOM(so
) != PF_INET6
)) {
3821 if (SOCK_TYPE(so
) == SOCK_STREAM
&& SOCK_PROTO(so
) == IPPROTO_TCP
) {
3822 struct tcpcb
*tp
= sototcpcb(so
);
3823 if (tp
== NULL
|| tp
->t_state
!= TCPS_CLOSED
) {
3830 error
= soopt_getm(sopt
, &token
);
3836 error
= soopt_mcopyin(sopt
, token
);
3842 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_KEY_UNIT
, sizeof(key_unit
), (void *)&key_unit
, NULL
);
3844 key_unit
= ntohl(key_unit
);
3845 if (key_unit
>= GROUP_COUNT_MAX
) {
3848 } else if (error
!= ENOENT
) {
3849 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to get the key unit from the token: %d", error
);
3855 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), (void *)&ctl_unit
, NULL
);
3857 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to get the control socket unit from the token: %d", error
);
3861 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_AGGREGATE_UNIT
, sizeof(aggregate_unit
), (void *)&aggregate_unit
, NULL
);
3862 if (error
&& error
!= ENOENT
) {
3863 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to get the aggregate unit from the token: %d", error
);
3867 /* A valid kernel control unit is required */
3868 ctl_unit
= ntohl(ctl_unit
);
3869 aggregate_unit
= ntohl(aggregate_unit
);
3871 if (ctl_unit
> 0 && ctl_unit
< GROUP_COUNT_MAX
) {
3872 socket_unlock(so
, 0);
3873 hmac_error
= flow_divert_packet_verify_hmac(token
, (key_unit
!= 0 ? key_unit
: ctl_unit
));
3876 if (hmac_error
&& hmac_error
!= ENOENT
) {
3877 FDLOG(LOG_ERR
, &nil_pcb
, "HMAC verfication failed: %d", hmac_error
);
3883 error
= flow_divert_pcb_init_internal(so
, ctl_unit
, aggregate_unit
);
3885 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3886 int log_level
= LOG_NOTICE
;
3888 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_LOG_LEVEL
, sizeof(log_level
), &log_level
, NULL
);
3890 fd_cb
->log_level
= (uint8_t)log_level
;
3894 fd_cb
->connect_token
= token
;
3897 fd_cb
->flags
|= FLOW_DIVERT_HAS_TOKEN
;
3900 if (hmac_error
== 0) {
3901 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3902 if (fd_cb
!= NULL
) {
3903 fd_cb
->flags
|= FLOW_DIVERT_HAS_HMAC
;
3908 if (token
!= NULL
) {
3916 flow_divert_token_get(struct socket
*so
, struct sockopt
*sopt
)
3920 uint8_t hmac
[SHA_DIGEST_LENGTH
];
3921 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3922 mbuf_t token
= NULL
;
3923 struct flow_divert_group
*control_group
= NULL
;
3925 if (!(so
->so_flags
& SOF_FLOW_DIVERT
)) {
3930 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
3932 if (fd_cb
->group
== NULL
) {
3937 error
= mbuf_gethdr(MBUF_DONTWAIT
, MBUF_TYPE_HEADER
, &token
);
3939 FDLOG(LOG_ERR
, fd_cb
, "failed to allocate the header mbuf: %d", error
);
3943 ctl_unit
= htonl(fd_cb
->group
->ctl_unit
);
3945 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), &ctl_unit
);
3950 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_FLOW_ID
, sizeof(fd_cb
->hash
), &fd_cb
->hash
);
3955 if (fd_cb
->app_data
!= NULL
) {
3956 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_APP_DATA
, (uint32_t)fd_cb
->app_data_length
, fd_cb
->app_data
);
3962 socket_unlock(so
, 0);
3963 lck_rw_lock_shared(&g_flow_divert_group_lck
);
3965 if (g_flow_divert_groups
!= NULL
&& g_active_group_count
> 0 &&
3966 fd_cb
->control_group_unit
> 0 && fd_cb
->control_group_unit
< GROUP_COUNT_MAX
) {
3967 control_group
= g_flow_divert_groups
[fd_cb
->control_group_unit
];
3970 if (control_group
!= NULL
) {
3971 lck_rw_lock_shared(&control_group
->lck
);
3972 ctl_unit
= htonl(control_group
->ctl_unit
);
3973 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_KEY_UNIT
, sizeof(ctl_unit
), &ctl_unit
);
3975 error
= flow_divert_packet_compute_hmac(token
, control_group
, hmac
);
3977 lck_rw_done(&control_group
->lck
);
3979 error
= ENOPROTOOPT
;
3982 lck_rw_done(&g_flow_divert_group_lck
);
3989 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_HMAC
, sizeof(hmac
), hmac
);
3994 if (sopt
->sopt_val
== USER_ADDR_NULL
) {
3995 /* If the caller passed NULL to getsockopt, just set the size of the token and return */
3996 sopt
->sopt_valsize
= mbuf_pkthdr_len(token
);
4000 error
= soopt_mcopyout(sopt
, token
);
4002 token
= NULL
; /* For some reason, soopt_mcopyout() frees the mbuf if it fails */
4007 if (token
!= NULL
) {
4015 flow_divert_kctl_connect(kern_ctl_ref kctlref __unused
, struct sockaddr_ctl
*sac
, void **unitinfo
)
4017 struct flow_divert_group
*new_group
= NULL
;
4020 if (sac
->sc_unit
>= GROUP_COUNT_MAX
) {
4027 new_group
= zalloc_flags(flow_divert_group_zone
, Z_WAITOK
| Z_ZERO
);
4028 lck_rw_init(&new_group
->lck
, flow_divert_mtx_grp
, flow_divert_mtx_attr
);
4029 RB_INIT(&new_group
->pcb_tree
);
4030 new_group
->ctl_unit
= sac
->sc_unit
;
4031 MBUFQ_INIT(&new_group
->send_queue
);
4032 new_group
->signing_id_trie
.root
= NULL_TRIE_IDX
;
4034 lck_rw_lock_exclusive(&g_flow_divert_group_lck
);
4036 if (g_flow_divert_groups
== NULL
) {
4037 MALLOC(g_flow_divert_groups
,
4038 struct flow_divert_group
**,
4039 GROUP_COUNT_MAX
* sizeof(struct flow_divert_group
*),
4044 if (g_flow_divert_groups
== NULL
) {
4046 } else if (g_flow_divert_groups
[sac
->sc_unit
] != NULL
) {
4049 g_flow_divert_groups
[sac
->sc_unit
] = new_group
;
4050 g_active_group_count
++;
4053 lck_rw_done(&g_flow_divert_group_lck
);
4057 *unitinfo
= new_group
;
4058 } else if (new_group
!= NULL
) {
4059 zfree(flow_divert_group_zone
, new_group
);
4065 flow_divert_kctl_disconnect(kern_ctl_ref kctlref __unused
, uint32_t unit
, void *unitinfo
)
4067 struct flow_divert_group
*group
= NULL
;
4070 if (unit
>= GROUP_COUNT_MAX
) {
4074 if (unitinfo
== NULL
) {
4078 FDLOG(LOG_INFO
, &nil_pcb
, "disconnecting group %d", unit
);
4080 lck_rw_lock_exclusive(&g_flow_divert_group_lck
);
4082 if (g_flow_divert_groups
== NULL
|| g_active_group_count
== 0) {
4083 panic("flow divert group %u is disconnecting, but no groups are active (groups = %p, active count = %u", unit
,
4084 g_flow_divert_groups
, g_active_group_count
);
4087 group
= g_flow_divert_groups
[unit
];
4089 if (group
!= (struct flow_divert_group
*)unitinfo
) {
4090 panic("group with unit %d (%p) != unit info (%p)", unit
, group
, unitinfo
);
4093 g_flow_divert_groups
[unit
] = NULL
;
4094 g_active_group_count
--;
4096 if (g_active_group_count
== 0) {
4097 FREE(g_flow_divert_groups
, M_TEMP
);
4098 g_flow_divert_groups
= NULL
;
4101 lck_rw_done(&g_flow_divert_group_lck
);
4103 if (group
!= NULL
) {
4104 flow_divert_close_all(group
);
4106 lck_rw_lock_exclusive(&group
->lck
);
4108 if (group
->token_key
!= NULL
) {
4109 memset(group
->token_key
, 0, group
->token_key_size
);
4110 FREE(group
->token_key
, M_TEMP
);
4111 group
->token_key
= NULL
;
4112 group
->token_key_size
= 0;
4115 /* Re-set the current trie */
4116 if (group
->signing_id_trie
.memory
!= NULL
) {
4117 FREE(group
->signing_id_trie
.memory
, M_TEMP
);
4119 memset(&group
->signing_id_trie
, 0, sizeof(group
->signing_id_trie
));
4120 group
->signing_id_trie
.root
= NULL_TRIE_IDX
;
4122 lck_rw_done(&group
->lck
);
4124 zfree(flow_divert_group_zone
, group
);
4133 flow_divert_kctl_send(kern_ctl_ref kctlref __unused
, uint32_t unit __unused
, void *unitinfo
, mbuf_t m
, int flags __unused
)
4135 return flow_divert_input(m
, (struct flow_divert_group
*)unitinfo
);
4139 flow_divert_kctl_rcvd(kern_ctl_ref kctlref __unused
, uint32_t unit __unused
, void *unitinfo
, int flags __unused
)
4141 struct flow_divert_group
*group
= (struct flow_divert_group
*)unitinfo
;
4143 if (!OSTestAndClear(GROUP_BIT_CTL_ENQUEUE_BLOCKED
, &group
->atomic_bits
)) {
4144 struct flow_divert_pcb
*fd_cb
;
4145 SLIST_HEAD(, flow_divert_pcb
) tmp_list
;
4147 lck_rw_lock_shared(&g_flow_divert_group_lck
);
4148 lck_rw_lock_exclusive(&group
->lck
);
4150 while (!MBUFQ_EMPTY(&group
->send_queue
)) {
4152 FDLOG0(LOG_DEBUG
, &nil_pcb
, "trying ctl_enqueuembuf again");
4153 next_packet
= MBUFQ_FIRST(&group
->send_queue
);
4154 int error
= ctl_enqueuembuf(g_flow_divert_kctl_ref
, group
->ctl_unit
, next_packet
, CTL_DATA_EOR
);
4156 FDLOG(LOG_DEBUG
, &nil_pcb
, "ctl_enqueuembuf returned an error: %d", error
);
4157 OSTestAndSet(GROUP_BIT_CTL_ENQUEUE_BLOCKED
, &group
->atomic_bits
);
4158 lck_rw_done(&group
->lck
);
4159 lck_rw_done(&g_flow_divert_group_lck
);
4162 MBUFQ_DEQUEUE(&group
->send_queue
, next_packet
);
4165 SLIST_INIT(&tmp_list
);
4167 RB_FOREACH(fd_cb
, fd_pcb_tree
, &group
->pcb_tree
) {
4169 SLIST_INSERT_HEAD(&tmp_list
, fd_cb
, tmp_list_entry
);
4172 lck_rw_done(&group
->lck
);
4174 SLIST_FOREACH(fd_cb
, &tmp_list
, tmp_list_entry
) {
4176 if (fd_cb
->so
!= NULL
) {
4177 socket_lock(fd_cb
->so
, 0);
4178 if (fd_cb
->group
!= NULL
) {
4179 flow_divert_send_buffered_data(fd_cb
, FALSE
);
4181 socket_unlock(fd_cb
->so
, 0);
4187 lck_rw_done(&g_flow_divert_group_lck
);
4192 flow_divert_kctl_init(void)
4194 struct kern_ctl_reg ctl_reg
;
4197 memset(&ctl_reg
, 0, sizeof(ctl_reg
));
4199 strlcpy(ctl_reg
.ctl_name
, FLOW_DIVERT_CONTROL_NAME
, sizeof(ctl_reg
.ctl_name
));
4200 ctl_reg
.ctl_name
[sizeof(ctl_reg
.ctl_name
) - 1] = '\0';
4201 ctl_reg
.ctl_flags
= CTL_FLAG_PRIVILEGED
| CTL_FLAG_REG_EXTENDED
;
4202 ctl_reg
.ctl_sendsize
= FD_CTL_SENDBUFF_SIZE
;
4203 ctl_reg
.ctl_recvsize
= FD_CTL_RCVBUFF_SIZE
;
4205 ctl_reg
.ctl_connect
= flow_divert_kctl_connect
;
4206 ctl_reg
.ctl_disconnect
= flow_divert_kctl_disconnect
;
4207 ctl_reg
.ctl_send
= flow_divert_kctl_send
;
4208 ctl_reg
.ctl_rcvd
= flow_divert_kctl_rcvd
;
4210 result
= ctl_register(&ctl_reg
, &g_flow_divert_kctl_ref
);
4213 FDLOG(LOG_ERR
, &nil_pcb
, "flow_divert_kctl_init - ctl_register failed: %d\n", result
);
4221 flow_divert_init(void)
4223 memset(&nil_pcb
, 0, sizeof(nil_pcb
));
4224 nil_pcb
.log_level
= LOG_NOTICE
;
4226 g_tcp_protosw
= pffindproto(AF_INET
, IPPROTO_TCP
, SOCK_STREAM
);
4228 VERIFY(g_tcp_protosw
!= NULL
);
4230 memcpy(&g_flow_divert_in_protosw
, g_tcp_protosw
, sizeof(g_flow_divert_in_protosw
));
4231 memcpy(&g_flow_divert_in_usrreqs
, g_tcp_protosw
->pr_usrreqs
, sizeof(g_flow_divert_in_usrreqs
));
4233 g_flow_divert_in_usrreqs
.pru_connect
= flow_divert_connect_out
;
4234 g_flow_divert_in_usrreqs
.pru_connectx
= flow_divert_connectx_out
;
4235 g_flow_divert_in_usrreqs
.pru_disconnect
= flow_divert_close
;
4236 g_flow_divert_in_usrreqs
.pru_disconnectx
= flow_divert_disconnectx
;
4237 g_flow_divert_in_usrreqs
.pru_rcvd
= flow_divert_rcvd
;
4238 g_flow_divert_in_usrreqs
.pru_send
= flow_divert_data_out
;
4239 g_flow_divert_in_usrreqs
.pru_shutdown
= flow_divert_shutdown
;
4240 g_flow_divert_in_usrreqs
.pru_preconnect
= flow_divert_preconnect
;
4242 g_flow_divert_in_protosw
.pr_usrreqs
= &g_flow_divert_in_usrreqs
;
4243 g_flow_divert_in_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
4246 * Socket filters shouldn't attach/detach to/from this protosw
4247 * since pr_protosw is to be used instead, which points to the
4248 * real protocol; if they do, it is a bug and we should panic.
4250 g_flow_divert_in_protosw
.pr_filter_head
.tqh_first
=
4251 (struct socket_filter
*)(uintptr_t)0xdeadbeefdeadbeef;
4252 g_flow_divert_in_protosw
.pr_filter_head
.tqh_last
=
4253 (struct socket_filter
**)(uintptr_t)0xdeadbeefdeadbeef;
4256 g_udp_protosw
= pffindproto(AF_INET
, IPPROTO_UDP
, SOCK_DGRAM
);
4257 VERIFY(g_udp_protosw
!= NULL
);
4259 memcpy(&g_flow_divert_in_udp_protosw
, g_udp_protosw
, sizeof(g_flow_divert_in_udp_protosw
));
4260 memcpy(&g_flow_divert_in_udp_usrreqs
, g_udp_protosw
->pr_usrreqs
, sizeof(g_flow_divert_in_udp_usrreqs
));
4262 g_flow_divert_in_udp_usrreqs
.pru_connect
= flow_divert_connect_out
;
4263 g_flow_divert_in_udp_usrreqs
.pru_connectx
= flow_divert_connectx_out
;
4264 g_flow_divert_in_udp_usrreqs
.pru_disconnect
= flow_divert_close
;
4265 g_flow_divert_in_udp_usrreqs
.pru_disconnectx
= flow_divert_disconnectx
;
4266 g_flow_divert_in_udp_usrreqs
.pru_rcvd
= flow_divert_rcvd
;
4267 g_flow_divert_in_udp_usrreqs
.pru_send
= flow_divert_data_out
;
4268 g_flow_divert_in_udp_usrreqs
.pru_shutdown
= flow_divert_shutdown
;
4269 g_flow_divert_in_udp_usrreqs
.pru_sosend_list
= pru_sosend_list_notsupp
;
4270 g_flow_divert_in_udp_usrreqs
.pru_soreceive_list
= pru_soreceive_list_notsupp
;
4271 g_flow_divert_in_udp_usrreqs
.pru_preconnect
= flow_divert_preconnect
;
4273 g_flow_divert_in_udp_protosw
.pr_usrreqs
= &g_flow_divert_in_usrreqs
;
4274 g_flow_divert_in_udp_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
4277 * Socket filters shouldn't attach/detach to/from this protosw
4278 * since pr_protosw is to be used instead, which points to the
4279 * real protocol; if they do, it is a bug and we should panic.
4281 g_flow_divert_in_udp_protosw
.pr_filter_head
.tqh_first
=
4282 (struct socket_filter
*)(uintptr_t)0xdeadbeefdeadbeef;
4283 g_flow_divert_in_udp_protosw
.pr_filter_head
.tqh_last
=
4284 (struct socket_filter
**)(uintptr_t)0xdeadbeefdeadbeef;
4286 g_tcp6_protosw
= (struct ip6protosw
*)pffindproto(AF_INET6
, IPPROTO_TCP
, SOCK_STREAM
);
4288 VERIFY(g_tcp6_protosw
!= NULL
);
4290 memcpy(&g_flow_divert_in6_protosw
, g_tcp6_protosw
, sizeof(g_flow_divert_in6_protosw
));
4291 memcpy(&g_flow_divert_in6_usrreqs
, g_tcp6_protosw
->pr_usrreqs
, sizeof(g_flow_divert_in6_usrreqs
));
4293 g_flow_divert_in6_usrreqs
.pru_connect
= flow_divert_connect_out
;
4294 g_flow_divert_in6_usrreqs
.pru_connectx
= flow_divert_connectx6_out
;
4295 g_flow_divert_in6_usrreqs
.pru_disconnect
= flow_divert_close
;
4296 g_flow_divert_in6_usrreqs
.pru_disconnectx
= flow_divert_disconnectx
;
4297 g_flow_divert_in6_usrreqs
.pru_rcvd
= flow_divert_rcvd
;
4298 g_flow_divert_in6_usrreqs
.pru_send
= flow_divert_data_out
;
4299 g_flow_divert_in6_usrreqs
.pru_shutdown
= flow_divert_shutdown
;
4300 g_flow_divert_in6_usrreqs
.pru_preconnect
= flow_divert_preconnect
;
4302 g_flow_divert_in6_protosw
.pr_usrreqs
= &g_flow_divert_in6_usrreqs
;
4303 g_flow_divert_in6_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
4305 * Socket filters shouldn't attach/detach to/from this protosw
4306 * since pr_protosw is to be used instead, which points to the
4307 * real protocol; if they do, it is a bug and we should panic.
4309 g_flow_divert_in6_protosw
.pr_filter_head
.tqh_first
=
4310 (struct socket_filter
*)(uintptr_t)0xdeadbeefdeadbeef;
4311 g_flow_divert_in6_protosw
.pr_filter_head
.tqh_last
=
4312 (struct socket_filter
**)(uintptr_t)0xdeadbeefdeadbeef;
4315 g_udp6_protosw
= (struct ip6protosw
*)pffindproto(AF_INET6
, IPPROTO_UDP
, SOCK_DGRAM
);
4317 VERIFY(g_udp6_protosw
!= NULL
);
4319 memcpy(&g_flow_divert_in6_udp_protosw
, g_udp6_protosw
, sizeof(g_flow_divert_in6_udp_protosw
));
4320 memcpy(&g_flow_divert_in6_udp_usrreqs
, g_udp6_protosw
->pr_usrreqs
, sizeof(g_flow_divert_in6_udp_usrreqs
));
4322 g_flow_divert_in6_udp_usrreqs
.pru_connect
= flow_divert_connect_out
;
4323 g_flow_divert_in6_udp_usrreqs
.pru_connectx
= flow_divert_connectx6_out
;
4324 g_flow_divert_in6_udp_usrreqs
.pru_disconnect
= flow_divert_close
;
4325 g_flow_divert_in6_udp_usrreqs
.pru_disconnectx
= flow_divert_disconnectx
;
4326 g_flow_divert_in6_udp_usrreqs
.pru_rcvd
= flow_divert_rcvd
;
4327 g_flow_divert_in6_udp_usrreqs
.pru_send
= flow_divert_data_out
;
4328 g_flow_divert_in6_udp_usrreqs
.pru_shutdown
= flow_divert_shutdown
;
4329 g_flow_divert_in6_udp_usrreqs
.pru_sosend_list
= pru_sosend_list_notsupp
;
4330 g_flow_divert_in6_udp_usrreqs
.pru_soreceive_list
= pru_soreceive_list_notsupp
;
4331 g_flow_divert_in6_udp_usrreqs
.pru_preconnect
= flow_divert_preconnect
;
4333 g_flow_divert_in6_udp_protosw
.pr_usrreqs
= &g_flow_divert_in6_udp_usrreqs
;
4334 g_flow_divert_in6_udp_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
4336 * Socket filters shouldn't attach/detach to/from this protosw
4337 * since pr_protosw is to be used instead, which points to the
4338 * real protocol; if they do, it is a bug and we should panic.
4340 g_flow_divert_in6_udp_protosw
.pr_filter_head
.tqh_first
=
4341 (struct socket_filter
*)(uintptr_t)0xdeadbeefdeadbeef;
4342 g_flow_divert_in6_udp_protosw
.pr_filter_head
.tqh_last
=
4343 (struct socket_filter
**)(uintptr_t)0xdeadbeefdeadbeef;
4345 flow_divert_grp_attr
= lck_grp_attr_alloc_init();
4346 if (flow_divert_grp_attr
== NULL
) {
4347 FDLOG0(LOG_ERR
, &nil_pcb
, "lck_grp_attr_alloc_init failed");
4348 g_init_result
= ENOMEM
;
4352 flow_divert_mtx_grp
= lck_grp_alloc_init(FLOW_DIVERT_CONTROL_NAME
, flow_divert_grp_attr
);
4353 if (flow_divert_mtx_grp
== NULL
) {
4354 FDLOG0(LOG_ERR
, &nil_pcb
, "lck_grp_alloc_init failed");
4355 g_init_result
= ENOMEM
;
4359 flow_divert_mtx_attr
= lck_attr_alloc_init();
4360 if (flow_divert_mtx_attr
== NULL
) {
4361 FDLOG0(LOG_ERR
, &nil_pcb
, "lck_attr_alloc_init failed");
4362 g_init_result
= ENOMEM
;
4366 g_init_result
= flow_divert_kctl_init();
4367 if (g_init_result
) {
4371 lck_rw_init(&g_flow_divert_group_lck
, flow_divert_mtx_grp
, flow_divert_mtx_attr
);
4374 if (g_init_result
!= 0) {
4375 if (flow_divert_mtx_attr
!= NULL
) {
4376 lck_attr_free(flow_divert_mtx_attr
);
4377 flow_divert_mtx_attr
= NULL
;
4379 if (flow_divert_mtx_grp
!= NULL
) {
4380 lck_grp_free(flow_divert_mtx_grp
);
4381 flow_divert_mtx_grp
= NULL
;
4383 if (flow_divert_grp_attr
!= NULL
) {
4384 lck_grp_attr_free(flow_divert_grp_attr
);
4385 flow_divert_grp_attr
= NULL
;
4388 if (g_flow_divert_kctl_ref
!= NULL
) {
4389 ctl_deregister(g_flow_divert_kctl_ref
);
4390 g_flow_divert_kctl_ref
= NULL
;