2 * Copyright (c) 2012-2017 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include <sys/types.h>
31 #include <sys/syslog.h>
32 #include <sys/queue.h>
33 #include <sys/malloc.h>
34 #include <sys/socket.h>
35 #include <sys/kpi_mbuf.h>
37 #include <sys/domain.h>
38 #include <sys/protosw.h>
39 #include <sys/socketvar.h>
40 #include <sys/kernel.h>
41 #include <sys/systm.h>
42 #include <sys/kern_control.h>
44 #include <sys/codesign.h>
45 #include <libkern/tree.h>
46 #include <kern/locks.h>
47 #include <kern/debug.h>
48 #include <net/if_var.h>
49 #include <net/route.h>
50 #include <net/flowhash.h>
51 #include <net/ntstat.h>
52 #include <netinet/in.h>
53 #include <netinet/in_var.h>
54 #include <netinet/tcp.h>
55 #include <netinet/tcp_var.h>
56 #include <netinet/tcp_fsm.h>
57 #include <netinet/flow_divert.h>
58 #include <netinet/flow_divert_proto.h>
60 #include <netinet6/in6_pcb.h>
61 #include <netinet6/ip6protosw.h>
63 #include <dev/random/randomdev.h>
64 #include <libkern/crypto/sha1.h>
65 #include <libkern/crypto/crypto_internal.h>
68 #define FLOW_DIVERT_CONNECT_STARTED 0x00000001
69 #define FLOW_DIVERT_READ_CLOSED 0x00000002
70 #define FLOW_DIVERT_WRITE_CLOSED 0x00000004
71 #define FLOW_DIVERT_TUNNEL_RD_CLOSED 0x00000008
72 #define FLOW_DIVERT_TUNNEL_WR_CLOSED 0x00000010
73 #define FLOW_DIVERT_TRANSFERRED 0x00000020
74 #define FLOW_DIVERT_HAS_HMAC 0x00000040
76 #define FDLOG(level, pcb, format, ...) \
77 os_log_with_type(OS_LOG_DEFAULT, flow_divert_syslog_type_to_oslog_type(level), "(%u): " format "\n", (pcb)->hash, __VA_ARGS__)
79 #define FDLOG0(level, pcb, msg) \
80 os_log_with_type(OS_LOG_DEFAULT, flow_divert_syslog_type_to_oslog_type(level), "(%u): " msg "\n", (pcb)->hash)
82 #define FDRETAIN(pcb) if ((pcb) != NULL) OSIncrementAtomic(&(pcb)->ref_count)
83 #define FDRELEASE(pcb) \
85 if ((pcb) != NULL && 1 == OSDecrementAtomic(&(pcb)->ref_count)) { \
86 flow_divert_pcb_destroy(pcb); \
90 #define FDLOCK(pcb) lck_mtx_lock(&(pcb)->mtx)
91 #define FDUNLOCK(pcb) lck_mtx_unlock(&(pcb)->mtx)
93 #define FD_CTL_SENDBUFF_SIZE (128 * 1024)
94 #define FD_CTL_RCVBUFF_SIZE (128 * 1024)
96 #define GROUP_BIT_CTL_ENQUEUE_BLOCKED 0
98 #define GROUP_COUNT_MAX 32
99 #define FLOW_DIVERT_MAX_NAME_SIZE 4096
100 #define FLOW_DIVERT_MAX_KEY_SIZE 1024
101 #define FLOW_DIVERT_MAX_TRIE_MEMORY (1024 * 1024)
103 struct flow_divert_trie_node
{
109 #define CHILD_MAP_SIZE 256
110 #define NULL_TRIE_IDX 0xffff
111 #define TRIE_NODE(t, i) ((t)->nodes[(i)])
112 #define TRIE_CHILD(t, i, b) (((t)->child_maps + (CHILD_MAP_SIZE * TRIE_NODE(t, i).child_map))[(b)])
113 #define TRIE_BYTE(t, i) ((t)->bytes[(i)])
115 static struct flow_divert_pcb nil_pcb
;
117 decl_lck_rw_data(static, g_flow_divert_group_lck
);
118 static struct flow_divert_group
**g_flow_divert_groups
= NULL
;
119 static uint32_t g_active_group_count
= 0;
121 static lck_grp_attr_t
*flow_divert_grp_attr
= NULL
;
122 static lck_attr_t
*flow_divert_mtx_attr
= NULL
;
123 static lck_grp_t
*flow_divert_mtx_grp
= NULL
;
124 static errno_t g_init_result
= 0;
126 static kern_ctl_ref g_flow_divert_kctl_ref
= NULL
;
128 static struct protosw g_flow_divert_in_protosw
;
129 static struct pr_usrreqs g_flow_divert_in_usrreqs
;
130 static struct protosw g_flow_divert_in_udp_protosw
;
131 static struct pr_usrreqs g_flow_divert_in_udp_usrreqs
;
133 static struct ip6protosw g_flow_divert_in6_protosw
;
134 static struct pr_usrreqs g_flow_divert_in6_usrreqs
;
135 static struct ip6protosw g_flow_divert_in6_udp_protosw
;
136 static struct pr_usrreqs g_flow_divert_in6_udp_usrreqs
;
139 static struct protosw
*g_tcp_protosw
= NULL
;
140 static struct ip6protosw
*g_tcp6_protosw
= NULL
;
141 static struct protosw
*g_udp_protosw
= NULL
;
142 static struct ip6protosw
*g_udp6_protosw
= NULL
;
145 flow_divert_dup_addr(sa_family_t family
, struct sockaddr
*addr
, struct sockaddr
**dup
);
148 flow_divert_inp_to_sockaddr(const struct inpcb
*inp
, struct sockaddr
**local_socket
);
151 flow_divert_is_sockaddr_valid(struct sockaddr
*addr
);
154 flow_divert_append_target_endpoint_tlv(mbuf_t connect_packet
, struct sockaddr
*toaddr
);
157 flow_divert_get_buffered_target_address(mbuf_t buffer
);
160 flow_divert_has_pcb_local_address(const struct inpcb
*inp
);
163 flow_divert_disconnect_socket(struct socket
*so
);
165 static inline uint8_t
166 flow_divert_syslog_type_to_oslog_type(int syslog_type
)
168 switch (syslog_type
) {
169 case LOG_ERR
: return OS_LOG_TYPE_ERROR
;
170 case LOG_INFO
: return OS_LOG_TYPE_INFO
;
171 case LOG_DEBUG
: return OS_LOG_TYPE_DEBUG
;
172 default: return OS_LOG_TYPE_DEFAULT
;
177 flow_divert_pcb_cmp(const struct flow_divert_pcb
*pcb_a
, const struct flow_divert_pcb
*pcb_b
)
179 return memcmp(&pcb_a
->hash
, &pcb_b
->hash
, sizeof(pcb_a
->hash
));
182 RB_PROTOTYPE(fd_pcb_tree
, flow_divert_pcb
, rb_link
, flow_divert_pcb_cmp
);
183 RB_GENERATE(fd_pcb_tree
, flow_divert_pcb
, rb_link
, flow_divert_pcb_cmp
);
186 flow_divert_packet_type2str(uint8_t packet_type
)
188 switch (packet_type
) {
189 case FLOW_DIVERT_PKT_CONNECT
:
191 case FLOW_DIVERT_PKT_CONNECT_RESULT
:
192 return "connect result";
193 case FLOW_DIVERT_PKT_DATA
:
195 case FLOW_DIVERT_PKT_CLOSE
:
197 case FLOW_DIVERT_PKT_READ_NOTIFY
:
198 return "read notification";
199 case FLOW_DIVERT_PKT_PROPERTIES_UPDATE
:
200 return "properties update";
201 case FLOW_DIVERT_PKT_APP_MAP_CREATE
:
202 return "app map create";
208 static struct flow_divert_pcb
*
209 flow_divert_pcb_lookup(uint32_t hash
, struct flow_divert_group
*group
)
211 struct flow_divert_pcb key_item
;
212 struct flow_divert_pcb
*fd_cb
= NULL
;
214 key_item
.hash
= hash
;
216 lck_rw_lock_shared(&group
->lck
);
217 fd_cb
= RB_FIND(fd_pcb_tree
, &group
->pcb_tree
, &key_item
);
219 lck_rw_done(&group
->lck
);
225 flow_divert_pcb_insert(struct flow_divert_pcb
*fd_cb
, uint32_t ctl_unit
)
228 struct flow_divert_pcb
*exist
= NULL
;
229 struct flow_divert_group
*group
;
230 static uint32_t g_nextkey
= 1;
231 static uint32_t g_hash_seed
= 0;
234 if (ctl_unit
== 0 || ctl_unit
>= GROUP_COUNT_MAX
) {
238 socket_unlock(fd_cb
->so
, 0);
239 lck_rw_lock_shared(&g_flow_divert_group_lck
);
241 if (g_flow_divert_groups
== NULL
|| g_active_group_count
== 0) {
242 FDLOG0(LOG_ERR
, &nil_pcb
, "No active groups, flow divert cannot be used for this socket");
247 group
= g_flow_divert_groups
[ctl_unit
];
249 FDLOG(LOG_ERR
, &nil_pcb
, "Group for control unit %u is NULL, flow divert cannot be used for this socket", ctl_unit
);
254 socket_lock(fd_cb
->so
, 0);
260 key
[0] = g_nextkey
++;
261 key
[1] = RandomULong();
263 if (g_hash_seed
== 0) {
264 g_hash_seed
= RandomULong();
267 fd_cb
->hash
= net_flowhash(key
, sizeof(key
), g_hash_seed
);
269 for (idx
= 1; idx
< GROUP_COUNT_MAX
; idx
++) {
270 struct flow_divert_group
*curr_group
= g_flow_divert_groups
[idx
];
271 if (curr_group
!= NULL
&& curr_group
!= group
) {
272 lck_rw_lock_shared(&curr_group
->lck
);
273 exist
= RB_FIND(fd_pcb_tree
, &curr_group
->pcb_tree
, fd_cb
);
274 lck_rw_done(&curr_group
->lck
);
282 lck_rw_lock_exclusive(&group
->lck
);
283 exist
= RB_INSERT(fd_pcb_tree
, &group
->pcb_tree
, fd_cb
);
284 lck_rw_done(&group
->lck
);
286 } while (exist
!= NULL
&& try_count
++ < 3);
289 fd_cb
->group
= group
;
290 FDRETAIN(fd_cb
); /* The group now has a reference */
296 socket_unlock(fd_cb
->so
, 0);
299 lck_rw_done(&g_flow_divert_group_lck
);
300 socket_lock(fd_cb
->so
, 0);
305 static struct flow_divert_pcb
*
306 flow_divert_pcb_create(socket_t so
)
308 struct flow_divert_pcb
*new_pcb
= NULL
;
310 MALLOC_ZONE(new_pcb
, struct flow_divert_pcb
*, sizeof(*new_pcb
), M_FLOW_DIVERT_PCB
, M_WAITOK
);
311 if (new_pcb
== NULL
) {
312 FDLOG0(LOG_ERR
, &nil_pcb
, "failed to allocate a pcb");
316 memset(new_pcb
, 0, sizeof(*new_pcb
));
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, app rx %u, tunnel tx %u, tunnel rx %u",
331 fd_cb
->bytes_written_by_app
, fd_cb
->bytes_read_by_app
, fd_cb
->bytes_sent
, fd_cb
->bytes_received
);
333 if (fd_cb
->local_address
!= NULL
) {
334 FREE(fd_cb
->local_address
, M_SONAME
);
336 if (fd_cb
->remote_address
!= NULL
) {
337 FREE(fd_cb
->remote_address
, M_SONAME
);
339 if (fd_cb
->connect_token
!= NULL
) {
340 mbuf_freem(fd_cb
->connect_token
);
342 if (fd_cb
->connect_packet
!= NULL
) {
343 mbuf_freem(fd_cb
->connect_packet
);
345 if (fd_cb
->app_data
!= NULL
) {
346 FREE(fd_cb
->app_data
, M_TEMP
);
348 FREE_ZONE(fd_cb
, sizeof(*fd_cb
), M_FLOW_DIVERT_PCB
);
352 flow_divert_pcb_remove(struct flow_divert_pcb
*fd_cb
)
354 if (fd_cb
->group
!= NULL
) {
355 struct flow_divert_group
*group
= fd_cb
->group
;
356 lck_rw_lock_exclusive(&group
->lck
);
357 FDLOG(LOG_INFO
, fd_cb
, "Removing from group %d, ref count = %d", group
->ctl_unit
, fd_cb
->ref_count
);
358 RB_REMOVE(fd_pcb_tree
, &group
->pcb_tree
, fd_cb
);
360 FDRELEASE(fd_cb
); /* Release the group's reference */
361 lck_rw_done(&group
->lck
);
366 flow_divert_packet_init(struct flow_divert_pcb
*fd_cb
, uint8_t packet_type
, mbuf_t
*packet
)
368 struct flow_divert_packet_header hdr
;
371 error
= mbuf_gethdr(MBUF_DONTWAIT
, MBUF_TYPE_HEADER
, packet
);
373 FDLOG(LOG_ERR
, fd_cb
, "failed to allocate the header mbuf: %d", error
);
377 hdr
.packet_type
= packet_type
;
378 hdr
.conn_id
= htonl(fd_cb
->hash
);
380 /* Lay down the header */
381 error
= mbuf_copyback(*packet
, 0, sizeof(hdr
), &hdr
, MBUF_DONTWAIT
);
383 FDLOG(LOG_ERR
, fd_cb
, "mbuf_copyback(hdr) failed: %d", error
);
393 flow_divert_packet_append_tlv(mbuf_t packet
, uint8_t type
, uint32_t length
, const void *value
)
395 uint32_t net_length
= htonl(length
);
398 error
= mbuf_copyback(packet
, mbuf_pkthdr_len(packet
), sizeof(type
), &type
, MBUF_DONTWAIT
);
400 FDLOG(LOG_ERR
, &nil_pcb
, "failed to append the type (%d)", type
);
404 error
= mbuf_copyback(packet
, mbuf_pkthdr_len(packet
), sizeof(net_length
), &net_length
, MBUF_DONTWAIT
);
406 FDLOG(LOG_ERR
, &nil_pcb
, "failed to append the length (%u)", length
);
410 error
= mbuf_copyback(packet
, mbuf_pkthdr_len(packet
), length
, value
, MBUF_DONTWAIT
);
412 FDLOG0(LOG_ERR
, &nil_pcb
, "failed to append the value");
420 flow_divert_packet_find_tlv(mbuf_t packet
, int offset
, uint8_t type
, int *err
, int next
)
422 size_t cursor
= offset
;
424 uint32_t curr_length
;
431 error
= mbuf_copydata(packet
, cursor
, sizeof(curr_type
), &curr_type
);
438 curr_type
= FLOW_DIVERT_TLV_NIL
;
441 if (curr_type
!= type
) {
442 cursor
+= sizeof(curr_type
);
443 error
= mbuf_copydata(packet
, cursor
, sizeof(curr_length
), &curr_length
);
449 cursor
+= (sizeof(curr_length
) + ntohl(curr_length
));
451 } while (curr_type
!= type
);
457 flow_divert_packet_get_tlv(mbuf_t packet
, int offset
, uint8_t type
, size_t buff_len
, void *buff
, uint32_t *val_size
)
463 tlv_offset
= flow_divert_packet_find_tlv(packet
, offset
, type
, &error
, 0);
464 if (tlv_offset
< 0) {
468 error
= mbuf_copydata(packet
, tlv_offset
+ sizeof(type
), sizeof(length
), &length
);
473 length
= ntohl(length
);
475 if (val_size
!= NULL
) {
479 if (buff
!= NULL
&& buff_len
> 0) {
480 size_t to_copy
= (length
< buff_len
) ? length
: buff_len
;
481 error
= mbuf_copydata(packet
, tlv_offset
+ sizeof(type
) + sizeof(length
), to_copy
, buff
);
491 flow_divert_packet_compute_hmac(mbuf_t packet
, struct flow_divert_group
*group
, uint8_t *hmac
)
493 mbuf_t curr_mbuf
= packet
;
495 if (g_crypto_funcs
== NULL
|| group
->token_key
== NULL
) {
499 cchmac_di_decl(g_crypto_funcs
->ccsha1_di
, hmac_ctx
);
500 g_crypto_funcs
->cchmac_init_fn(g_crypto_funcs
->ccsha1_di
, hmac_ctx
, group
->token_key_size
, group
->token_key
);
502 while (curr_mbuf
!= NULL
) {
503 g_crypto_funcs
->cchmac_update_fn(g_crypto_funcs
->ccsha1_di
, hmac_ctx
, mbuf_len(curr_mbuf
), mbuf_data(curr_mbuf
));
504 curr_mbuf
= mbuf_next(curr_mbuf
);
507 g_crypto_funcs
->cchmac_final_fn(g_crypto_funcs
->ccsha1_di
, hmac_ctx
, hmac
);
513 flow_divert_packet_verify_hmac(mbuf_t packet
, uint32_t ctl_unit
)
516 struct flow_divert_group
*group
= NULL
;
518 uint8_t packet_hmac
[SHA_DIGEST_LENGTH
];
519 uint8_t computed_hmac
[SHA_DIGEST_LENGTH
];
522 lck_rw_lock_shared(&g_flow_divert_group_lck
);
524 if (g_flow_divert_groups
!= NULL
&& g_active_group_count
> 0) {
525 group
= g_flow_divert_groups
[ctl_unit
];
529 lck_rw_done(&g_flow_divert_group_lck
);
533 lck_rw_lock_shared(&group
->lck
);
535 if (group
->token_key
== NULL
) {
540 hmac_offset
= flow_divert_packet_find_tlv(packet
, 0, FLOW_DIVERT_TLV_HMAC
, &error
, 0);
541 if (hmac_offset
< 0) {
545 error
= flow_divert_packet_get_tlv(packet
, hmac_offset
, FLOW_DIVERT_TLV_HMAC
, sizeof(packet_hmac
), packet_hmac
, NULL
);
550 /* Chop off the HMAC TLV */
551 error
= mbuf_split(packet
, hmac_offset
, MBUF_WAITOK
, &tail
);
558 error
= flow_divert_packet_compute_hmac(packet
, group
, computed_hmac
);
563 if (memcmp(packet_hmac
, computed_hmac
, sizeof(packet_hmac
))) {
564 FDLOG0(LOG_WARNING
, &nil_pcb
, "HMAC in token does not match computed HMAC");
570 lck_rw_done(&group
->lck
);
571 lck_rw_done(&g_flow_divert_group_lck
);
576 flow_divert_add_data_statistics(struct flow_divert_pcb
*fd_cb
, int data_len
, Boolean send
)
578 struct inpcb
*inp
= NULL
;
579 struct ifnet
*ifp
= NULL
;
580 Boolean cell
= FALSE
;
581 Boolean wifi
= FALSE
;
582 Boolean wired
= FALSE
;
584 inp
= sotoinpcb(fd_cb
->so
);
589 ifp
= inp
->inp_last_outifp
;
591 cell
= IFNET_IS_CELLULAR(ifp
);
592 wifi
= (!cell
&& IFNET_IS_WIFI(ifp
));
593 wired
= (!wifi
&& IFNET_IS_WIRED(ifp
));
597 INP_ADD_STAT(inp
, cell
, wifi
, wired
, txpackets
, 1);
598 INP_ADD_STAT(inp
, cell
, wifi
, wired
, txbytes
, data_len
);
600 INP_ADD_STAT(inp
, cell
, wifi
, wired
, rxpackets
, 1);
601 INP_ADD_STAT(inp
, cell
, wifi
, wired
, rxbytes
, data_len
);
603 inp_set_activity_bitmap(inp
);
607 flow_divert_check_no_cellular(struct flow_divert_pcb
*fd_cb
)
609 struct inpcb
*inp
= NULL
;
611 inp
= sotoinpcb(fd_cb
->so
);
612 if (inp
&& INP_NO_CELLULAR(inp
) && inp
->inp_last_outifp
&&
613 IFNET_IS_CELLULAR(inp
->inp_last_outifp
)) {
621 flow_divert_check_no_expensive(struct flow_divert_pcb
*fd_cb
)
623 struct inpcb
*inp
= NULL
;
625 inp
= sotoinpcb(fd_cb
->so
);
626 if (inp
&& INP_NO_EXPENSIVE(inp
) && inp
->inp_last_outifp
&&
627 IFNET_IS_EXPENSIVE(inp
->inp_last_outifp
)) {
635 flow_divert_update_closed_state(struct flow_divert_pcb
*fd_cb
, int how
, Boolean tunnel
)
637 if (how
!= SHUT_RD
) {
638 fd_cb
->flags
|= FLOW_DIVERT_WRITE_CLOSED
;
639 if (tunnel
|| !(fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
)) {
640 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_WR_CLOSED
;
641 /* If the tunnel is not accepting writes any more, then flush the send buffer */
642 sbflush(&fd_cb
->so
->so_snd
);
645 if (how
!= SHUT_WR
) {
646 fd_cb
->flags
|= FLOW_DIVERT_READ_CLOSED
;
647 if (tunnel
|| !(fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
)) {
648 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_RD_CLOSED
;
654 trie_node_alloc(struct flow_divert_trie
*trie
)
656 if (trie
->nodes_free_next
< trie
->nodes_count
) {
657 uint16_t node_idx
= trie
->nodes_free_next
++;
658 TRIE_NODE(trie
, node_idx
).child_map
= NULL_TRIE_IDX
;
661 return NULL_TRIE_IDX
;
666 trie_child_map_alloc(struct flow_divert_trie
*trie
)
668 if (trie
->child_maps_free_next
< trie
->child_maps_count
) {
669 return trie
->child_maps_free_next
++;
671 return NULL_TRIE_IDX
;
676 trie_bytes_move(struct flow_divert_trie
*trie
, uint16_t bytes_idx
, size_t bytes_size
)
678 uint16_t start
= trie
->bytes_free_next
;
679 if (start
+ bytes_size
<= trie
->bytes_count
) {
680 if (start
!= bytes_idx
) {
681 memmove(&TRIE_BYTE(trie
, start
), &TRIE_BYTE(trie
, bytes_idx
), bytes_size
);
683 trie
->bytes_free_next
+= bytes_size
;
686 return NULL_TRIE_IDX
;
691 flow_divert_trie_insert(struct flow_divert_trie
*trie
, uint16_t string_start
, size_t string_len
)
693 uint16_t current
= trie
->root
;
694 uint16_t child
= trie
->root
;
695 uint16_t string_end
= string_start
+ string_len
;
696 uint16_t string_idx
= string_start
;
697 uint16_t string_remainder
= string_len
;
699 while (child
!= NULL_TRIE_IDX
) {
700 uint16_t parent
= current
;
702 uint16_t current_end
;
705 child
= NULL_TRIE_IDX
;
707 current_end
= TRIE_NODE(trie
, current
).start
+ TRIE_NODE(trie
, current
).length
;
709 for (node_idx
= TRIE_NODE(trie
, current
).start
;
710 node_idx
< current_end
&&
711 string_idx
< string_end
&&
712 TRIE_BYTE(trie
, node_idx
) == TRIE_BYTE(trie
, string_idx
);
713 node_idx
++, string_idx
++) {
717 string_remainder
= string_end
- string_idx
;
719 if (node_idx
< (TRIE_NODE(trie
, current
).start
+ TRIE_NODE(trie
, current
).length
)) {
721 * We did not reach the end of the current node's string.
722 * We need to split the current node into two:
723 * 1. A new node that contains the prefix of the node that matches
724 * the prefix of the string being inserted.
725 * 2. The current node modified to point to the remainder
726 * of the current node's string.
728 uint16_t prefix
= trie_node_alloc(trie
);
729 if (prefix
== NULL_TRIE_IDX
) {
730 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of trie nodes while splitting an existing node");
731 return NULL_TRIE_IDX
;
735 * Prefix points to the portion of the current nodes's string that has matched
736 * the input string thus far.
738 TRIE_NODE(trie
, prefix
).start
= TRIE_NODE(trie
, current
).start
;
739 TRIE_NODE(trie
, prefix
).length
= (node_idx
- TRIE_NODE(trie
, current
).start
);
742 * Prefix has the current node as the child corresponding to the first byte
745 TRIE_NODE(trie
, prefix
).child_map
= trie_child_map_alloc(trie
);
746 if (TRIE_NODE(trie
, prefix
).child_map
== NULL_TRIE_IDX
) {
747 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of child maps while splitting an existing node");
748 return NULL_TRIE_IDX
;
750 TRIE_CHILD(trie
, prefix
, TRIE_BYTE(trie
, node_idx
)) = current
;
752 /* Parent has the prefix as the child correspoding to the first byte in the prefix */
753 TRIE_CHILD(trie
, parent
, TRIE_BYTE(trie
, TRIE_NODE(trie
, prefix
).start
)) = prefix
;
755 /* Current node is adjusted to point to the remainder */
756 TRIE_NODE(trie
, current
).start
= node_idx
;
757 TRIE_NODE(trie
, current
).length
-= TRIE_NODE(trie
, prefix
).length
;
759 /* We want to insert the new leaf (if any) as a child of the prefix */
763 if (string_remainder
> 0) {
765 * We still have bytes in the string that have not been matched yet.
766 * If the current node has children, iterate to the child corresponding
767 * to the next byte in the string.
769 if (TRIE_NODE(trie
, current
).child_map
!= NULL_TRIE_IDX
) {
770 child
= TRIE_CHILD(trie
, current
, TRIE_BYTE(trie
, string_idx
));
773 } /* while (child != NULL_TRIE_IDX) */
775 if (string_remainder
> 0) {
776 /* Add a new leaf containing the remainder of the string */
777 uint16_t leaf
= trie_node_alloc(trie
);
778 if (leaf
== NULL_TRIE_IDX
) {
779 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of trie nodes while inserting a new leaf");
780 return NULL_TRIE_IDX
;
783 TRIE_NODE(trie
, leaf
).start
= trie_bytes_move(trie
, string_idx
, string_remainder
);
784 if (TRIE_NODE(trie
, leaf
).start
== NULL_TRIE_IDX
) {
785 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of bytes while inserting a new leaf");
786 return NULL_TRIE_IDX
;
788 TRIE_NODE(trie
, leaf
).length
= string_remainder
;
790 /* Set the new leaf as the child of the current node */
791 if (TRIE_NODE(trie
, current
).child_map
== NULL_TRIE_IDX
) {
792 TRIE_NODE(trie
, current
).child_map
= trie_child_map_alloc(trie
);
793 if (TRIE_NODE(trie
, current
).child_map
== NULL_TRIE_IDX
) {
794 FDLOG0(LOG_ERR
, &nil_pcb
, "Ran out of child maps while inserting a new leaf");
795 return NULL_TRIE_IDX
;
798 TRIE_CHILD(trie
, current
, TRIE_BYTE(trie
, TRIE_NODE(trie
, leaf
).start
)) = leaf
;
800 } /* else duplicate or this string is a prefix of one of the existing strings */
805 #define APPLE_WEBCLIP_ID_PREFIX "com.apple.webapp"
807 flow_divert_trie_search(struct flow_divert_trie
*trie
, uint8_t *string_bytes
)
809 uint16_t current
= trie
->root
;
810 uint16_t string_idx
= 0;
812 while (current
!= NULL_TRIE_IDX
) {
813 uint16_t next
= NULL_TRIE_IDX
;
814 uint16_t node_end
= TRIE_NODE(trie
, current
).start
+ TRIE_NODE(trie
, current
).length
;
817 for (node_idx
= TRIE_NODE(trie
, current
).start
;
818 node_idx
< node_end
&& string_bytes
[string_idx
] != '\0' && string_bytes
[string_idx
] == TRIE_BYTE(trie
, node_idx
);
819 node_idx
++, string_idx
++) {
823 if (node_idx
== node_end
) {
824 if (string_bytes
[string_idx
] == '\0') {
825 return current
; /* Got an exact match */
826 } else if (string_idx
== strlen(APPLE_WEBCLIP_ID_PREFIX
) &&
827 0 == strncmp((const char *)string_bytes
, APPLE_WEBCLIP_ID_PREFIX
, string_idx
)) {
828 string_bytes
[string_idx
] = '\0';
829 return current
; /* Got an apple webclip id prefix match */
830 } else if (TRIE_NODE(trie
, current
).child_map
!= NULL_TRIE_IDX
) {
831 next
= TRIE_CHILD(trie
, current
, string_bytes
[string_idx
]);
837 return NULL_TRIE_IDX
;
840 struct uuid_search_info
{
842 char *found_signing_id
;
843 boolean_t found_multiple_signing_ids
;
848 flow_divert_find_proc_by_uuid_callout(proc_t p
, void *arg
)
850 struct uuid_search_info
*info
= (struct uuid_search_info
*)arg
;
851 int result
= PROC_RETURNED_DONE
; /* By default, we didn't find the process */
853 if (info
->found_signing_id
!= NULL
) {
854 if (!info
->found_multiple_signing_ids
) {
855 /* All processes that were found had the same signing identifier, so just claim this first one and be done. */
856 info
->found_proc
= p
;
857 result
= PROC_CLAIMED_DONE
;
859 uuid_string_t uuid_str
;
860 uuid_unparse(info
->target_uuid
, uuid_str
);
861 FDLOG(LOG_WARNING
, &nil_pcb
, "Found multiple processes with UUID %s with different signing identifiers", uuid_str
);
863 FREE(info
->found_signing_id
, M_TEMP
);
864 info
->found_signing_id
= NULL
;
867 if (result
== PROC_RETURNED_DONE
) {
868 uuid_string_t uuid_str
;
869 uuid_unparse(info
->target_uuid
, uuid_str
);
870 FDLOG(LOG_WARNING
, &nil_pcb
, "Failed to find a process with UUID %s", uuid_str
);
877 flow_divert_find_proc_by_uuid_filter(proc_t p
, void *arg
)
879 struct uuid_search_info
*info
= (struct uuid_search_info
*)arg
;
882 if (info
->found_multiple_signing_ids
) {
886 include
= (uuid_compare(p
->p_uuid
, info
->target_uuid
) == 0);
888 const char *signing_id
= cs_identity_get(p
);
889 if (signing_id
!= NULL
) {
890 FDLOG(LOG_INFO
, &nil_pcb
, "Found process %d with signing identifier %s", p
->p_pid
, signing_id
);
891 size_t signing_id_size
= strlen(signing_id
) + 1;
892 if (info
->found_signing_id
== NULL
) {
893 MALLOC(info
->found_signing_id
, char *, signing_id_size
, M_TEMP
, M_WAITOK
);
894 memcpy(info
->found_signing_id
, signing_id
, signing_id_size
);
895 } else if (memcmp(signing_id
, info
->found_signing_id
, signing_id_size
)) {
896 info
->found_multiple_signing_ids
= TRUE
;
899 info
->found_multiple_signing_ids
= TRUE
;
901 include
= !info
->found_multiple_signing_ids
;
908 flow_divert_find_proc_by_uuid(uuid_t uuid
)
910 struct uuid_search_info info
;
912 if (LOG_INFO
<= nil_pcb
.log_level
) {
913 uuid_string_t uuid_str
;
914 uuid_unparse(uuid
, uuid_str
);
915 FDLOG(LOG_INFO
, &nil_pcb
, "Looking for process with UUID %s", uuid_str
);
918 memset(&info
, 0, sizeof(info
));
919 info
.found_proc
= PROC_NULL
;
920 uuid_copy(info
.target_uuid
, uuid
);
922 proc_iterate(PROC_ALLPROCLIST
, flow_divert_find_proc_by_uuid_callout
, &info
, flow_divert_find_proc_by_uuid_filter
, &info
);
924 return info
.found_proc
;
928 flow_divert_get_src_proc(struct socket
*so
, proc_t
*proc
)
932 if (so
->so_flags
& SOF_DELEGATED
) {
933 if ((*proc
)->p_pid
!= so
->e_pid
) {
934 *proc
= proc_find(so
->e_pid
);
936 } else if (uuid_compare((*proc
)->p_uuid
, so
->e_uuid
)) {
937 *proc
= flow_divert_find_proc_by_uuid(so
->e_uuid
);
940 } else if (*proc
== PROC_NULL
) {
941 *proc
= current_proc();
944 if (*proc
!= PROC_NULL
) {
945 if ((*proc
)->p_pid
== 0) {
958 flow_divert_send_packet(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, Boolean enqueue
)
962 if (fd_cb
->group
== NULL
) {
963 fd_cb
->so
->so_error
= ECONNABORTED
;
964 flow_divert_disconnect_socket(fd_cb
->so
);
968 lck_rw_lock_shared(&fd_cb
->group
->lck
);
970 if (MBUFQ_EMPTY(&fd_cb
->group
->send_queue
)) {
971 error
= ctl_enqueuembuf(g_flow_divert_kctl_ref
, fd_cb
->group
->ctl_unit
, packet
, CTL_DATA_EOR
);
976 if (error
== ENOBUFS
) {
978 if (!lck_rw_lock_shared_to_exclusive(&fd_cb
->group
->lck
)) {
979 lck_rw_lock_exclusive(&fd_cb
->group
->lck
);
981 MBUFQ_ENQUEUE(&fd_cb
->group
->send_queue
, packet
);
984 OSTestAndSet(GROUP_BIT_CTL_ENQUEUE_BLOCKED
, &fd_cb
->group
->atomic_bits
);
987 lck_rw_done(&fd_cb
->group
->lck
);
993 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
)
997 char *signing_id
= NULL
;
998 int free_signing_id
= 0;
999 mbuf_t connect_packet
= NULL
;
1000 proc_t src_proc
= p
;
1001 int release_proc
= 0;
1003 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_CONNECT
, &connect_packet
);
1010 if (fd_cb
->connect_token
!= NULL
&& (fd_cb
->flags
& FLOW_DIVERT_HAS_HMAC
)) {
1011 uint32_t sid_size
= 0;
1012 int find_error
= flow_divert_packet_get_tlv(fd_cb
->connect_token
, 0, FLOW_DIVERT_TLV_SIGNING_ID
, 0, NULL
, &sid_size
);
1013 if (find_error
== 0 && sid_size
> 0) {
1014 MALLOC(signing_id
, char *, sid_size
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
1015 if (signing_id
!= NULL
) {
1016 flow_divert_packet_get_tlv(fd_cb
->connect_token
, 0, FLOW_DIVERT_TLV_SIGNING_ID
, sid_size
, signing_id
, NULL
);
1017 FDLOG(LOG_INFO
, fd_cb
, "Got %s from token", signing_id
);
1018 free_signing_id
= 1;
1023 socket_unlock(so
, 0);
1025 if (signing_id
== NULL
) {
1026 release_proc
= flow_divert_get_src_proc(so
, &src_proc
);
1027 if (src_proc
!= PROC_NULL
) {
1028 proc_lock(src_proc
);
1029 if (src_proc
->p_csflags
& (CS_VALID
| CS_DEBUGGED
)) {
1031 cs_id
= cs_identity_get(src_proc
);
1032 signing_id
= __DECONST(char *, cs_id
);
1034 FDLOG0(LOG_WARNING
, fd_cb
, "Signature is invalid");
1037 FDLOG0(LOG_WARNING
, fd_cb
, "Failed to determine the current proc");
1040 src_proc
= PROC_NULL
;
1043 if (signing_id
!= NULL
) {
1044 uint16_t result
= NULL_TRIE_IDX
;
1045 lck_rw_lock_shared(&fd_cb
->group
->lck
);
1046 if (fd_cb
->group
->flags
& FLOW_DIVERT_GROUP_FLAG_NO_APP_MAP
) {
1049 result
= flow_divert_trie_search(&fd_cb
->group
->signing_id_trie
, (uint8_t *)signing_id
);
1051 lck_rw_done(&fd_cb
->group
->lck
);
1052 if (result
!= NULL_TRIE_IDX
) {
1054 FDLOG(LOG_INFO
, fd_cb
, "%s matched", signing_id
);
1056 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_SIGNING_ID
, strlen(signing_id
), signing_id
);
1058 if (src_proc
!= PROC_NULL
) {
1059 unsigned char cdhash
[SHA1_RESULTLEN
];
1060 error
= proc_getcdhash(src_proc
, cdhash
);
1062 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_CDHASH
, sizeof(cdhash
), cdhash
);
1064 FDLOG(LOG_ERR
, fd_cb
, "failed to append the cdhash: %d", error
);
1067 FDLOG(LOG_ERR
, fd_cb
, "failed to get the cdhash: %d", error
);
1071 FDLOG(LOG_ERR
, fd_cb
, "failed to append the signing ID: %d", error
);
1074 FDLOG(LOG_WARNING
, fd_cb
, "%s did not match", signing_id
);
1077 FDLOG0(LOG_WARNING
, fd_cb
, "Failed to get the code signing identity");
1078 if (fd_cb
->group
->flags
& FLOW_DIVERT_GROUP_FLAG_NO_APP_MAP
) {
1083 if (src_proc
!= PROC_NULL
) {
1084 proc_unlock(src_proc
);
1086 proc_rele(src_proc
);
1091 if (free_signing_id
) {
1092 FREE(signing_id
, M_TEMP
);
1099 error
= flow_divert_packet_append_tlv(connect_packet
,
1100 FLOW_DIVERT_TLV_TRAFFIC_CLASS
,
1101 sizeof(fd_cb
->so
->so_traffic_class
),
1102 &fd_cb
->so
->so_traffic_class
);
1107 if (SOCK_TYPE(fd_cb
->so
) == SOCK_STREAM
) {
1108 flow_type
= FLOW_DIVERT_FLOW_TYPE_TCP
;
1109 } else if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
1110 flow_type
= FLOW_DIVERT_FLOW_TYPE_UDP
;
1115 error
= flow_divert_packet_append_tlv(connect_packet
,
1116 FLOW_DIVERT_TLV_FLOW_TYPE
,
1124 if (fd_cb
->so
->so_flags
& SOF_DELEGATED
) {
1125 error
= flow_divert_packet_append_tlv(connect_packet
,
1126 FLOW_DIVERT_TLV_PID
,
1127 sizeof(fd_cb
->so
->e_pid
),
1133 error
= flow_divert_packet_append_tlv(connect_packet
,
1134 FLOW_DIVERT_TLV_UUID
,
1135 sizeof(fd_cb
->so
->e_uuid
),
1136 &fd_cb
->so
->e_uuid
);
1141 error
= flow_divert_packet_append_tlv(connect_packet
,
1142 FLOW_DIVERT_TLV_PID
,
1143 sizeof(fd_cb
->so
->e_pid
),
1144 &fd_cb
->so
->last_pid
);
1149 error
= flow_divert_packet_append_tlv(connect_packet
,
1150 FLOW_DIVERT_TLV_UUID
,
1151 sizeof(fd_cb
->so
->e_uuid
),
1152 &fd_cb
->so
->last_uuid
);
1158 if (fd_cb
->connect_token
!= NULL
) {
1159 unsigned int token_len
= m_length(fd_cb
->connect_token
);
1160 mbuf_concatenate(connect_packet
, fd_cb
->connect_token
);
1161 mbuf_pkthdr_adjustlen(connect_packet
, token_len
);
1162 fd_cb
->connect_token
= NULL
;
1164 uint32_t ctl_unit
= htonl(fd_cb
->control_group_unit
);
1166 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), &ctl_unit
);
1171 error
= flow_divert_append_target_endpoint_tlv(connect_packet
, to
);
1177 if (fd_cb
->local_address
!= NULL
) {
1181 struct inpcb
*inp
= sotoinpcb(so
);
1182 if (flow_divert_has_pcb_local_address(inp
)) {
1183 error
= flow_divert_inp_to_sockaddr(inp
, &fd_cb
->local_address
);
1185 FDLOG0(LOG_ERR
, fd_cb
, "failed to get the local socket address.");
1191 if (fd_cb
->local_address
!= NULL
) {
1192 /* socket is bound. */
1193 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_LOCAL_ADDR
,
1194 fd_cb
->local_address
->sa_len
, fd_cb
->local_address
);
1200 if (so
->so_flags1
& SOF1_DATA_IDEMPOTENT
) {
1201 uint32_t flags
= FLOW_DIVERT_TOKEN_FLAG_TFO
;
1202 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_FLAGS
, sizeof(flags
), &flags
);
1210 *out_connect_packet
= connect_packet
;
1211 } else if (connect_packet
!= NULL
) {
1212 mbuf_freem(connect_packet
);
1219 flow_divert_send_connect_result(struct flow_divert_pcb
*fd_cb
)
1222 mbuf_t packet
= NULL
;
1223 int rbuff_space
= 0;
1225 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_CONNECT_RESULT
, &packet
);
1227 FDLOG(LOG_ERR
, fd_cb
, "failed to create a connect result packet: %d", error
);
1231 rbuff_space
= fd_cb
->so
->so_rcv
.sb_hiwat
;
1232 if (rbuff_space
< 0) {
1235 rbuff_space
= htonl(rbuff_space
);
1236 error
= flow_divert_packet_append_tlv(packet
,
1237 FLOW_DIVERT_TLV_SPACE_AVAILABLE
,
1238 sizeof(rbuff_space
),
1244 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1250 if (error
&& packet
!= NULL
) {
1258 flow_divert_send_close(struct flow_divert_pcb
*fd_cb
, int how
)
1261 mbuf_t packet
= NULL
;
1264 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_CLOSE
, &packet
);
1266 FDLOG(LOG_ERR
, fd_cb
, "failed to create a close packet: %d", error
);
1270 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_ERROR_CODE
, sizeof(zero
), &zero
);
1272 FDLOG(LOG_ERR
, fd_cb
, "failed to add the error code TLV: %d", error
);
1277 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_HOW
, sizeof(how
), &how
);
1279 FDLOG(LOG_ERR
, fd_cb
, "failed to add the how flag: %d", error
);
1283 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1289 if (error
&& packet
!= NULL
) {
1297 flow_divert_tunnel_how_closed(struct flow_divert_pcb
*fd_cb
)
1299 if ((fd_cb
->flags
& (FLOW_DIVERT_TUNNEL_RD_CLOSED
| FLOW_DIVERT_TUNNEL_WR_CLOSED
)) ==
1300 (FLOW_DIVERT_TUNNEL_RD_CLOSED
| FLOW_DIVERT_TUNNEL_WR_CLOSED
)) {
1302 } else if (fd_cb
->flags
& FLOW_DIVERT_TUNNEL_RD_CLOSED
) {
1304 } else if (fd_cb
->flags
& FLOW_DIVERT_TUNNEL_WR_CLOSED
) {
1312 * Determine what close messages if any need to be sent to the tunnel. Returns TRUE if the tunnel is closed for both reads and
1313 * writes. Returns FALSE otherwise.
1316 flow_divert_send_close_if_needed(struct flow_divert_pcb
*fd_cb
)
1320 /* Do not send any close messages if there is still data in the send buffer */
1321 if (fd_cb
->so
->so_snd
.sb_cc
== 0) {
1322 if ((fd_cb
->flags
& (FLOW_DIVERT_READ_CLOSED
| FLOW_DIVERT_TUNNEL_RD_CLOSED
)) == FLOW_DIVERT_READ_CLOSED
) {
1323 /* Socket closed reads, but tunnel did not. Tell tunnel to close reads */
1326 if ((fd_cb
->flags
& (FLOW_DIVERT_WRITE_CLOSED
| FLOW_DIVERT_TUNNEL_WR_CLOSED
)) == FLOW_DIVERT_WRITE_CLOSED
) {
1327 /* Socket closed writes, but tunnel did not. Tell tunnel to close writes */
1328 if (how
== SHUT_RD
) {
1337 FDLOG(LOG_INFO
, fd_cb
, "sending close, how = %d", how
);
1338 if (flow_divert_send_close(fd_cb
, how
) != ENOBUFS
) {
1339 /* Successfully sent the close packet. Record the ways in which the tunnel has been closed */
1340 if (how
!= SHUT_RD
) {
1341 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_WR_CLOSED
;
1343 if (how
!= SHUT_WR
) {
1344 fd_cb
->flags
|= FLOW_DIVERT_TUNNEL_RD_CLOSED
;
1349 if (flow_divert_tunnel_how_closed(fd_cb
) == SHUT_RDWR
) {
1350 flow_divert_disconnect_socket(fd_cb
->so
);
1355 flow_divert_send_data_packet(struct flow_divert_pcb
*fd_cb
, mbuf_t data
, size_t data_len
, struct sockaddr
*toaddr
, Boolean force
)
1361 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_DATA
, &packet
);
1363 FDLOG(LOG_ERR
, fd_cb
, "flow_divert_packet_init failed: %d", error
);
1367 if (toaddr
!= NULL
) {
1368 error
= flow_divert_append_target_endpoint_tlv(packet
, toaddr
);
1370 FDLOG(LOG_ERR
, fd_cb
, "flow_divert_append_target_endpoint_tlv() failed: %d", error
);
1375 if (data_len
> 0 && data
!= NULL
) {
1376 last
= m_last(packet
);
1377 mbuf_setnext(last
, data
);
1378 mbuf_pkthdr_adjustlen(packet
, data_len
);
1380 error
= flow_divert_send_packet(fd_cb
, packet
, force
);
1383 mbuf_setnext(last
, NULL
);
1386 fd_cb
->bytes_sent
+= data_len
;
1387 flow_divert_add_data_statistics(fd_cb
, data_len
, TRUE
);
1394 flow_divert_send_buffered_data(struct flow_divert_pcb
*fd_cb
, Boolean force
)
1401 to_send
= fd_cb
->so
->so_snd
.sb_cc
;
1402 buffer
= fd_cb
->so
->so_snd
.sb_mb
;
1404 if (buffer
== NULL
&& to_send
> 0) {
1405 FDLOG(LOG_ERR
, fd_cb
, "Send buffer is NULL, but size is supposed to be %lu", to_send
);
1409 /* Ignore the send window if force is enabled */
1410 if (!force
&& (to_send
> fd_cb
->send_window
)) {
1411 to_send
= fd_cb
->send_window
;
1414 if (SOCK_TYPE(fd_cb
->so
) == SOCK_STREAM
) {
1415 while (sent
< to_send
) {
1419 data_len
= to_send
- sent
;
1420 if (data_len
> FLOW_DIVERT_CHUNK_SIZE
) {
1421 data_len
= FLOW_DIVERT_CHUNK_SIZE
;
1424 error
= mbuf_copym(buffer
, sent
, data_len
, MBUF_DONTWAIT
, &data
);
1426 FDLOG(LOG_ERR
, fd_cb
, "mbuf_copym failed: %d", error
);
1430 error
= flow_divert_send_data_packet(fd_cb
, data
, data_len
, NULL
, force
);
1438 sbdrop(&fd_cb
->so
->so_snd
, sent
);
1439 sowwakeup(fd_cb
->so
);
1440 } else if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
1446 struct sockaddr
*toaddr
= flow_divert_get_buffered_target_address(buffer
);
1449 if (toaddr
!= NULL
) {
1450 /* look for data in the chain */
1453 if (m
!= NULL
&& m
->m_type
== MT_DATA
) {
1459 FDLOG0(LOG_ERR
, fd_cb
, "failed to find type MT_DATA in the mbuf chain.");
1463 data_len
= mbuf_pkthdr_len(m
);
1465 FDLOG(LOG_DEBUG
, fd_cb
, "mbuf_copym() data_len = %lu", data_len
);
1466 error
= mbuf_copym(m
, 0, data_len
, MBUF_DONTWAIT
, &data
);
1468 FDLOG(LOG_ERR
, fd_cb
, "mbuf_copym failed: %d", error
);
1474 error
= flow_divert_send_data_packet(fd_cb
, data
, data_len
, toaddr
, force
);
1481 buffer
= buffer
->m_nextpkt
;
1482 (void) sbdroprecord(&(fd_cb
->so
->so_snd
));
1487 FDLOG(LOG_DEBUG
, fd_cb
, "sent %lu bytes of buffered data", sent
);
1488 if (fd_cb
->send_window
>= sent
) {
1489 fd_cb
->send_window
-= sent
;
1491 fd_cb
->send_window
= 0;
1497 flow_divert_send_app_data(struct flow_divert_pcb
*fd_cb
, mbuf_t data
, struct sockaddr
*toaddr
)
1499 size_t to_send
= mbuf_pkthdr_len(data
);
1502 if (to_send
> fd_cb
->send_window
) {
1503 to_send
= fd_cb
->send_window
;
1506 if (fd_cb
->so
->so_snd
.sb_cc
> 0) {
1507 to_send
= 0; /* If the send buffer is non-empty, then we can't send anything */
1510 if (SOCK_TYPE(fd_cb
->so
) == SOCK_STREAM
) {
1512 mbuf_t remaining_data
= data
;
1513 mbuf_t pkt_data
= NULL
;
1514 while (sent
< to_send
&& remaining_data
!= NULL
) {
1515 size_t pkt_data_len
;
1517 pkt_data
= remaining_data
;
1519 if ((to_send
- sent
) > FLOW_DIVERT_CHUNK_SIZE
) {
1520 pkt_data_len
= FLOW_DIVERT_CHUNK_SIZE
;
1522 pkt_data_len
= to_send
- sent
;
1525 if (pkt_data_len
< mbuf_pkthdr_len(pkt_data
)) {
1526 error
= mbuf_split(pkt_data
, pkt_data_len
, MBUF_DONTWAIT
, &remaining_data
);
1528 FDLOG(LOG_ERR
, fd_cb
, "mbuf_split failed: %d", error
);
1533 remaining_data
= NULL
;
1536 error
= flow_divert_send_data_packet(fd_cb
, pkt_data
, pkt_data_len
, NULL
, FALSE
);
1543 sent
+= pkt_data_len
;
1546 fd_cb
->send_window
-= sent
;
1550 if (pkt_data
!= NULL
) {
1551 if (sbspace(&fd_cb
->so
->so_snd
) > 0) {
1552 if (!sbappendstream(&fd_cb
->so
->so_snd
, pkt_data
)) {
1553 FDLOG(LOG_ERR
, fd_cb
, "sbappendstream failed with pkt_data, send buffer size = %u, send_window = %u\n",
1554 fd_cb
->so
->so_snd
.sb_cc
, fd_cb
->send_window
);
1561 if (remaining_data
!= NULL
) {
1562 if (sbspace(&fd_cb
->so
->so_snd
) > 0) {
1563 if (!sbappendstream(&fd_cb
->so
->so_snd
, remaining_data
)) {
1564 FDLOG(LOG_ERR
, fd_cb
, "sbappendstream failed with remaining_data, send buffer size = %u, send_window = %u\n",
1565 fd_cb
->so
->so_snd
.sb_cc
, fd_cb
->send_window
);
1571 } else if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
1572 if (to_send
|| mbuf_pkthdr_len(data
) == 0) {
1573 error
= flow_divert_send_data_packet(fd_cb
, data
, to_send
, toaddr
, FALSE
);
1575 FDLOG(LOG_ERR
, fd_cb
, "flow_divert_send_data_packet failed. send data size = %lu", to_send
);
1577 fd_cb
->send_window
-= to_send
;
1581 if (sbspace(&fd_cb
->so
->so_snd
) >= (int)mbuf_pkthdr_len(data
)) {
1582 if (toaddr
!= NULL
) {
1583 if (!sbappendaddr(&fd_cb
->so
->so_snd
, toaddr
, data
, NULL
, &error
)) {
1584 FDLOG(LOG_ERR
, fd_cb
,
1585 "sbappendaddr failed. send buffer size = %u, send_window = %u, error = %d\n",
1586 fd_cb
->so
->so_snd
.sb_cc
, fd_cb
->send_window
, error
);
1589 if (!sbappendrecord(&fd_cb
->so
->so_snd
, data
)) {
1590 FDLOG(LOG_ERR
, fd_cb
,
1591 "sbappendrecord failed. send buffer size = %u, send_window = %u, error = %d\n",
1592 fd_cb
->so
->so_snd
.sb_cc
, fd_cb
->send_window
, error
);
1605 flow_divert_send_read_notification(struct flow_divert_pcb
*fd_cb
, uint32_t read_count
)
1608 mbuf_t packet
= NULL
;
1609 uint32_t net_read_count
= htonl(read_count
);
1611 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_READ_NOTIFY
, &packet
);
1613 FDLOG(LOG_ERR
, fd_cb
, "failed to create a read notification packet: %d", error
);
1617 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_READ_COUNT
, sizeof(net_read_count
), &net_read_count
);
1619 FDLOG(LOG_ERR
, fd_cb
, "failed to add the read count: %d", error
);
1623 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1629 if (error
&& packet
!= NULL
) {
1637 flow_divert_send_traffic_class_update(struct flow_divert_pcb
*fd_cb
, int traffic_class
)
1640 mbuf_t packet
= NULL
;
1642 error
= flow_divert_packet_init(fd_cb
, FLOW_DIVERT_PKT_PROPERTIES_UPDATE
, &packet
);
1644 FDLOG(LOG_ERR
, fd_cb
, "failed to create a properties update packet: %d", error
);
1648 error
= flow_divert_packet_append_tlv(packet
, FLOW_DIVERT_TLV_TRAFFIC_CLASS
, sizeof(traffic_class
), &traffic_class
);
1650 FDLOG(LOG_ERR
, fd_cb
, "failed to add the traffic class: %d", error
);
1654 error
= flow_divert_send_packet(fd_cb
, packet
, TRUE
);
1660 if (error
&& packet
!= NULL
) {
1668 flow_divert_handle_connect_result(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
1670 uint32_t connect_error
;
1671 uint32_t ctl_unit
= 0;
1673 struct flow_divert_group
*grp
= NULL
;
1674 struct sockaddr_storage local_address
;
1675 int out_if_index
= 0;
1676 struct sockaddr_storage remote_address
;
1677 uint32_t send_window
;
1678 uint32_t app_data_length
= 0;
1680 memset(&local_address
, 0, sizeof(local_address
));
1681 memset(&remote_address
, 0, sizeof(remote_address
));
1683 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_ERROR_CODE
, sizeof(connect_error
), &connect_error
, NULL
);
1685 FDLOG(LOG_ERR
, fd_cb
, "failed to get the connect result: %d", error
);
1689 FDLOG(LOG_INFO
, fd_cb
, "received connect result %u", connect_error
);
1691 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_SPACE_AVAILABLE
, sizeof(send_window
), &send_window
, NULL
);
1693 FDLOG(LOG_ERR
, fd_cb
, "failed to get the send window: %d", error
);
1697 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), &ctl_unit
, NULL
);
1699 FDLOG0(LOG_INFO
, fd_cb
, "No control unit provided in the connect result");
1702 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_LOCAL_ADDR
, sizeof(local_address
), &local_address
, NULL
);
1704 FDLOG0(LOG_INFO
, fd_cb
, "No local address provided");
1707 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_REMOTE_ADDR
, sizeof(remote_address
), &remote_address
, NULL
);
1709 FDLOG0(LOG_INFO
, fd_cb
, "No remote address provided");
1712 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_OUT_IF_INDEX
, sizeof(out_if_index
), &out_if_index
, NULL
);
1714 FDLOG0(LOG_INFO
, fd_cb
, "No output if index provided");
1717 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_APP_DATA
, 0, NULL
, &app_data_length
);
1719 FDLOG0(LOG_INFO
, fd_cb
, "No application data provided in connect result");
1723 connect_error
= ntohl(connect_error
);
1724 ctl_unit
= ntohl(ctl_unit
);
1726 lck_rw_lock_shared(&g_flow_divert_group_lck
);
1728 if (connect_error
== 0 && ctl_unit
> 0) {
1729 if (ctl_unit
>= GROUP_COUNT_MAX
) {
1730 FDLOG(LOG_ERR
, fd_cb
, "Connect result contains an invalid control unit: %u", ctl_unit
);
1732 } else if (g_flow_divert_groups
== NULL
|| g_active_group_count
== 0) {
1733 FDLOG0(LOG_ERR
, fd_cb
, "No active groups, dropping connection");
1736 grp
= g_flow_divert_groups
[ctl_unit
];
1744 if (fd_cb
->so
!= NULL
) {
1745 struct inpcb
*inp
= NULL
;
1746 struct ifnet
*ifp
= NULL
;
1747 struct flow_divert_group
*old_group
;
1749 socket_lock(fd_cb
->so
, 0);
1751 if (!(fd_cb
->so
->so_state
& SS_ISCONNECTING
)) {
1755 inp
= sotoinpcb(fd_cb
->so
);
1757 if (connect_error
|| error
) {
1758 goto set_socket_state
;
1761 if (local_address
.ss_family
== 0 && fd_cb
->local_address
== NULL
) {
1763 goto set_socket_state
;
1765 if (local_address
.ss_family
!= 0 && fd_cb
->local_address
== NULL
) {
1766 if (local_address
.ss_len
> sizeof(local_address
)) {
1767 local_address
.ss_len
= sizeof(local_address
);
1769 fd_cb
->local_address
= dup_sockaddr((struct sockaddr
*)&local_address
, 1);
1772 if (remote_address
.ss_family
!= 0) {
1773 if (remote_address
.ss_len
> sizeof(remote_address
)) {
1774 remote_address
.ss_len
= sizeof(remote_address
);
1776 fd_cb
->remote_address
= dup_sockaddr((struct sockaddr
*)&remote_address
, 1);
1779 goto set_socket_state
;
1782 if (app_data_length
> 0) {
1783 uint8_t *app_data
= NULL
;
1784 MALLOC(app_data
, uint8_t *, app_data_length
, M_TEMP
, M_WAITOK
);
1785 if (app_data
!= NULL
) {
1786 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_APP_DATA
, app_data_length
, app_data
, NULL
);
1788 FDLOG(LOG_INFO
, fd_cb
, "Got %u bytes of app data from the connect result", app_data_length
);
1789 if (fd_cb
->app_data
!= NULL
) {
1790 FREE(fd_cb
->app_data
, M_TEMP
);
1792 fd_cb
->app_data
= app_data
;
1793 fd_cb
->app_data_length
= app_data_length
;
1795 FDLOG(LOG_ERR
, fd_cb
, "Failed to copy %u bytes of application data from the connect result packet", app_data_length
);
1796 FREE(app_data
, M_TEMP
);
1799 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
);
1803 ifnet_head_lock_shared();
1804 if (out_if_index
> 0 && out_if_index
<= if_index
) {
1805 ifp
= ifindex2ifnet
[out_if_index
];
1809 inp
->inp_last_outifp
= ifp
;
1816 goto set_socket_state
;
1819 if (fd_cb
->group
== NULL
) {
1821 goto set_socket_state
;
1825 old_group
= fd_cb
->group
;
1827 lck_rw_lock_exclusive(&old_group
->lck
);
1828 lck_rw_lock_exclusive(&grp
->lck
);
1830 RB_REMOVE(fd_pcb_tree
, &old_group
->pcb_tree
, fd_cb
);
1831 if (RB_INSERT(fd_pcb_tree
, &grp
->pcb_tree
, fd_cb
) != NULL
) {
1832 panic("group with unit %u already contains a connection with hash %u", grp
->ctl_unit
, fd_cb
->hash
);
1837 lck_rw_done(&grp
->lck
);
1838 lck_rw_done(&old_group
->lck
);
1841 fd_cb
->send_window
= ntohl(send_window
);
1844 if (!connect_error
&& !error
) {
1845 FDLOG0(LOG_INFO
, fd_cb
, "sending connect result");
1846 error
= flow_divert_send_connect_result(fd_cb
);
1849 if (connect_error
|| error
) {
1850 if (!connect_error
) {
1851 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, FALSE
);
1852 fd_cb
->so
->so_error
= error
;
1853 flow_divert_send_close_if_needed(fd_cb
);
1855 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, TRUE
);
1856 fd_cb
->so
->so_error
= connect_error
;
1858 flow_divert_disconnect_socket(fd_cb
->so
);
1860 flow_divert_send_buffered_data(fd_cb
, FALSE
);
1861 soisconnected(fd_cb
->so
);
1865 socket_unlock(fd_cb
->so
, 0);
1869 lck_rw_done(&g_flow_divert_group_lck
);
1873 flow_divert_handle_close(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
1875 uint32_t close_error
;
1879 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_ERROR_CODE
, sizeof(close_error
), &close_error
, NULL
);
1881 FDLOG(LOG_ERR
, fd_cb
, "failed to get the close error: %d", error
);
1885 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_HOW
, sizeof(how
), &how
, NULL
);
1887 FDLOG(LOG_ERR
, fd_cb
, "failed to get the close how flag: %d", error
);
1893 FDLOG(LOG_INFO
, fd_cb
, "close received, how = %d", how
);
1896 if (fd_cb
->so
!= NULL
) {
1897 socket_lock(fd_cb
->so
, 0);
1899 fd_cb
->so
->so_error
= ntohl(close_error
);
1901 flow_divert_update_closed_state(fd_cb
, how
, TRUE
);
1903 how
= flow_divert_tunnel_how_closed(fd_cb
);
1904 if (how
== SHUT_RDWR
) {
1905 flow_divert_disconnect_socket(fd_cb
->so
);
1906 } else if (how
== SHUT_RD
) {
1907 socantrcvmore(fd_cb
->so
);
1908 } else if (how
== SHUT_WR
) {
1909 socantsendmore(fd_cb
->so
);
1912 socket_unlock(fd_cb
->so
, 0);
1918 flow_divert_get_control_mbuf(struct flow_divert_pcb
*fd_cb
)
1920 if (fd_cb
->local_address
!= NULL
) {
1921 struct inpcb
*inp
= sotoinpcb(fd_cb
->so
);
1922 if ((inp
->inp_vflag
& INP_IPV4
) &&
1923 (inp
->inp_flags
& INP_RECVDSTADDR
) &&
1924 fd_cb
->local_address
->sa_family
== AF_INET
&&
1925 fd_cb
->local_address
->sa_len
>= sizeof(struct sockaddr_in
)) {
1926 struct sockaddr_in
*sin
= (struct sockaddr_in
*)(void *)fd_cb
->local_address
;
1928 return sbcreatecontrol((caddr_t
) &sin
->sin_addr
, sizeof(struct in_addr
), IP_RECVDSTADDR
, IPPROTO_IP
);
1929 } else if ((inp
->inp_vflag
& INP_IPV6
) &&
1930 (inp
->inp_flags
& IN6P_PKTINFO
) &&
1931 fd_cb
->local_address
->sa_family
== AF_INET6
&&
1932 fd_cb
->local_address
->sa_len
>= sizeof(struct sockaddr_in6
)) {
1933 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)(void *)fd_cb
->local_address
;
1934 struct in6_pktinfo pi6
;
1936 bcopy(&sin6
->sin6_addr
, &pi6
.ipi6_addr
, sizeof(struct in6_addr
));
1937 pi6
.ipi6_ifindex
= 0;
1938 return sbcreatecontrol((caddr_t
)&pi6
, sizeof(struct in6_pktinfo
), IPV6_PKTINFO
, IPPROTO_IPV6
);
1945 flow_divert_handle_data(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, size_t offset
)
1948 if (fd_cb
->so
!= NULL
) {
1952 struct sockaddr_storage remote_address
;
1953 boolean_t got_remote_sa
= FALSE
;
1955 socket_lock(fd_cb
->so
, 0);
1957 if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
1958 uint32_t val_size
= 0;
1960 /* check if we got remote address with data */
1961 memset(&remote_address
, 0, sizeof(remote_address
));
1962 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_REMOTE_ADDR
, sizeof(remote_address
), &remote_address
, &val_size
);
1963 if (error
|| val_size
> sizeof(remote_address
)) {
1964 FDLOG0(LOG_INFO
, fd_cb
, "No remote address provided");
1967 /* validate the address */
1968 if (flow_divert_is_sockaddr_valid((struct sockaddr
*)&remote_address
)) {
1969 got_remote_sa
= TRUE
;
1971 offset
+= (sizeof(uint8_t) + sizeof(uint32_t) + val_size
);
1975 data_size
= (mbuf_pkthdr_len(packet
) - offset
);
1977 FDLOG(LOG_DEBUG
, fd_cb
, "received %lu bytes of data", data_size
);
1979 error
= mbuf_split(packet
, offset
, MBUF_DONTWAIT
, &data
);
1980 if (error
|| data
== NULL
) {
1981 FDLOG(LOG_ERR
, fd_cb
, "mbuf_split failed: %d", error
);
1983 if (flow_divert_check_no_cellular(fd_cb
) ||
1984 flow_divert_check_no_expensive(fd_cb
)) {
1985 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, TRUE
);
1986 flow_divert_send_close(fd_cb
, SHUT_RDWR
);
1987 flow_divert_disconnect_socket(fd_cb
->so
);
1988 } else if (!(fd_cb
->so
->so_state
& SS_CANTRCVMORE
)) {
1989 if (SOCK_TYPE(fd_cb
->so
) == SOCK_STREAM
) {
1990 if (sbappendstream(&fd_cb
->so
->so_rcv
, data
)) {
1991 fd_cb
->bytes_received
+= data_size
;
1992 flow_divert_add_data_statistics(fd_cb
, data_size
, FALSE
);
1993 fd_cb
->sb_size
= fd_cb
->so
->so_rcv
.sb_cc
;
1994 sorwakeup(fd_cb
->so
);
1997 FDLOG0(LOG_ERR
, fd_cb
, "received data, but appendstream failed");
1999 } else if (SOCK_TYPE(fd_cb
->so
) == SOCK_DGRAM
) {
2000 struct sockaddr
*append_sa
;
2003 if (got_remote_sa
== TRUE
) {
2004 error
= flow_divert_dup_addr(fd_cb
->so
->so_proto
->pr_domain
->dom_family
,
2005 (struct sockaddr
*)&remote_address
, &append_sa
);
2007 error
= flow_divert_dup_addr(fd_cb
->so
->so_proto
->pr_domain
->dom_family
,
2008 fd_cb
->remote_address
, &append_sa
);
2011 FDLOG0(LOG_ERR
, fd_cb
, "failed to dup the socket address.");
2014 mctl
= flow_divert_get_control_mbuf(fd_cb
);
2015 if (sbappendaddr(&fd_cb
->so
->so_rcv
, append_sa
, data
, mctl
, NULL
)) {
2016 fd_cb
->bytes_received
+= data_size
;
2017 flow_divert_add_data_statistics(fd_cb
, data_size
, FALSE
);
2018 fd_cb
->sb_size
= fd_cb
->so
->so_rcv
.sb_cc
;
2019 sorwakeup(fd_cb
->so
);
2022 FDLOG0(LOG_ERR
, fd_cb
, "received data, but sbappendaddr failed");
2025 FREE(append_sa
, M_TEMP
);
2030 socket_unlock(fd_cb
->so
, 0);
2036 flow_divert_handle_read_notification(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
2038 uint32_t read_count
;
2041 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_READ_COUNT
, sizeof(read_count
), &read_count
, NULL
);
2043 FDLOG(LOG_ERR
, fd_cb
, "failed to get the read count: %d", error
);
2047 FDLOG(LOG_DEBUG
, fd_cb
, "received a read notification for %u bytes", ntohl(read_count
));
2050 if (fd_cb
->so
!= NULL
) {
2051 socket_lock(fd_cb
->so
, 0);
2052 fd_cb
->send_window
+= ntohl(read_count
);
2053 flow_divert_send_buffered_data(fd_cb
, FALSE
);
2054 socket_unlock(fd_cb
->so
, 0);
2060 flow_divert_handle_group_init(struct flow_divert_group
*group
, mbuf_t packet
, int offset
)
2063 uint32_t key_size
= 0;
2067 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_TOKEN_KEY
, 0, NULL
, &key_size
);
2069 FDLOG(LOG_ERR
, &nil_pcb
, "failed to get the key size: %d", error
);
2073 if (key_size
== 0 || key_size
> FLOW_DIVERT_MAX_KEY_SIZE
) {
2074 FDLOG(LOG_ERR
, &nil_pcb
, "Invalid key size: %u", key_size
);
2078 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_LOG_LEVEL
, sizeof(log_level
), &log_level
, NULL
);
2080 nil_pcb
.log_level
= log_level
;
2083 lck_rw_lock_exclusive(&group
->lck
);
2085 MALLOC(group
->token_key
, uint8_t *, key_size
, M_TEMP
, M_WAITOK
);
2086 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_TOKEN_KEY
, key_size
, group
->token_key
, NULL
);
2088 FDLOG(LOG_ERR
, &nil_pcb
, "failed to get the token key: %d", error
);
2089 FREE(group
->token_key
, M_TEMP
);
2090 group
->token_key
= NULL
;
2091 lck_rw_done(&group
->lck
);
2095 group
->token_key_size
= key_size
;
2097 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_FLAGS
, sizeof(flags
), &flags
, NULL
);
2099 group
->flags
= flags
;
2102 lck_rw_done(&group
->lck
);
2106 flow_divert_handle_properties_update(struct flow_divert_pcb
*fd_cb
, mbuf_t packet
, int offset
)
2109 struct sockaddr_storage local_address
;
2110 int out_if_index
= 0;
2111 struct sockaddr_storage remote_address
;
2112 uint32_t app_data_length
= 0;
2114 FDLOG0(LOG_INFO
, fd_cb
, "received a properties update");
2116 memset(&local_address
, 0, sizeof(local_address
));
2117 memset(&remote_address
, 0, sizeof(remote_address
));
2119 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_LOCAL_ADDR
, sizeof(local_address
), &local_address
, NULL
);
2121 FDLOG0(LOG_INFO
, fd_cb
, "No local address provided in properties update");
2124 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_REMOTE_ADDR
, sizeof(remote_address
), &remote_address
, NULL
);
2126 FDLOG0(LOG_INFO
, fd_cb
, "No remote address provided in properties update");
2129 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_OUT_IF_INDEX
, sizeof(out_if_index
), &out_if_index
, NULL
);
2131 FDLOG0(LOG_INFO
, fd_cb
, "No output if index provided in properties update");
2134 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_APP_DATA
, 0, NULL
, &app_data_length
);
2136 FDLOG0(LOG_INFO
, fd_cb
, "No application data provided in properties update");
2140 if (fd_cb
->so
!= NULL
) {
2141 socket_lock(fd_cb
->so
, 0);
2143 if (local_address
.ss_family
!= 0) {
2144 if (local_address
.ss_len
> sizeof(local_address
)) {
2145 local_address
.ss_len
= sizeof(local_address
);
2147 if (fd_cb
->local_address
!= NULL
) {
2148 FREE(fd_cb
->local_address
, M_SONAME
);
2149 fd_cb
->local_address
= NULL
;
2151 fd_cb
->local_address
= dup_sockaddr((struct sockaddr
*)&local_address
, 1);
2154 if (remote_address
.ss_family
!= 0) {
2155 if (remote_address
.ss_len
> sizeof(remote_address
)) {
2156 remote_address
.ss_len
= sizeof(remote_address
);
2158 if (fd_cb
->remote_address
!= NULL
) {
2159 FREE(fd_cb
->remote_address
, M_SONAME
);
2160 fd_cb
->remote_address
= NULL
;
2162 fd_cb
->remote_address
= dup_sockaddr((struct sockaddr
*)&remote_address
, 1);
2165 if (out_if_index
> 0) {
2166 struct inpcb
*inp
= NULL
;
2167 struct ifnet
*ifp
= NULL
;
2169 inp
= sotoinpcb(fd_cb
->so
);
2171 ifnet_head_lock_shared();
2172 if (out_if_index
<= if_index
) {
2173 ifp
= ifindex2ifnet
[out_if_index
];
2177 inp
->inp_last_outifp
= ifp
;
2182 if (app_data_length
> 0) {
2183 uint8_t *app_data
= NULL
;
2184 MALLOC(app_data
, uint8_t *, app_data_length
, M_TEMP
, M_WAITOK
);
2185 if (app_data
!= NULL
) {
2186 error
= flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_APP_DATA
, app_data_length
, app_data
, NULL
);
2188 if (fd_cb
->app_data
!= NULL
) {
2189 FREE(fd_cb
->app_data
, M_TEMP
);
2191 fd_cb
->app_data
= app_data
;
2192 fd_cb
->app_data_length
= app_data_length
;
2194 FDLOG(LOG_ERR
, fd_cb
, "Failed to copy %u bytes of application data from the properties update packet", app_data_length
);
2195 FREE(app_data
, M_TEMP
);
2198 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
);
2202 socket_unlock(fd_cb
->so
, 0);
2208 flow_divert_handle_app_map_create(struct flow_divert_group
*group
, mbuf_t packet
, int offset
)
2210 size_t bytes_mem_size
;
2211 size_t child_maps_mem_size
;
2214 struct flow_divert_trie new_trie
;
2215 int insert_error
= 0;
2216 size_t nodes_mem_size
;
2217 int prefix_count
= 0;
2218 int signing_id_count
= 0;
2219 size_t trie_memory_size
= 0;
2221 lck_rw_lock_exclusive(&group
->lck
);
2223 /* Re-set the current trie */
2224 if (group
->signing_id_trie
.memory
!= NULL
) {
2225 FREE(group
->signing_id_trie
.memory
, M_TEMP
);
2227 memset(&group
->signing_id_trie
, 0, sizeof(group
->signing_id_trie
));
2228 group
->signing_id_trie
.root
= NULL_TRIE_IDX
;
2230 memset(&new_trie
, 0, sizeof(new_trie
));
2232 /* Get the number of shared prefixes in the new set of signing ID strings */
2233 flow_divert_packet_get_tlv(packet
, offset
, FLOW_DIVERT_TLV_PREFIX_COUNT
, sizeof(prefix_count
), &prefix_count
, NULL
);
2235 if (prefix_count
< 0) {
2236 lck_rw_done(&group
->lck
);
2240 /* Compute the number of signing IDs and the total amount of bytes needed to store them */
2241 for (cursor
= flow_divert_packet_find_tlv(packet
, offset
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 0);
2243 cursor
= flow_divert_packet_find_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 1)) {
2244 uint32_t sid_size
= 0;
2245 flow_divert_packet_get_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, 0, NULL
, &sid_size
);
2246 new_trie
.bytes_count
+= sid_size
;
2250 if (signing_id_count
== 0) {
2251 lck_rw_done(&group
->lck
);
2255 new_trie
.nodes_count
= (prefix_count
+ signing_id_count
+ 1); /* + 1 for the root node */
2256 new_trie
.child_maps_count
= (prefix_count
+ 1); /* + 1 for the root node */
2258 FDLOG(LOG_INFO
, &nil_pcb
, "Nodes count = %lu, child maps count = %lu, bytes_count = %lu",
2259 new_trie
.nodes_count
, new_trie
.child_maps_count
, new_trie
.bytes_count
);
2261 nodes_mem_size
= (sizeof(*new_trie
.nodes
) * new_trie
.nodes_count
);
2262 child_maps_mem_size
= (sizeof(*new_trie
.child_maps
) * CHILD_MAP_SIZE
* new_trie
.child_maps_count
);
2263 bytes_mem_size
= (sizeof(*new_trie
.bytes
) * new_trie
.bytes_count
);
2265 trie_memory_size
= nodes_mem_size
+ child_maps_mem_size
+ bytes_mem_size
;
2266 if (trie_memory_size
> FLOW_DIVERT_MAX_TRIE_MEMORY
) {
2267 FDLOG(LOG_ERR
, &nil_pcb
, "Trie memory size (%lu) is too big (maximum is %u)", trie_memory_size
, FLOW_DIVERT_MAX_TRIE_MEMORY
);
2268 lck_rw_done(&group
->lck
);
2272 MALLOC(new_trie
.memory
, void *, trie_memory_size
, M_TEMP
, M_WAITOK
);
2273 if (new_trie
.memory
== NULL
) {
2274 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to allocate %lu bytes of memory for the signing ID trie",
2275 nodes_mem_size
+ child_maps_mem_size
+ bytes_mem_size
);
2276 lck_rw_done(&group
->lck
);
2280 /* Initialize the free lists */
2281 new_trie
.nodes
= (struct flow_divert_trie_node
*)new_trie
.memory
;
2282 new_trie
.nodes_free_next
= 0;
2283 memset(new_trie
.nodes
, 0, nodes_mem_size
);
2285 new_trie
.child_maps
= (uint16_t *)(void *)((uint8_t *)new_trie
.memory
+ nodes_mem_size
);
2286 new_trie
.child_maps_free_next
= 0;
2287 memset(new_trie
.child_maps
, 0xff, child_maps_mem_size
);
2289 new_trie
.bytes
= (uint8_t *)(void *)((uint8_t *)new_trie
.memory
+ nodes_mem_size
+ child_maps_mem_size
);
2290 new_trie
.bytes_free_next
= 0;
2292 /* The root is an empty node */
2293 new_trie
.root
= trie_node_alloc(&new_trie
);
2295 /* Add each signing ID to the trie */
2296 for (cursor
= flow_divert_packet_find_tlv(packet
, offset
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 0);
2298 cursor
= flow_divert_packet_find_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, &error
, 1)) {
2299 uint32_t sid_size
= 0;
2300 flow_divert_packet_get_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, 0, NULL
, &sid_size
);
2301 if (new_trie
.bytes_free_next
+ sid_size
<= new_trie
.bytes_count
) {
2302 uint16_t new_node_idx
;
2303 flow_divert_packet_get_tlv(packet
, cursor
, FLOW_DIVERT_TLV_SIGNING_ID
, sid_size
, &TRIE_BYTE(&new_trie
, new_trie
.bytes_free_next
), NULL
);
2304 new_node_idx
= flow_divert_trie_insert(&new_trie
, new_trie
.bytes_free_next
, sid_size
);
2305 if (new_node_idx
== NULL_TRIE_IDX
) {
2306 insert_error
= EINVAL
;
2310 FDLOG0(LOG_ERR
, &nil_pcb
, "No place to put signing ID for insertion");
2311 insert_error
= ENOBUFS
;
2316 if (!insert_error
) {
2317 group
->signing_id_trie
= new_trie
;
2319 FREE(new_trie
.memory
, M_TEMP
);
2322 lck_rw_done(&group
->lck
);
2326 flow_divert_input(mbuf_t packet
, struct flow_divert_group
*group
)
2328 struct flow_divert_packet_header hdr
;
2330 struct flow_divert_pcb
*fd_cb
;
2332 if (mbuf_pkthdr_len(packet
) < sizeof(hdr
)) {
2333 FDLOG(LOG_ERR
, &nil_pcb
, "got a bad packet, length (%lu) < sizeof hdr (%lu)", mbuf_pkthdr_len(packet
), sizeof(hdr
));
2338 if (mbuf_pkthdr_len(packet
) > FD_CTL_RCVBUFF_SIZE
) {
2339 FDLOG(LOG_ERR
, &nil_pcb
, "got a bad packet, length (%lu) > %d", mbuf_pkthdr_len(packet
), FD_CTL_RCVBUFF_SIZE
);
2344 error
= mbuf_copydata(packet
, 0, sizeof(hdr
), &hdr
);
2346 FDLOG(LOG_ERR
, &nil_pcb
, "mbuf_copydata failed for the header: %d", error
);
2351 hdr
.conn_id
= ntohl(hdr
.conn_id
);
2353 if (hdr
.conn_id
== 0) {
2354 switch (hdr
.packet_type
) {
2355 case FLOW_DIVERT_PKT_GROUP_INIT
:
2356 flow_divert_handle_group_init(group
, packet
, sizeof(hdr
));
2358 case FLOW_DIVERT_PKT_APP_MAP_CREATE
:
2359 flow_divert_handle_app_map_create(group
, packet
, sizeof(hdr
));
2362 FDLOG(LOG_WARNING
, &nil_pcb
, "got an unknown message type: %d", hdr
.packet_type
);
2368 fd_cb
= flow_divert_pcb_lookup(hdr
.conn_id
, group
); /* This retains the PCB */
2369 if (fd_cb
== NULL
) {
2370 if (hdr
.packet_type
!= FLOW_DIVERT_PKT_CLOSE
&& hdr
.packet_type
!= FLOW_DIVERT_PKT_READ_NOTIFY
) {
2371 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
);
2376 switch (hdr
.packet_type
) {
2377 case FLOW_DIVERT_PKT_CONNECT_RESULT
:
2378 flow_divert_handle_connect_result(fd_cb
, packet
, sizeof(hdr
));
2380 case FLOW_DIVERT_PKT_CLOSE
:
2381 flow_divert_handle_close(fd_cb
, packet
, sizeof(hdr
));
2383 case FLOW_DIVERT_PKT_DATA
:
2384 flow_divert_handle_data(fd_cb
, packet
, sizeof(hdr
));
2386 case FLOW_DIVERT_PKT_READ_NOTIFY
:
2387 flow_divert_handle_read_notification(fd_cb
, packet
, sizeof(hdr
));
2389 case FLOW_DIVERT_PKT_PROPERTIES_UPDATE
:
2390 flow_divert_handle_properties_update(fd_cb
, packet
, sizeof(hdr
));
2393 FDLOG(LOG_WARNING
, fd_cb
, "got an unknown message type: %d", hdr
.packet_type
);
2405 flow_divert_close_all(struct flow_divert_group
*group
)
2407 struct flow_divert_pcb
*fd_cb
;
2408 SLIST_HEAD(, flow_divert_pcb
) tmp_list
;
2410 SLIST_INIT(&tmp_list
);
2412 lck_rw_lock_exclusive(&group
->lck
);
2414 MBUFQ_DRAIN(&group
->send_queue
);
2416 RB_FOREACH(fd_cb
, fd_pcb_tree
, &group
->pcb_tree
) {
2418 SLIST_INSERT_HEAD(&tmp_list
, fd_cb
, tmp_list_entry
);
2421 lck_rw_done(&group
->lck
);
2423 while (!SLIST_EMPTY(&tmp_list
)) {
2424 fd_cb
= SLIST_FIRST(&tmp_list
);
2426 SLIST_REMOVE_HEAD(&tmp_list
, tmp_list_entry
);
2427 if (fd_cb
->so
!= NULL
) {
2428 socket_lock(fd_cb
->so
, 0);
2429 flow_divert_pcb_remove(fd_cb
);
2430 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, TRUE
);
2431 fd_cb
->so
->so_error
= ECONNABORTED
;
2432 flow_divert_disconnect_socket(fd_cb
->so
);
2433 socket_unlock(fd_cb
->so
, 0);
2441 flow_divert_detach(struct socket
*so
)
2443 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2445 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2447 so
->so_flags
&= ~SOF_FLOW_DIVERT
;
2448 so
->so_fd_pcb
= NULL
;
2450 FDLOG(LOG_INFO
, fd_cb
, "Detaching, ref count = %d", fd_cb
->ref_count
);
2452 if (fd_cb
->group
!= NULL
) {
2453 /* Last-ditch effort to send any buffered data */
2454 flow_divert_send_buffered_data(fd_cb
, TRUE
);
2456 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, FALSE
);
2457 flow_divert_send_close_if_needed(fd_cb
);
2458 /* Remove from the group */
2459 flow_divert_pcb_remove(fd_cb
);
2462 socket_unlock(so
, 0);
2468 FDRELEASE(fd_cb
); /* Release the socket's reference */
2472 flow_divert_close(struct socket
*so
)
2474 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2476 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2478 FDLOG0(LOG_INFO
, fd_cb
, "Closing");
2480 if (SOCK_TYPE(so
) == SOCK_STREAM
) {
2481 soisdisconnecting(so
);
2482 sbflush(&so
->so_rcv
);
2485 flow_divert_send_buffered_data(fd_cb
, TRUE
);
2486 flow_divert_update_closed_state(fd_cb
, SHUT_RDWR
, FALSE
);
2487 flow_divert_send_close_if_needed(fd_cb
);
2489 /* Remove from the group */
2490 flow_divert_pcb_remove(fd_cb
);
2496 flow_divert_disconnectx(struct socket
*so
, sae_associd_t aid
,
2497 sae_connid_t cid __unused
)
2499 if (aid
!= SAE_ASSOCID_ANY
&& aid
!= SAE_ASSOCID_ALL
) {
2503 return flow_divert_close(so
);
2507 flow_divert_shutdown(struct socket
*so
)
2509 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2511 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2513 FDLOG0(LOG_INFO
, fd_cb
, "Can't send more");
2517 flow_divert_update_closed_state(fd_cb
, SHUT_WR
, FALSE
);
2518 flow_divert_send_close_if_needed(fd_cb
);
2524 flow_divert_rcvd(struct socket
*so
, int flags __unused
)
2526 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2527 uint32_t latest_sb_size
;
2528 uint32_t read_count
;
2530 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2532 latest_sb_size
= fd_cb
->so
->so_rcv
.sb_cc
;
2534 if (fd_cb
->sb_size
< latest_sb_size
) {
2535 panic("flow divert rcvd event handler (%u): saved rcv buffer size (%u) is less than latest rcv buffer size (%u)",
2536 fd_cb
->hash
, fd_cb
->sb_size
, latest_sb_size
);
2539 read_count
= fd_cb
->sb_size
- latest_sb_size
;
2541 FDLOG(LOG_DEBUG
, fd_cb
, "app read %u bytes", read_count
);
2543 if (read_count
> 0 && flow_divert_send_read_notification(fd_cb
, read_count
) == 0) {
2544 fd_cb
->bytes_read_by_app
+= read_count
;
2545 fd_cb
->sb_size
= latest_sb_size
;
2552 flow_divert_append_target_endpoint_tlv(mbuf_t connect_packet
, struct sockaddr
*toaddr
)
2557 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_TARGET_ADDRESS
, toaddr
->sa_len
, toaddr
);
2562 if (toaddr
->sa_family
== AF_INET
) {
2563 port
= ntohs((satosin(toaddr
))->sin_port
);
2567 port
= ntohs((satosin6(toaddr
))->sin6_port
);
2571 error
= flow_divert_packet_append_tlv(connect_packet
, FLOW_DIVERT_TLV_TARGET_PORT
, sizeof(port
), &port
);
2581 flow_divert_get_buffered_target_address(mbuf_t buffer
)
2583 if (buffer
!= NULL
&& buffer
->m_type
== MT_SONAME
) {
2584 struct sockaddr
*toaddr
= mtod(buffer
, struct sockaddr
*);
2585 if (toaddr
!= NULL
&& flow_divert_is_sockaddr_valid(toaddr
)) {
2593 flow_divert_is_sockaddr_valid(struct sockaddr
*addr
)
2595 switch (addr
->sa_family
) {
2597 if (addr
->sa_len
!= sizeof(struct sockaddr_in
)) {
2603 if (addr
->sa_len
!= sizeof(struct sockaddr_in6
)) {
2615 flow_divert_inp_to_sockaddr(const struct inpcb
*inp
, struct sockaddr
**local_socket
)
2618 union sockaddr_in_4_6 sin46
;
2620 bzero(&sin46
, sizeof(sin46
));
2621 if (inp
->inp_vflag
& INP_IPV4
) {
2622 struct sockaddr_in
*sin
= &sin46
.sin
;
2624 sin
->sin_family
= AF_INET
;
2625 sin
->sin_len
= sizeof(*sin
);
2626 sin
->sin_port
= inp
->inp_lport
;
2627 sin
->sin_addr
= inp
->inp_laddr
;
2628 } else if (inp
->inp_vflag
& INP_IPV6
) {
2629 struct sockaddr_in6
*sin6
= &sin46
.sin6
;
2631 sin6
->sin6_len
= sizeof(*sin6
);
2632 sin6
->sin6_family
= AF_INET6
;
2633 sin6
->sin6_port
= inp
->inp_lport
;
2634 sin6
->sin6_addr
= inp
->in6p_laddr
;
2636 *local_socket
= dup_sockaddr((struct sockaddr
*)&sin46
, 1);
2637 if (*local_socket
== NULL
) {
2644 flow_divert_has_pcb_local_address(const struct inpcb
*inp
)
2646 return inp
->inp_lport
!= 0
2647 && (inp
->inp_laddr
.s_addr
!= INADDR_ANY
|| !IN6_IS_ADDR_UNSPECIFIED(&inp
->in6p_laddr
));
2651 flow_divert_dup_addr(sa_family_t family
, struct sockaddr
*addr
,
2652 struct sockaddr
**dup
)
2655 struct sockaddr
*result
;
2656 struct sockaddr_storage ss
;
2661 memset(&ss
, 0, sizeof(ss
));
2662 ss
.ss_family
= family
;
2663 if (ss
.ss_family
== AF_INET
) {
2664 ss
.ss_len
= sizeof(struct sockaddr_in
);
2667 else if (ss
.ss_family
== AF_INET6
) {
2668 ss
.ss_len
= sizeof(struct sockaddr_in6
);
2674 result
= (struct sockaddr
*)&ss
;
2678 *dup
= dup_sockaddr(result
, 1);
2688 flow_divert_disconnect_socket(struct socket
*so
)
2690 soisdisconnected(so
);
2691 if (SOCK_TYPE(so
) == SOCK_DGRAM
) {
2692 struct inpcb
*inp
= NULL
;
2694 inp
= sotoinpcb(so
);
2697 if (SOCK_CHECK_DOM(so
, PF_INET6
)) {
2707 flow_divert_getpeername(struct socket
*so
, struct sockaddr
**sa
)
2709 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2711 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2713 return flow_divert_dup_addr(so
->so_proto
->pr_domain
->dom_family
,
2714 fd_cb
->remote_address
,
2719 flow_divert_getsockaddr(struct socket
*so
, struct sockaddr
**sa
)
2721 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2723 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2725 return flow_divert_dup_addr(so
->so_proto
->pr_domain
->dom_family
,
2726 fd_cb
->local_address
,
2731 flow_divert_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
2733 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2735 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2737 if (sopt
->sopt_name
== SO_TRAFFIC_CLASS
) {
2738 if (sopt
->sopt_dir
== SOPT_SET
&& fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
) {
2739 flow_divert_send_traffic_class_update(fd_cb
, so
->so_traffic_class
);
2743 if (SOCK_DOM(so
) == PF_INET
) {
2744 return g_tcp_protosw
->pr_ctloutput(so
, sopt
);
2747 else if (SOCK_DOM(so
) == PF_INET6
) {
2748 return g_tcp6_protosw
->pr_ctloutput(so
, sopt
);
2755 flow_divert_connect_out(struct socket
*so
, struct sockaddr
*to
, proc_t p
)
2757 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2759 struct inpcb
*inp
= sotoinpcb(so
);
2760 struct sockaddr_in
*sinp
;
2761 mbuf_t connect_packet
= NULL
;
2764 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
2766 if (fd_cb
->group
== NULL
) {
2767 error
= ENETUNREACH
;
2774 } else if (inp
->inp_state
== INPCB_STATE_DEAD
) {
2776 error
= so
->so_error
;
2784 if ((fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
) && !(fd_cb
->flags
& FLOW_DIVERT_TRANSFERRED
)) {
2789 if (fd_cb
->flags
& FLOW_DIVERT_TRANSFERRED
) {
2790 FDLOG0(LOG_INFO
, fd_cb
, "fully transferred");
2791 fd_cb
->flags
&= ~FLOW_DIVERT_TRANSFERRED
;
2792 if (fd_cb
->remote_address
!= NULL
) {
2793 soisconnected(fd_cb
->so
);
2798 FDLOG0(LOG_INFO
, fd_cb
, "Connecting");
2800 if (fd_cb
->connect_packet
== NULL
) {
2802 FDLOG0(LOG_ERR
, fd_cb
, "No destination address available when creating connect packet");
2807 sinp
= (struct sockaddr_in
*)(void *)to
;
2808 if (sinp
->sin_family
== AF_INET
&& IN_MULTICAST(ntohl(sinp
->sin_addr
.s_addr
))) {
2809 error
= EAFNOSUPPORT
;
2813 error
= flow_divert_create_connect_packet(fd_cb
, to
, so
, p
, &connect_packet
);
2818 if (so
->so_flags1
& SOF1_PRECONNECT_DATA
) {
2819 FDLOG0(LOG_INFO
, fd_cb
, "Delaying sending the connect packet until send or receive");
2823 FDLOG0(LOG_INFO
, fd_cb
, "Sending saved connect packet");
2824 connect_packet
= fd_cb
->connect_packet
;
2825 fd_cb
->connect_packet
= NULL
;
2829 error
= flow_divert_send_packet(fd_cb
, connect_packet
, TRUE
);
2834 fd_cb
->flags
|= FLOW_DIVERT_CONNECT_STARTED
;
2836 fd_cb
->connect_packet
= connect_packet
;
2837 connect_packet
= NULL
;
2843 if (error
&& connect_packet
!= NULL
) {
2844 mbuf_freem(connect_packet
);
2850 flow_divert_connectx_out_common(struct socket
*so
, struct sockaddr
*dst
,
2851 struct proc
*p
, sae_connid_t
*pcid
, struct uio
*auio
, user_ssize_t
*bytes_written
)
2853 struct inpcb
*inp
= sotoinpcb(so
);
2860 VERIFY(dst
!= NULL
);
2862 error
= flow_divert_connect_out(so
, dst
, p
);
2868 /* if there is data, send it */
2870 user_ssize_t datalen
= 0;
2872 socket_unlock(so
, 0);
2874 VERIFY(bytes_written
!= NULL
);
2876 datalen
= uio_resid(auio
);
2877 error
= so
->so_proto
->pr_usrreqs
->pru_sosend(so
, NULL
, (uio_t
)auio
, NULL
, NULL
, 0);
2880 if (error
== 0 || error
== EWOULDBLOCK
) {
2881 *bytes_written
= datalen
- uio_resid(auio
);
2885 * sosend returns EWOULDBLOCK if it's a non-blocking
2886 * socket or a timeout occured (this allows to return
2887 * the amount of queued data through sendit()).
2889 * However, connectx() returns EINPROGRESS in case of a
2890 * blocking socket. So we change the return value here.
2892 if (error
== EWOULDBLOCK
) {
2893 error
= EINPROGRESS
;
2897 if (error
== 0 && pcid
!= NULL
) {
2898 *pcid
= 1; /* there is only 1 connection for a TCP */
2905 flow_divert_connectx_out(struct socket
*so
, struct sockaddr
*src __unused
,
2906 struct sockaddr
*dst
, struct proc
*p
, uint32_t ifscope __unused
,
2907 sae_associd_t aid __unused
, sae_connid_t
*pcid
, uint32_t flags __unused
, void *arg __unused
,
2908 uint32_t arglen __unused
, struct uio
*uio
, user_ssize_t
*bytes_written
)
2910 return flow_divert_connectx_out_common(so
, dst
, p
, pcid
, uio
, bytes_written
);
2915 flow_divert_connectx6_out(struct socket
*so
, struct sockaddr
*src __unused
,
2916 struct sockaddr
*dst
, struct proc
*p
, uint32_t ifscope __unused
,
2917 sae_associd_t aid __unused
, sae_connid_t
*pcid
, uint32_t flags __unused
, void *arg __unused
,
2918 uint32_t arglen __unused
, struct uio
*uio
, user_ssize_t
*bytes_written
)
2920 return flow_divert_connectx_out_common(so
, dst
, p
, pcid
, uio
, bytes_written
);
2925 flow_divert_getconninfo(struct socket
*so
, sae_connid_t cid
, uint32_t *flags
,
2926 uint32_t *ifindex
, int32_t *soerror
, user_addr_t src
, socklen_t
*src_len
,
2927 user_addr_t dst
, socklen_t
*dst_len
, uint32_t *aux_type
,
2928 user_addr_t aux_data __unused
, uint32_t *aux_len
)
2931 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
2932 struct ifnet
*ifp
= NULL
;
2933 struct inpcb
*inp
= sotoinpcb(so
);
2935 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
));
2937 if (so
->so_fd_pcb
== NULL
|| inp
== NULL
) {
2942 if (cid
!= SAE_CONNID_ANY
&& cid
!= SAE_CONNID_ALL
&& cid
!= 1) {
2947 ifp
= inp
->inp_last_outifp
;
2948 *ifindex
= ((ifp
!= NULL
) ? ifp
->if_index
: 0);
2949 *soerror
= so
->so_error
;
2952 if (so
->so_state
& SS_ISCONNECTED
) {
2953 *flags
|= (CIF_CONNECTED
| CIF_PREFERRED
);
2956 if (fd_cb
->local_address
== NULL
) {
2957 struct sockaddr_in sin
;
2958 bzero(&sin
, sizeof(sin
));
2959 sin
.sin_len
= sizeof(sin
);
2960 sin
.sin_family
= AF_INET
;
2961 *src_len
= sin
.sin_len
;
2962 if (src
!= USER_ADDR_NULL
) {
2963 error
= copyout(&sin
, src
, sin
.sin_len
);
2969 *src_len
= fd_cb
->local_address
->sa_len
;
2970 if (src
!= USER_ADDR_NULL
) {
2971 error
= copyout(fd_cb
->local_address
, src
, fd_cb
->local_address
->sa_len
);
2978 if (fd_cb
->remote_address
== NULL
) {
2979 struct sockaddr_in sin
;
2980 bzero(&sin
, sizeof(sin
));
2981 sin
.sin_len
= sizeof(sin
);
2982 sin
.sin_family
= AF_INET
;
2983 *dst_len
= sin
.sin_len
;
2984 if (dst
!= USER_ADDR_NULL
) {
2985 error
= copyout(&sin
, dst
, sin
.sin_len
);
2991 *dst_len
= fd_cb
->remote_address
->sa_len
;
2992 if (dst
!= USER_ADDR_NULL
) {
2993 error
= copyout(fd_cb
->remote_address
, dst
, fd_cb
->remote_address
->sa_len
);
3008 flow_divert_control(struct socket
*so
, u_long cmd
, caddr_t data
, struct ifnet
*ifp __unused
, struct proc
*p __unused
)
3013 case SIOCGCONNINFO32
: {
3014 struct so_cinforeq32 cifr
;
3015 bcopy(data
, &cifr
, sizeof(cifr
));
3016 error
= flow_divert_getconninfo(so
, cifr
.scir_cid
, &cifr
.scir_flags
,
3017 &cifr
.scir_ifindex
, &cifr
.scir_error
, cifr
.scir_src
,
3018 &cifr
.scir_src_len
, cifr
.scir_dst
, &cifr
.scir_dst_len
,
3019 &cifr
.scir_aux_type
, cifr
.scir_aux_data
,
3020 &cifr
.scir_aux_len
);
3022 bcopy(&cifr
, data
, sizeof(cifr
));
3027 case SIOCGCONNINFO64
: {
3028 struct so_cinforeq64 cifr
;
3029 bcopy(data
, &cifr
, sizeof(cifr
));
3030 error
= flow_divert_getconninfo(so
, cifr
.scir_cid
, &cifr
.scir_flags
,
3031 &cifr
.scir_ifindex
, &cifr
.scir_error
, cifr
.scir_src
,
3032 &cifr
.scir_src_len
, cifr
.scir_dst
, &cifr
.scir_dst_len
,
3033 &cifr
.scir_aux_type
, cifr
.scir_aux_data
,
3034 &cifr
.scir_aux_len
);
3036 bcopy(&cifr
, data
, sizeof(cifr
));
3049 flow_divert_in_control(struct socket
*so
, u_long cmd
, caddr_t data
, struct ifnet
*ifp
, struct proc
*p
)
3051 int error
= flow_divert_control(so
, cmd
, data
, ifp
, p
);
3053 if (error
== EOPNOTSUPP
) {
3054 error
= in_control(so
, cmd
, data
, ifp
, p
);
3061 flow_divert_in6_control(struct socket
*so
, u_long cmd
, caddr_t data
, struct ifnet
*ifp
, struct proc
*p
)
3063 int error
= flow_divert_control(so
, cmd
, data
, ifp
, p
);
3065 if (error
== EOPNOTSUPP
) {
3066 error
= in6_control(so
, cmd
, data
, ifp
, p
);
3073 flow_divert_data_out(struct socket
*so
, int flags
, mbuf_t data
, struct sockaddr
*to
, mbuf_t control
, struct proc
*p
)
3075 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3079 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
3081 inp
= sotoinpcb(so
);
3082 if (inp
== NULL
|| inp
->inp_state
== INPCB_STATE_DEAD
) {
3087 if (control
&& mbuf_len(control
) > 0) {
3092 if (flags
& MSG_OOB
) {
3094 goto done
; /* We don't support OOB data */
3097 error
= flow_divert_check_no_cellular(fd_cb
) ||
3098 flow_divert_check_no_expensive(fd_cb
);
3103 /* Implicit connect */
3104 if (!(fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
)) {
3105 FDLOG0(LOG_INFO
, fd_cb
, "implicit connect");
3106 error
= flow_divert_connect_out(so
, to
, p
);
3111 if (so
->so_flags1
& SOF1_DATA_IDEMPOTENT
) {
3112 /* Open up the send window so that the data will get sent right away */
3113 fd_cb
->send_window
= mbuf_pkthdr_len(data
);
3117 FDLOG(LOG_DEBUG
, fd_cb
, "app wrote %lu bytes", mbuf_pkthdr_len(data
));
3119 fd_cb
->bytes_written_by_app
+= mbuf_pkthdr_len(data
);
3120 error
= flow_divert_send_app_data(fd_cb
, data
, to
);
3127 if (flags
& PRUS_EOF
) {
3128 flow_divert_shutdown(so
);
3142 flow_divert_preconnect(struct socket
*so
)
3144 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3147 if (!(fd_cb
->flags
& FLOW_DIVERT_CONNECT_STARTED
) && fd_cb
->connect_packet
!= NULL
) {
3148 FDLOG0(LOG_INFO
, fd_cb
, "Pre-connect read: sending saved connect packet");
3149 mbuf_t connect_packet
= fd_cb
->connect_packet
;
3150 fd_cb
->connect_packet
= NULL
;
3152 error
= flow_divert_send_packet(fd_cb
, connect_packet
, TRUE
);
3154 mbuf_freem(connect_packet
);
3157 fd_cb
->flags
|= FLOW_DIVERT_CONNECT_STARTED
;
3160 soclearfastopen(so
);
3166 flow_divert_set_protosw(struct socket
*so
)
3168 so
->so_flags
|= SOF_FLOW_DIVERT
;
3169 if (SOCK_DOM(so
) == PF_INET
) {
3170 so
->so_proto
= &g_flow_divert_in_protosw
;
3174 so
->so_proto
= (struct protosw
*)&g_flow_divert_in6_protosw
;
3180 flow_divert_set_udp_protosw(struct socket
*so
)
3182 so
->so_flags
|= SOF_FLOW_DIVERT
;
3183 if (SOCK_DOM(so
) == PF_INET
) {
3184 so
->so_proto
= &g_flow_divert_in_udp_protosw
;
3188 so
->so_proto
= (struct protosw
*)&g_flow_divert_in6_udp_protosw
;
3194 flow_divert_attach(struct socket
*so
, uint32_t flow_id
, uint32_t ctl_unit
)
3197 struct flow_divert_pcb
*fd_cb
= NULL
;
3198 struct ifnet
*ifp
= NULL
;
3199 struct inpcb
*inp
= NULL
;
3200 struct socket
*old_so
;
3201 mbuf_t recv_data
= NULL
;
3203 socket_unlock(so
, 0);
3205 FDLOG(LOG_INFO
, &nil_pcb
, "Attaching socket to flow %u", flow_id
);
3207 /* Find the flow divert control block */
3208 lck_rw_lock_shared(&g_flow_divert_group_lck
);
3209 if (g_flow_divert_groups
!= NULL
&& g_active_group_count
> 0) {
3210 struct flow_divert_group
*group
= g_flow_divert_groups
[ctl_unit
];
3211 if (group
!= NULL
) {
3212 fd_cb
= flow_divert_pcb_lookup(flow_id
, group
);
3215 lck_rw_done(&g_flow_divert_group_lck
);
3217 if (fd_cb
== NULL
) {
3224 /* Dis-associate the flow divert control block from its current socket */
3227 inp
= sotoinpcb(old_so
);
3229 VERIFY(inp
!= NULL
);
3231 socket_lock(old_so
, 0);
3232 flow_divert_disconnect_socket(old_so
);
3233 old_so
->so_flags
&= ~SOF_FLOW_DIVERT
;
3234 old_so
->so_fd_pcb
= NULL
;
3235 if (SOCK_TYPE(old_so
) == SOCK_STREAM
) {
3236 old_so
->so_proto
= pffindproto(SOCK_DOM(old_so
), IPPROTO_TCP
, SOCK_STREAM
);
3237 } else if (SOCK_TYPE(old_so
) == SOCK_DGRAM
) {
3238 old_so
->so_proto
= pffindproto(SOCK_DOM(old_so
), IPPROTO_UDP
, SOCK_DGRAM
);
3241 /* Save the output interface */
3242 ifp
= inp
->inp_last_outifp
;
3243 if (old_so
->so_rcv
.sb_cc
> 0) {
3244 error
= mbuf_dup(old_so
->so_rcv
.sb_mb
, MBUF_DONTWAIT
, &recv_data
);
3245 sbflush(&old_so
->so_rcv
);
3247 socket_unlock(old_so
, 0);
3249 /* Associate the new socket with the flow divert control block */
3251 so
->so_fd_pcb
= fd_cb
;
3252 inp
= sotoinpcb(so
);
3253 inp
->inp_last_outifp
= ifp
;
3254 if (recv_data
!= NULL
) {
3255 if (sbappendstream(&so
->so_rcv
, recv_data
)) {
3259 flow_divert_set_protosw(so
);
3260 socket_unlock(so
, 0);
3263 fd_cb
->flags
|= FLOW_DIVERT_TRANSFERRED
;
3270 if (fd_cb
!= NULL
) {
3271 FDRELEASE(fd_cb
); /* Release the reference obtained via flow_divert_pcb_lookup */
3278 flow_divert_implicit_data_out(struct socket
*so
, int flags
, mbuf_t data
, struct sockaddr
*to
, mbuf_t control
, struct proc
*p
)
3280 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3284 inp
= sotoinpcb(so
);
3289 if (fd_cb
== NULL
) {
3290 uint32_t fd_ctl_unit
= necp_socket_get_flow_divert_control_unit(inp
);
3291 if (fd_ctl_unit
> 0) {
3292 error
= flow_divert_pcb_init(so
, fd_ctl_unit
);
3293 fd_cb
= so
->so_fd_pcb
;
3294 if (error
!= 0 || fd_cb
== NULL
) {
3302 return flow_divert_data_out(so
, flags
, data
, to
, control
, p
);
3316 flow_divert_pcb_init(struct socket
*so
, uint32_t ctl_unit
)
3319 struct flow_divert_pcb
*fd_cb
;
3321 if (so
->so_flags
& SOF_FLOW_DIVERT
) {
3325 fd_cb
= flow_divert_pcb_create(so
);
3326 if (fd_cb
!= NULL
) {
3327 error
= flow_divert_pcb_insert(fd_cb
, ctl_unit
);
3329 FDLOG(LOG_ERR
, fd_cb
, "pcb insert failed: %d", error
);
3332 fd_cb
->control_group_unit
= ctl_unit
;
3333 so
->so_fd_pcb
= fd_cb
;
3335 if (SOCK_TYPE(so
) == SOCK_STREAM
) {
3336 flow_divert_set_protosw(so
);
3337 } else if (SOCK_TYPE(so
) == SOCK_DGRAM
) {
3338 flow_divert_set_udp_protosw(so
);
3341 FDLOG0(LOG_INFO
, fd_cb
, "Created");
3351 flow_divert_token_set(struct socket
*so
, struct sockopt
*sopt
)
3353 uint32_t ctl_unit
= 0;
3354 uint32_t key_unit
= 0;
3355 uint32_t flow_id
= 0;
3358 mbuf_t token
= NULL
;
3360 if (so
->so_flags
& SOF_FLOW_DIVERT
) {
3365 if (g_init_result
) {
3366 FDLOG(LOG_ERR
, &nil_pcb
, "flow_divert_init failed (%d), cannot use flow divert", g_init_result
);
3367 error
= ENOPROTOOPT
;
3371 if ((SOCK_TYPE(so
) != SOCK_STREAM
&& SOCK_TYPE(so
) != SOCK_DGRAM
) ||
3372 (SOCK_PROTO(so
) != IPPROTO_TCP
&& SOCK_PROTO(so
) != IPPROTO_UDP
) ||
3373 (SOCK_DOM(so
) != PF_INET
3375 && SOCK_DOM(so
) != PF_INET6
3381 if (SOCK_TYPE(so
) == SOCK_STREAM
&& SOCK_PROTO(so
) == IPPROTO_TCP
) {
3382 struct tcpcb
*tp
= sototcpcb(so
);
3383 if (tp
== NULL
|| tp
->t_state
!= TCPS_CLOSED
) {
3390 error
= soopt_getm(sopt
, &token
);
3396 error
= soopt_mcopyin(sopt
, token
);
3402 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_KEY_UNIT
, sizeof(key_unit
), (void *)&key_unit
, NULL
);
3404 key_unit
= ntohl(key_unit
);
3405 if (key_unit
>= GROUP_COUNT_MAX
) {
3408 } else if (error
!= ENOENT
) {
3409 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to get the key unit from the token: %d", error
);
3415 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), (void *)&ctl_unit
, NULL
);
3417 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to get the control socket unit from the token: %d", error
);
3421 /* A valid kernel control unit is required */
3422 ctl_unit
= ntohl(ctl_unit
);
3423 if (ctl_unit
== 0 || ctl_unit
>= GROUP_COUNT_MAX
) {
3424 FDLOG(LOG_ERR
, &nil_pcb
, "Got an invalid control socket unit: %u", ctl_unit
);
3429 socket_unlock(so
, 0);
3430 hmac_error
= flow_divert_packet_verify_hmac(token
, (key_unit
!= 0 ? key_unit
: ctl_unit
));
3433 if (hmac_error
&& hmac_error
!= ENOENT
) {
3434 FDLOG(LOG_ERR
, &nil_pcb
, "HMAC verfication failed: %d", hmac_error
);
3439 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_FLOW_ID
, sizeof(flow_id
), (void *)&flow_id
, NULL
);
3440 if (error
&& error
!= ENOENT
) {
3441 FDLOG(LOG_ERR
, &nil_pcb
, "Failed to get the flow ID from the token: %d", error
);
3446 error
= flow_divert_pcb_init(so
, ctl_unit
);
3448 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3449 int log_level
= LOG_NOTICE
;
3451 error
= flow_divert_packet_get_tlv(token
, 0, FLOW_DIVERT_TLV_LOG_LEVEL
,
3452 sizeof(log_level
), &log_level
, NULL
);
3454 fd_cb
->log_level
= log_level
;
3458 fd_cb
->connect_token
= token
;
3462 error
= flow_divert_attach(so
, flow_id
, ctl_unit
);
3465 if (hmac_error
== 0) {
3466 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3467 if (fd_cb
!= NULL
) {
3468 fd_cb
->flags
|= FLOW_DIVERT_HAS_HMAC
;
3473 if (token
!= NULL
) {
3481 flow_divert_token_get(struct socket
*so
, struct sockopt
*sopt
)
3485 uint8_t hmac
[SHA_DIGEST_LENGTH
];
3486 struct flow_divert_pcb
*fd_cb
= so
->so_fd_pcb
;
3487 mbuf_t token
= NULL
;
3488 struct flow_divert_group
*control_group
= NULL
;
3490 if (!(so
->so_flags
& SOF_FLOW_DIVERT
)) {
3495 VERIFY((so
->so_flags
& SOF_FLOW_DIVERT
) && so
->so_fd_pcb
!= NULL
);
3497 if (fd_cb
->group
== NULL
) {
3502 error
= mbuf_gethdr(MBUF_DONTWAIT
, MBUF_TYPE_HEADER
, &token
);
3504 FDLOG(LOG_ERR
, fd_cb
, "failed to allocate the header mbuf: %d", error
);
3508 ctl_unit
= htonl(fd_cb
->group
->ctl_unit
);
3510 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_CTL_UNIT
, sizeof(ctl_unit
), &ctl_unit
);
3515 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_FLOW_ID
, sizeof(fd_cb
->hash
), &fd_cb
->hash
);
3520 if (fd_cb
->app_data
!= NULL
) {
3521 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_APP_DATA
, fd_cb
->app_data_length
, fd_cb
->app_data
);
3527 socket_unlock(so
, 0);
3528 lck_rw_lock_shared(&g_flow_divert_group_lck
);
3530 if (g_flow_divert_groups
!= NULL
&& g_active_group_count
> 0 &&
3531 fd_cb
->control_group_unit
> 0 && fd_cb
->control_group_unit
< GROUP_COUNT_MAX
) {
3532 control_group
= g_flow_divert_groups
[fd_cb
->control_group_unit
];
3535 if (control_group
!= NULL
) {
3536 lck_rw_lock_shared(&control_group
->lck
);
3537 ctl_unit
= htonl(control_group
->ctl_unit
);
3538 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_KEY_UNIT
, sizeof(ctl_unit
), &ctl_unit
);
3540 error
= flow_divert_packet_compute_hmac(token
, control_group
, hmac
);
3542 lck_rw_done(&control_group
->lck
);
3544 error
= ENOPROTOOPT
;
3547 lck_rw_done(&g_flow_divert_group_lck
);
3554 error
= flow_divert_packet_append_tlv(token
, FLOW_DIVERT_TLV_HMAC
, sizeof(hmac
), hmac
);
3559 if (sopt
->sopt_val
== USER_ADDR_NULL
) {
3560 /* If the caller passed NULL to getsockopt, just set the size of the token and return */
3561 sopt
->sopt_valsize
= mbuf_pkthdr_len(token
);
3565 error
= soopt_mcopyout(sopt
, token
);
3567 token
= NULL
; /* For some reason, soopt_mcopyout() frees the mbuf if it fails */
3572 if (token
!= NULL
) {
3580 flow_divert_kctl_connect(kern_ctl_ref kctlref __unused
, struct sockaddr_ctl
*sac
, void **unitinfo
)
3582 struct flow_divert_group
*new_group
= NULL
;
3585 if (sac
->sc_unit
>= GROUP_COUNT_MAX
) {
3592 MALLOC_ZONE(new_group
, struct flow_divert_group
*, sizeof(*new_group
), M_FLOW_DIVERT_GROUP
, M_WAITOK
);
3593 if (new_group
== NULL
) {
3598 memset(new_group
, 0, sizeof(*new_group
));
3600 lck_rw_init(&new_group
->lck
, flow_divert_mtx_grp
, flow_divert_mtx_attr
);
3601 RB_INIT(&new_group
->pcb_tree
);
3602 new_group
->ctl_unit
= sac
->sc_unit
;
3603 MBUFQ_INIT(&new_group
->send_queue
);
3604 new_group
->signing_id_trie
.root
= NULL_TRIE_IDX
;
3606 lck_rw_lock_exclusive(&g_flow_divert_group_lck
);
3608 if (g_flow_divert_groups
== NULL
) {
3609 MALLOC(g_flow_divert_groups
,
3610 struct flow_divert_group
**,
3611 GROUP_COUNT_MAX
* sizeof(struct flow_divert_group
*),
3616 if (g_flow_divert_groups
== NULL
) {
3618 } else if (g_flow_divert_groups
[sac
->sc_unit
] != NULL
) {
3621 g_flow_divert_groups
[sac
->sc_unit
] = new_group
;
3622 g_active_group_count
++;
3625 lck_rw_done(&g_flow_divert_group_lck
);
3627 *unitinfo
= new_group
;
3630 if (error
!= 0 && new_group
!= NULL
) {
3631 FREE_ZONE(new_group
, sizeof(*new_group
), M_FLOW_DIVERT_GROUP
);
3637 flow_divert_kctl_disconnect(kern_ctl_ref kctlref __unused
, uint32_t unit
, void *unitinfo
)
3639 struct flow_divert_group
*group
= NULL
;
3642 if (unit
>= GROUP_COUNT_MAX
) {
3646 FDLOG(LOG_INFO
, &nil_pcb
, "disconnecting group %d", unit
);
3648 lck_rw_lock_exclusive(&g_flow_divert_group_lck
);
3650 if (g_flow_divert_groups
== NULL
|| g_active_group_count
== 0) {
3651 panic("flow divert group %u is disconnecting, but no groups are active (groups = %p, active count = %u", unit
,
3652 g_flow_divert_groups
, g_active_group_count
);
3655 group
= g_flow_divert_groups
[unit
];
3657 if (group
!= (struct flow_divert_group
*)unitinfo
) {
3658 panic("group with unit %d (%p) != unit info (%p)", unit
, group
, unitinfo
);
3661 if (group
!= NULL
) {
3662 flow_divert_close_all(group
);
3663 if (group
->token_key
!= NULL
) {
3664 memset(group
->token_key
, 0, group
->token_key_size
);
3665 FREE(group
->token_key
, M_TEMP
);
3666 group
->token_key
= NULL
;
3667 group
->token_key_size
= 0;
3670 /* Re-set the current trie */
3671 if (group
->signing_id_trie
.memory
!= NULL
) {
3672 FREE(group
->signing_id_trie
.memory
, M_TEMP
);
3674 memset(&group
->signing_id_trie
, 0, sizeof(group
->signing_id_trie
));
3675 group
->signing_id_trie
.root
= NULL_TRIE_IDX
;
3677 FREE_ZONE(group
, sizeof(*group
), M_FLOW_DIVERT_GROUP
);
3678 g_flow_divert_groups
[unit
] = NULL
;
3679 g_active_group_count
--;
3684 if (g_active_group_count
== 0) {
3685 FREE(g_flow_divert_groups
, M_TEMP
);
3686 g_flow_divert_groups
= NULL
;
3689 lck_rw_done(&g_flow_divert_group_lck
);
3695 flow_divert_kctl_send(kern_ctl_ref kctlref __unused
, uint32_t unit __unused
, void *unitinfo
, mbuf_t m
, int flags __unused
)
3697 return flow_divert_input(m
, (struct flow_divert_group
*)unitinfo
);
3701 flow_divert_kctl_rcvd(kern_ctl_ref kctlref __unused
, uint32_t unit __unused
, void *unitinfo
, int flags __unused
)
3703 struct flow_divert_group
*group
= (struct flow_divert_group
*)unitinfo
;
3705 if (!OSTestAndClear(GROUP_BIT_CTL_ENQUEUE_BLOCKED
, &group
->atomic_bits
)) {
3706 struct flow_divert_pcb
*fd_cb
;
3707 SLIST_HEAD(, flow_divert_pcb
) tmp_list
;
3709 lck_rw_lock_shared(&g_flow_divert_group_lck
);
3710 lck_rw_lock_exclusive(&group
->lck
);
3712 while (!MBUFQ_EMPTY(&group
->send_queue
)) {
3714 FDLOG0(LOG_DEBUG
, &nil_pcb
, "trying ctl_enqueuembuf again");
3715 next_packet
= MBUFQ_FIRST(&group
->send_queue
);
3716 int error
= ctl_enqueuembuf(g_flow_divert_kctl_ref
, group
->ctl_unit
, next_packet
, CTL_DATA_EOR
);
3718 FDLOG(LOG_DEBUG
, &nil_pcb
, "ctl_enqueuembuf returned an error: %d", error
);
3719 OSTestAndSet(GROUP_BIT_CTL_ENQUEUE_BLOCKED
, &group
->atomic_bits
);
3720 lck_rw_done(&group
->lck
);
3721 lck_rw_done(&g_flow_divert_group_lck
);
3724 MBUFQ_DEQUEUE(&group
->send_queue
, next_packet
);
3727 SLIST_INIT(&tmp_list
);
3729 RB_FOREACH(fd_cb
, fd_pcb_tree
, &group
->pcb_tree
) {
3731 SLIST_INSERT_HEAD(&tmp_list
, fd_cb
, tmp_list_entry
);
3734 lck_rw_done(&group
->lck
);
3736 SLIST_FOREACH(fd_cb
, &tmp_list
, tmp_list_entry
) {
3738 if (fd_cb
->so
!= NULL
) {
3739 socket_lock(fd_cb
->so
, 0);
3740 if (fd_cb
->group
!= NULL
) {
3741 flow_divert_send_buffered_data(fd_cb
, FALSE
);
3743 socket_unlock(fd_cb
->so
, 0);
3749 lck_rw_done(&g_flow_divert_group_lck
);
3754 flow_divert_kctl_init(void)
3756 struct kern_ctl_reg ctl_reg
;
3759 memset(&ctl_reg
, 0, sizeof(ctl_reg
));
3761 strlcpy(ctl_reg
.ctl_name
, FLOW_DIVERT_CONTROL_NAME
, sizeof(ctl_reg
.ctl_name
));
3762 ctl_reg
.ctl_name
[sizeof(ctl_reg
.ctl_name
) - 1] = '\0';
3763 ctl_reg
.ctl_flags
= CTL_FLAG_PRIVILEGED
| CTL_FLAG_REG_EXTENDED
;
3764 ctl_reg
.ctl_sendsize
= FD_CTL_SENDBUFF_SIZE
;
3765 ctl_reg
.ctl_recvsize
= FD_CTL_RCVBUFF_SIZE
;
3767 ctl_reg
.ctl_connect
= flow_divert_kctl_connect
;
3768 ctl_reg
.ctl_disconnect
= flow_divert_kctl_disconnect
;
3769 ctl_reg
.ctl_send
= flow_divert_kctl_send
;
3770 ctl_reg
.ctl_rcvd
= flow_divert_kctl_rcvd
;
3772 result
= ctl_register(&ctl_reg
, &g_flow_divert_kctl_ref
);
3775 FDLOG(LOG_ERR
, &nil_pcb
, "flow_divert_kctl_init - ctl_register failed: %d\n", result
);
3783 flow_divert_init(void)
3785 memset(&nil_pcb
, 0, sizeof(nil_pcb
));
3786 nil_pcb
.log_level
= LOG_NOTICE
;
3788 g_tcp_protosw
= pffindproto(AF_INET
, IPPROTO_TCP
, SOCK_STREAM
);
3790 VERIFY(g_tcp_protosw
!= NULL
);
3792 memcpy(&g_flow_divert_in_protosw
, g_tcp_protosw
, sizeof(g_flow_divert_in_protosw
));
3793 memcpy(&g_flow_divert_in_usrreqs
, g_tcp_protosw
->pr_usrreqs
, sizeof(g_flow_divert_in_usrreqs
));
3795 g_flow_divert_in_usrreqs
.pru_connect
= flow_divert_connect_out
;
3796 g_flow_divert_in_usrreqs
.pru_connectx
= flow_divert_connectx_out
;
3797 g_flow_divert_in_usrreqs
.pru_control
= flow_divert_in_control
;
3798 g_flow_divert_in_usrreqs
.pru_disconnect
= flow_divert_close
;
3799 g_flow_divert_in_usrreqs
.pru_disconnectx
= flow_divert_disconnectx
;
3800 g_flow_divert_in_usrreqs
.pru_peeraddr
= flow_divert_getpeername
;
3801 g_flow_divert_in_usrreqs
.pru_rcvd
= flow_divert_rcvd
;
3802 g_flow_divert_in_usrreqs
.pru_send
= flow_divert_data_out
;
3803 g_flow_divert_in_usrreqs
.pru_shutdown
= flow_divert_shutdown
;
3804 g_flow_divert_in_usrreqs
.pru_sockaddr
= flow_divert_getsockaddr
;
3805 g_flow_divert_in_usrreqs
.pru_preconnect
= flow_divert_preconnect
;
3807 g_flow_divert_in_protosw
.pr_usrreqs
= &g_flow_divert_in_usrreqs
;
3808 g_flow_divert_in_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
3811 * Socket filters shouldn't attach/detach to/from this protosw
3812 * since pr_protosw is to be used instead, which points to the
3813 * real protocol; if they do, it is a bug and we should panic.
3815 g_flow_divert_in_protosw
.pr_filter_head
.tqh_first
=
3816 (struct socket_filter
*)(uintptr_t)0xdeadbeefdeadbeef;
3817 g_flow_divert_in_protosw
.pr_filter_head
.tqh_last
=
3818 (struct socket_filter
**)(uintptr_t)0xdeadbeefdeadbeef;
3821 g_udp_protosw
= pffindproto(AF_INET
, IPPROTO_UDP
, SOCK_DGRAM
);
3822 VERIFY(g_udp_protosw
!= NULL
);
3824 memcpy(&g_flow_divert_in_udp_protosw
, g_udp_protosw
, sizeof(g_flow_divert_in_udp_protosw
));
3825 memcpy(&g_flow_divert_in_udp_usrreqs
, g_udp_protosw
->pr_usrreqs
, sizeof(g_flow_divert_in_udp_usrreqs
));
3827 g_flow_divert_in_udp_usrreqs
.pru_connect
= flow_divert_connect_out
;
3828 g_flow_divert_in_udp_usrreqs
.pru_connectx
= flow_divert_connectx_out
;
3829 g_flow_divert_in_udp_usrreqs
.pru_control
= flow_divert_in_control
;
3830 g_flow_divert_in_udp_usrreqs
.pru_disconnect
= flow_divert_close
;
3831 g_flow_divert_in_udp_usrreqs
.pru_disconnectx
= flow_divert_disconnectx
;
3832 g_flow_divert_in_udp_usrreqs
.pru_peeraddr
= flow_divert_getpeername
;
3833 g_flow_divert_in_udp_usrreqs
.pru_rcvd
= flow_divert_rcvd
;
3834 g_flow_divert_in_udp_usrreqs
.pru_send
= flow_divert_data_out
;
3835 g_flow_divert_in_udp_usrreqs
.pru_shutdown
= flow_divert_shutdown
;
3836 g_flow_divert_in_udp_usrreqs
.pru_sockaddr
= flow_divert_getsockaddr
;
3837 g_flow_divert_in_udp_usrreqs
.pru_sosend_list
= pru_sosend_list_notsupp
;
3838 g_flow_divert_in_udp_usrreqs
.pru_soreceive_list
= pru_soreceive_list_notsupp
;
3839 g_flow_divert_in_udp_usrreqs
.pru_preconnect
= flow_divert_preconnect
;
3841 g_flow_divert_in_udp_protosw
.pr_usrreqs
= &g_flow_divert_in_usrreqs
;
3842 g_flow_divert_in_udp_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
3845 * Socket filters shouldn't attach/detach to/from this protosw
3846 * since pr_protosw is to be used instead, which points to the
3847 * real protocol; if they do, it is a bug and we should panic.
3849 g_flow_divert_in_udp_protosw
.pr_filter_head
.tqh_first
=
3850 (struct socket_filter
*)(uintptr_t)0xdeadbeefdeadbeef;
3851 g_flow_divert_in_udp_protosw
.pr_filter_head
.tqh_last
=
3852 (struct socket_filter
**)(uintptr_t)0xdeadbeefdeadbeef;
3855 g_tcp6_protosw
= (struct ip6protosw
*)pffindproto(AF_INET6
, IPPROTO_TCP
, SOCK_STREAM
);
3857 VERIFY(g_tcp6_protosw
!= NULL
);
3859 memcpy(&g_flow_divert_in6_protosw
, g_tcp6_protosw
, sizeof(g_flow_divert_in6_protosw
));
3860 memcpy(&g_flow_divert_in6_usrreqs
, g_tcp6_protosw
->pr_usrreqs
, sizeof(g_flow_divert_in6_usrreqs
));
3862 g_flow_divert_in6_usrreqs
.pru_connect
= flow_divert_connect_out
;
3863 g_flow_divert_in6_usrreqs
.pru_connectx
= flow_divert_connectx6_out
;
3864 g_flow_divert_in6_usrreqs
.pru_control
= flow_divert_in6_control
;
3865 g_flow_divert_in6_usrreqs
.pru_disconnect
= flow_divert_close
;
3866 g_flow_divert_in6_usrreqs
.pru_disconnectx
= flow_divert_disconnectx
;
3867 g_flow_divert_in6_usrreqs
.pru_peeraddr
= flow_divert_getpeername
;
3868 g_flow_divert_in6_usrreqs
.pru_rcvd
= flow_divert_rcvd
;
3869 g_flow_divert_in6_usrreqs
.pru_send
= flow_divert_data_out
;
3870 g_flow_divert_in6_usrreqs
.pru_shutdown
= flow_divert_shutdown
;
3871 g_flow_divert_in6_usrreqs
.pru_sockaddr
= flow_divert_getsockaddr
;
3872 g_flow_divert_in6_usrreqs
.pru_preconnect
= flow_divert_preconnect
;
3874 g_flow_divert_in6_protosw
.pr_usrreqs
= &g_flow_divert_in6_usrreqs
;
3875 g_flow_divert_in6_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
3877 * Socket filters shouldn't attach/detach to/from this protosw
3878 * since pr_protosw is to be used instead, which points to the
3879 * real protocol; if they do, it is a bug and we should panic.
3881 g_flow_divert_in6_protosw
.pr_filter_head
.tqh_first
=
3882 (struct socket_filter
*)(uintptr_t)0xdeadbeefdeadbeef;
3883 g_flow_divert_in6_protosw
.pr_filter_head
.tqh_last
=
3884 (struct socket_filter
**)(uintptr_t)0xdeadbeefdeadbeef;
3887 g_udp6_protosw
= (struct ip6protosw
*)pffindproto(AF_INET6
, IPPROTO_UDP
, SOCK_DGRAM
);
3889 VERIFY(g_udp6_protosw
!= NULL
);
3891 memcpy(&g_flow_divert_in6_udp_protosw
, g_udp6_protosw
, sizeof(g_flow_divert_in6_udp_protosw
));
3892 memcpy(&g_flow_divert_in6_udp_usrreqs
, g_udp6_protosw
->pr_usrreqs
, sizeof(g_flow_divert_in6_udp_usrreqs
));
3894 g_flow_divert_in6_udp_usrreqs
.pru_connect
= flow_divert_connect_out
;
3895 g_flow_divert_in6_udp_usrreqs
.pru_connectx
= flow_divert_connectx6_out
;
3896 g_flow_divert_in6_udp_usrreqs
.pru_control
= flow_divert_in6_control
;
3897 g_flow_divert_in6_udp_usrreqs
.pru_disconnect
= flow_divert_close
;
3898 g_flow_divert_in6_udp_usrreqs
.pru_disconnectx
= flow_divert_disconnectx
;
3899 g_flow_divert_in6_udp_usrreqs
.pru_peeraddr
= flow_divert_getpeername
;
3900 g_flow_divert_in6_udp_usrreqs
.pru_rcvd
= flow_divert_rcvd
;
3901 g_flow_divert_in6_udp_usrreqs
.pru_send
= flow_divert_data_out
;
3902 g_flow_divert_in6_udp_usrreqs
.pru_shutdown
= flow_divert_shutdown
;
3903 g_flow_divert_in6_udp_usrreqs
.pru_sockaddr
= flow_divert_getsockaddr
;
3904 g_flow_divert_in6_udp_usrreqs
.pru_sosend_list
= pru_sosend_list_notsupp
;
3905 g_flow_divert_in6_udp_usrreqs
.pru_soreceive_list
= pru_soreceive_list_notsupp
;
3906 g_flow_divert_in6_udp_usrreqs
.pru_preconnect
= flow_divert_preconnect
;
3908 g_flow_divert_in6_udp_protosw
.pr_usrreqs
= &g_flow_divert_in6_udp_usrreqs
;
3909 g_flow_divert_in6_udp_protosw
.pr_ctloutput
= flow_divert_ctloutput
;
3911 * Socket filters shouldn't attach/detach to/from this protosw
3912 * since pr_protosw is to be used instead, which points to the
3913 * real protocol; if they do, it is a bug and we should panic.
3915 g_flow_divert_in6_udp_protosw
.pr_filter_head
.tqh_first
=
3916 (struct socket_filter
*)(uintptr_t)0xdeadbeefdeadbeef;
3917 g_flow_divert_in6_udp_protosw
.pr_filter_head
.tqh_last
=
3918 (struct socket_filter
**)(uintptr_t)0xdeadbeefdeadbeef;
3921 flow_divert_grp_attr
= lck_grp_attr_alloc_init();
3922 if (flow_divert_grp_attr
== NULL
) {
3923 FDLOG0(LOG_ERR
, &nil_pcb
, "lck_grp_attr_alloc_init failed");
3924 g_init_result
= ENOMEM
;
3928 flow_divert_mtx_grp
= lck_grp_alloc_init(FLOW_DIVERT_CONTROL_NAME
, flow_divert_grp_attr
);
3929 if (flow_divert_mtx_grp
== NULL
) {
3930 FDLOG0(LOG_ERR
, &nil_pcb
, "lck_grp_alloc_init failed");
3931 g_init_result
= ENOMEM
;
3935 flow_divert_mtx_attr
= lck_attr_alloc_init();
3936 if (flow_divert_mtx_attr
== NULL
) {
3937 FDLOG0(LOG_ERR
, &nil_pcb
, "lck_attr_alloc_init failed");
3938 g_init_result
= ENOMEM
;
3942 g_init_result
= flow_divert_kctl_init();
3943 if (g_init_result
) {
3947 lck_rw_init(&g_flow_divert_group_lck
, flow_divert_mtx_grp
, flow_divert_mtx_attr
);
3950 if (g_init_result
!= 0) {
3951 if (flow_divert_mtx_attr
!= NULL
) {
3952 lck_attr_free(flow_divert_mtx_attr
);
3953 flow_divert_mtx_attr
= NULL
;
3955 if (flow_divert_mtx_grp
!= NULL
) {
3956 lck_grp_free(flow_divert_mtx_grp
);
3957 flow_divert_mtx_grp
= NULL
;
3959 if (flow_divert_grp_attr
!= NULL
) {
3960 lck_grp_attr_free(flow_divert_grp_attr
);
3961 flow_divert_grp_attr
= NULL
;
3964 if (g_flow_divert_kctl_ref
!= NULL
) {
3965 ctl_deregister(g_flow_divert_kctl_ref
);
3966 g_flow_divert_kctl_ref
= NULL
;