xref: /xnu-12377.81.4/tests/tcp_cache_test.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
1 /*
2  * Copyright (c) 2025 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <darwintest.h>
30 #include <sys/sysctl.h>
31 #include <netinet/tcp_cache.h>
32 #include <arpa/inet.h>
33 #include <stdlib.h>
34 
35 T_DECL(tcp_cache_list_sysctl, "Test retrieving TCP cache list via sysctl")
36 {
37 	size_t size = 0;
38 	int ret;
39 
40 	// First call to get the required buffer size
41 	ret = sysctlbyname("net.inet.tcp.cache_list", NULL, &size, NULL, 0);
42 	if (ret == -1) {
43 		T_SKIP("sysctlbyname(\"net.inet.tcp.cache_list\") error: %d", errno);
44 	}
45 
46 	T_LOG("TCP cache list size: %zu bytes", size);
47 
48 	if (size == 0) {
49 		T_PASS("No TCP cache entries found");
50 	}
51 
52 	// Allocate buffer and retrieve the data
53 	void *buffer = malloc(size);
54 	T_QUIET; T_ASSERT_NOTNULL(buffer, "malloc buffer");
55 
56 	ret = sysctlbyname("net.inet.tcp.cache_list", buffer, &size, NULL, 0);
57 	T_ASSERT_POSIX_SUCCESS(ret, "sysctlbyname to get data");
58 
59 	// Calculate number of entries
60 	size_t num_entries = size / sizeof(struct tcp_cache_data);
61 	T_LOG("Found %zu TCP cache entries", num_entries);
62 
63 	struct tcp_cache_data *entries = (struct tcp_cache_data *)buffer;
64 
65 	// Log all fields of each entry
66 	for (size_t i = 0; i < num_entries; i++) {
67 		struct tcp_cache_data *entry = &entries[i];
68 
69 		T_LOG("Entry %zu:", i);
70 		T_LOG("  tc_last_access: %u", entry->tc_last_access);
71 		T_LOG("  tc_key.tck_family: %d", entry->tc_key.tck_family);
72 
73 		// Log source key info
74 		T_LOG("  tc_key.tck_src.thk_family: %d", entry->tc_key.tck_src.thk_family);
75 		if (entry->tc_key.tck_src.thk_family == AF_INET) {
76 			T_LOG("  tc_key.tck_src IP: %s", inet_ntoa(entry->tc_key.tck_src.thk_ip.addr));
77 		} else if (entry->tc_key.tck_src.thk_family == AF_INET6) {
78 			char addr_str[INET6_ADDRSTRLEN];
79 			inet_ntop(AF_INET6, &entry->tc_key.tck_src.thk_ip.addr6, addr_str, sizeof(addr_str));
80 			T_LOG("  tc_key.tck_src IPv6: %s", addr_str);
81 		}
82 
83 		// Log destination address
84 		if (entry->tc_key.tck_family == AF_INET) {
85 			T_LOG("  tc_key.tck_dst IP: %s", inet_ntoa(entry->tc_key.tck_dst.addr));
86 		} else if (entry->tc_key.tck_family == AF_INET6) {
87 			char addr_str[INET6_ADDRSTRLEN];
88 			inet_ntop(AF_INET6, &entry->tc_key.tck_dst.addr6, addr_str, sizeof(addr_str));
89 			T_LOG("  tc_key.tck_dst IPv6: %s", addr_str);
90 		}
91 
92 		// Log TFO cookie info
93 		T_LOG("  tc_tfo_cookie_len: %u", entry->tc_tfo_cookie_len);
94 		if (entry->tc_tfo_cookie_len > 0) {
95 			char cookie_hex[TFO_COOKIE_LEN_MAX * 2 + 1] = {0};
96 			for (int j = 0; j < entry->tc_tfo_cookie_len && j < TFO_COOKIE_LEN_MAX; j++) {
97 				snprintf(cookie_hex + j * 2, 3, "%02x", entry->tc_tfo_cookie[j]);
98 			}
99 			T_LOG("  tc_tfo_cookie: %s", cookie_hex);
100 		}
101 
102 		// Log MPTCP info
103 		T_LOG("  tc_mptcp_version_confirmed: %u", entry->tc_mptcp_version_confirmed);
104 		T_LOG("  tc_mptcp_version: %u", entry->tc_mptcp_version);
105 		T_LOG("  tc_mptcp_next_version_try: %u", entry->tc_mptcp_next_version_try);
106 		T_LOG(""); // Empty line between entries
107 	}
108 
109 	free(buffer);
110 
111 	T_PASS("%s", __func__);
112 }
113 
114 T_DECL(tcp_heuristics_list_sysctl, "Test retrieving TCP heuristics list via sysctl")
115 {
116 	size_t size = 0;
117 	int ret;
118 
119 	// First call to get the required buffer size
120 	ret = sysctlbyname("net.inet.tcp.heuristics_list", NULL, &size, NULL, 0);
121 	if (ret == -1) {
122 		T_SKIP("sysctlbyname(\"net.inet.tcp.cache_list\") error: %d", errno);
123 	}
124 
125 	T_LOG("TCP heuristics list size: %zu bytes", size);
126 
127 	if (size == 0) {
128 		T_PASS("No TCP heuristics entries found");
129 	}
130 
131 	// Allocate buffer and retrieve the data
132 	void *buffer = malloc(size);
133 	T_QUIET; T_ASSERT_NOTNULL(buffer, "malloc buffer");
134 
135 	ret = sysctlbyname("net.inet.tcp.heuristics_list", buffer, &size, NULL, 0);
136 	T_ASSERT_POSIX_SUCCESS(ret, "sysctlbyname to get data");
137 
138 	// Calculate number of entries
139 	size_t num_entries = size / sizeof(struct tcp_heuristics_data);
140 	T_LOG("Found %zu TCP heuristics entries", num_entries);
141 
142 	struct tcp_heuristics_data *entries = (struct tcp_heuristics_data *)buffer;
143 
144 	// Log all fields of each entry
145 	for (size_t i = 0; i < num_entries; i++) {
146 		struct tcp_heuristics_data *entry = &entries[i];
147 
148 		T_LOG("Heuristics Entry %zu:", i);
149 		T_LOG("  th_last_access: %u", entry->th_last_access);
150 		T_LOG("  th_key.thk_family: %d", entry->th_key.thk_family);
151 
152 		// Log source key info
153 		if (entry->th_key.thk_family == AF_INET) {
154 			T_LOG("  th_key.thk_ip IP: %s", inet_ntoa(entry->th_key.thk_ip.addr));
155 		} else if (entry->th_key.thk_family == AF_INET6) {
156 			char addr_str[INET6_ADDRSTRLEN];
157 			inet_ntop(AF_INET6, &entry->th_key.thk_ip.addr6, addr_str, sizeof(addr_str));
158 			T_LOG("  th_key.thk_ip IPv6: %s", addr_str);
159 		}
160 
161 		// Log TFO heuristics
162 		T_LOG("  th_tfo_data_loss: %u", entry->th_tfo_data_loss);
163 		T_LOG("  th_tfo_req_loss: %u", entry->th_tfo_req_loss);
164 		T_LOG("  th_tfo_data_rst: %u", entry->th_tfo_data_rst);
165 
166 
167 		T_LOG("  th_tfo_req_rst: %u", entry->th_tfo_req_rst);
168 
169 		// Log MPTCP heuristics
170 		T_LOG("  th_mptcp_loss: %u", entry->th_mptcp_loss);
171 		T_LOG("  th_mptcp_success: %u", entry->th_mptcp_success);
172 
173 		// Log ECN heuristics
174 		T_LOG("  th_ecn_droprst: %u", entry->th_ecn_droprst);
175 		T_LOG("  th_ecn_synrst: %u", entry->th_ecn_synrst);
176 
177 		// Log timing information
178 		T_LOG("  th_tfo_enabled_time: %u", entry->th_tfo_enabled_time);
179 		T_LOG("  th_tfo_backoff_until: %u", entry->th_tfo_backoff_until);
180 		T_LOG("  th_tfo_backoff: %u", entry->th_tfo_backoff);
181 		T_LOG("  th_mptcp_backoff: %u", entry->th_mptcp_backoff);
182 		T_LOG("  th_ecn_backoff: %u", entry->th_ecn_backoff);
183 
184 		// Log flags
185 		T_LOG("  th_tfo_in_backoff: %u", entry->th_tfo_in_backoff);
186 		T_LOG("  th_mptcp_in_backoff: %u", entry->th_mptcp_in_backoff);
187 		T_LOG("  th_mptcp_heuristic_disabled: %u", entry->th_mptcp_heuristic_disabled);
188 		T_LOG(""); // Empty line between entries
189 	}
190 
191 	free(buffer);
192 
193 	T_PASS("%s", __func__);
194 }
195