1/*
2 * Copyright (c) 2023 Apple 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 <sys/param.h>
30#include <sys/protosw.h>
31#include <sys/systm.h>
32#include <sys/sysctl.h>
33
34#include <kern/bits.h>
35
36#include <netinet/ip.h>
37#include <netinet/ip6.h>
38
39#include <netinet/inp_log.h>
40#include <netinet/in_pcb.h>
41
42#include <netinet/udp_log.h>
43#include <netinet/udp_var.h>
44
45SYSCTL_NODE(_net_inet_udp, OID_AUTO, log, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
46 "UDP");
47
48#if (DEVELOPMENT || DEBUG)
49#define UDP_LOG_ENABLE_DEFAULT \
50 (ULEF_CONNECTION | ULEF_DST_LOCAL | ULEF_DST_GW)
51#else /* (DEVELOPMENT || DEBUG) */
52#define UDP_LOG_ENABLE_DEFAULT 0
53#endif /* (DEVELOPMENT || DEBUG) */
54
55uint32_t udp_log_enable_flags = UDP_LOG_ENABLE_DEFAULT;
56SYSCTL_UINT(_net_inet_udp_log, OID_AUTO, enable,
57 CTLFLAG_RW | CTLFLAG_LOCKED, &udp_log_enable_flags, 0, "");
58
59
60/*
61 * The following is a help to describe the values of the flags
62 */
63#define X(name, value, description, ...) #description ":" #value " "
64SYSCTL_STRING(_net_inet_udp_log, OID_AUTO, enable_usage, CTLFLAG_RD | CTLFLAG_LOCKED,
65 UDP_ENABLE_FLAG_LIST, 0, "");
66#undef X
67
68/*
69 *
70 */
71uint32_t udp_log_local_port_included = 0;
72SYSCTL_UINT(_net_inet_udp_log, OID_AUTO, local_port_included, CTLFLAG_RW | CTLFLAG_LOCKED,
73 &udp_log_local_port_included, 0, "");
74uint32_t udp_log_remote_port_included = 0;
75SYSCTL_UINT(_net_inet_udp_log, OID_AUTO, remote_port_included, CTLFLAG_RW | CTLFLAG_LOCKED,
76 &udp_log_remote_port_included, 0, "");
77
78uint32_t udp_log_local_port_excluded = 0;
79SYSCTL_UINT(_net_inet_udp_log, OID_AUTO, local_port_excluded, CTLFLAG_RW | CTLFLAG_LOCKED,
80 &udp_log_local_port_excluded, 0, "");
81uint32_t udp_log_remote_port_excluded = 0;
82SYSCTL_UINT(_net_inet_udp_log, OID_AUTO, remote_port_excluded, CTLFLAG_RW | CTLFLAG_LOCKED,
83 &udp_log_remote_port_excluded, 0, "");
84
85
86#define UDP_LOG_RATE_LIMIT 1000
87static unsigned int udp_log_rate_limit = UDP_LOG_RATE_LIMIT;
88SYSCTL_UINT(_net_inet_udp_log, OID_AUTO, rate_limit,
89 CTLFLAG_RW | CTLFLAG_LOCKED, &udp_log_rate_limit, 0, "");
90
91/* 1 minute by default */
92#define UDP_LOG_RATE_DURATION 60
93static unsigned int udp_log_rate_duration = UDP_LOG_RATE_DURATION;
94SYSCTL_UINT(_net_inet_udp_log, OID_AUTO, rate_duration,
95 CTLFLAG_RW | CTLFLAG_LOCKED, &udp_log_rate_duration, 0, "");
96
97static unsigned long udp_log_rate_max = 0;
98SYSCTL_ULONG(_net_inet_udp_log, OID_AUTO, rate_max,
99 CTLFLAG_RD | CTLFLAG_LOCKED, &udp_log_rate_max, "");
100
101static unsigned long udp_log_rate_exceeded_total = 0;
102SYSCTL_ULONG(_net_inet_udp_log, OID_AUTO, rate_exceeded_total,
103 CTLFLAG_RD | CTLFLAG_LOCKED, &udp_log_rate_exceeded_total, "");
104
105static unsigned long udp_log_rate_current = 0;
106SYSCTL_ULONG(_net_inet_udp_log, OID_AUTO, rate_current,
107 CTLFLAG_RD | CTLFLAG_LOCKED, &udp_log_rate_current, "");
108
109static bool udp_log_rate_exceeded_logged = false;
110
111static uint64_t udp_log_current_period = 0;
112
113#define ADDRESS_STR_LEN (MAX_IPv6_STR_LEN + 6)
114
115
116#define UDP_LOG_COMMON_FMT \
117 "[%s:%u<->%s:%u] " \
118 "interface: %s " \
119 "(skipped: %lu)\n"
120
121#define UDP_LOG_COMMON_ARGS \
122 laddr_buf, ntohs(local_port), faddr_buf, ntohs(foreign_port), \
123 ifp != NULL ? if_name(ifp) : "", \
124 udp_log_rate_exceeded_total
125
126#define UDP_LOG_COMMON_PCB_FMT \
127 UDP_LOG_COMMON_FMT \
128 "so_gencnt: %llu " \
129 "so_state: 0x%04x " \
130 "process: %s:%u "
131
132#define UDP_LOG_COMMON_PCB_ARGS \
133 UDP_LOG_COMMON_ARGS, \
134 so != NULL ? so->so_gencnt : 0, \
135 so != NULL ? so->so_state : 0, \
136 inp->inp_last_proc_name, so->last_pid
137
138/*
139 * Returns true when above the rate limit
140 */
141static bool
142udp_log_is_rate_limited(void)
143{
144 uint64_t current_net_period = net_uptime();
145
146 /* When set to zero it means to reset to default */
147 if (udp_log_rate_duration == 0) {
148 udp_log_rate_duration = UDP_LOG_RATE_DURATION;
149 }
150 if (udp_log_rate_limit == 0) {
151 udp_log_rate_duration = UDP_LOG_RATE_LIMIT;
152 }
153
154 if (current_net_period > udp_log_current_period + udp_log_rate_duration) {
155 if (udp_log_rate_current > udp_log_rate_max) {
156 udp_log_rate_max = udp_log_rate_current;
157 }
158 udp_log_current_period = current_net_period;
159 udp_log_rate_current = 0;
160 udp_log_rate_exceeded_logged = false;
161 }
162
163 udp_log_rate_current += 1;
164
165 if (udp_log_rate_current > (unsigned long) udp_log_rate_limit) {
166 udp_log_rate_exceeded_total += 1;
167 return true;
168 }
169
170 return false;
171}
172
173static bool
174udp_log_port_allowed(struct inpcb *inp)
175{
176 if ((udp_log_local_port_included > 0 && udp_log_local_port_included <= IPPORT_HILASTAUTO) ||
177 (udp_log_remote_port_included > 0 && udp_log_remote_port_included <= IPPORT_HILASTAUTO)) {
178 if (ntohs(inp->inp_lport) == udp_log_local_port_included ||
179 ntohs(inp->inp_fport) == udp_log_remote_port_included) {
180 return true;
181 } else {
182 return false;
183 }
184 }
185 if ((udp_log_local_port_excluded > 0 && udp_log_local_port_excluded <= IPPORT_HILASTAUTO) ||
186 (udp_log_remote_port_excluded > 0 && udp_log_remote_port_excluded <= IPPORT_HILASTAUTO)) {
187 if (ntohs(inp->inp_lport) == udp_log_local_port_excluded ||
188 ntohs(inp->inp_fport) == udp_log_remote_port_excluded) {
189 return false;
190 }
191 }
192 return true;
193}
194
195__attribute__((noinline))
196void
197udp_log_bind(struct inpcb *inp, const char *event, int error)
198{
199 struct socket *so;
200 struct ifnet *ifp;
201 char laddr_buf[ADDRESS_STR_LEN];
202 char faddr_buf[ADDRESS_STR_LEN];
203 in_port_t local_port;
204 in_port_t foreign_port;
205
206 if (inp == NULL || inp->inp_socket == NULL || event == NULL) {
207 return;
208 }
209
210 /* Do not log too much */
211 if (udp_log_is_rate_limited()) {
212 return;
213 }
214
215 if (!udp_log_port_allowed(inp)) {
216 return;
217 }
218
219 inp->inp_flags2 &= ~INP2_LOGGED_SUMMARY;
220 inp->inp_flags2 |= INP2_LOGGING_ENABLED;
221
222 so = inp->inp_socket;
223
224 local_port = inp->inp_lport;
225 foreign_port = inp->inp_fport;
226
227 ifp = inp->inp_last_outifp != NULL ? inp->inp_last_outifp :
228 inp->inp_boundifp != NULL ? inp->inp_boundifp : NULL;
229
230 inp_log_addresses(inp, lbuf: laddr_buf, lbuflen: sizeof(laddr_buf), fbuf: faddr_buf, fbuflen: sizeof(faddr_buf));
231
232#define UDP_LOG_BIND_FMT \
233 "udp %s: " \
234 UDP_LOG_COMMON_PCB_FMT \
235 "bytes in/out: %llu/%llu " \
236 "pkts in/out: %llu/%llu " \
237 "error: %d " \
238 "so_error: %d " \
239 "svc/tc: %u"
240
241#define UDP_LOG_BIND_ARGS \
242 event, \
243 UDP_LOG_COMMON_PCB_ARGS, \
244 inp->inp_stat->rxbytes, inp->inp_stat->txbytes, \
245 inp->inp_stat->rxpackets, inp->inp_stat->txpackets, \
246 error, \
247 so->so_error, \
248 (so->so_flags1 & SOF1_TC_NET_SERV_TYPE) ? so->so_netsvctype : so->so_traffic_class
249
250 os_log(OS_LOG_DEFAULT, UDP_LOG_BIND_FMT,
251 UDP_LOG_BIND_ARGS);
252
253#undef UDP_LOG_BIND_FMT
254#undef UDP_LOG_BIND_ARGS
255}
256
257__attribute__((noinline))
258void
259udp_log_connection(struct inpcb *inp, const char *event, int error)
260{
261 struct socket *so;
262 struct ifnet *ifp;
263 char laddr_buf[ADDRESS_STR_LEN];
264 char faddr_buf[ADDRESS_STR_LEN];
265 in_port_t local_port;
266 in_port_t foreign_port;
267
268 if (inp == NULL || inp->inp_socket == NULL || event == NULL) {
269 return;
270 }
271
272 /* Do not log too much */
273 if (udp_log_is_rate_limited()) {
274 return;
275 }
276
277 if (!udp_log_port_allowed(inp)) {
278 return;
279 }
280
281 /* Clear the logging flags as one may reconnect an UDP socket */
282 inp->inp_flags2 &= ~INP2_LOGGED_SUMMARY;
283 inp->inp_flags2 |= INP2_LOGGING_ENABLED;
284
285 so = inp->inp_socket;
286
287 local_port = inp->inp_lport;
288 foreign_port = inp->inp_fport;
289
290 ifp = inp->inp_last_outifp != NULL ? inp->inp_last_outifp :
291 inp->inp_boundifp != NULL ? inp->inp_boundifp : NULL;
292
293 inp_log_addresses(inp, lbuf: laddr_buf, lbuflen: sizeof(laddr_buf), fbuf: faddr_buf, fbuflen: sizeof(faddr_buf));
294
295#define UDP_LOG_CONNECT_FMT \
296 "udp %s: " \
297 UDP_LOG_COMMON_PCB_FMT \
298 "bytes in/out: %llu/%llu " \
299 "pkts in/out: %llu/%llu " \
300 "error: %d " \
301 "so_error: %d " \
302 "svc/tc: %u " \
303 "flow: 0x%x"
304
305#define UDP_LOG_CONNECT_ARGS \
306 event, \
307 UDP_LOG_COMMON_PCB_ARGS, \
308 inp->inp_stat->rxbytes, inp->inp_stat->txbytes, \
309 inp->inp_stat->rxpackets, inp->inp_stat->txpackets, \
310 error, \
311 so->so_error, \
312 (so->so_flags1 & SOF1_TC_NET_SERV_TYPE) ? so->so_netsvctype : so->so_traffic_class, \
313 inp->inp_flowhash
314
315 os_log(OS_LOG_DEFAULT, UDP_LOG_CONNECT_FMT,
316 UDP_LOG_CONNECT_ARGS);
317
318#undef UDP_LOG_CONNECT_FMT
319#undef UDP_LOG_CONNECT_ARGS
320}
321
322__attribute__((noinline))
323void
324udp_log_connection_summary(struct inpcb *inp)
325{
326 struct socket *so;
327 struct ifnet *ifp;
328 clock_sec_t duration_secs = 0;
329 clock_usec_t duration_microsecs = 0;
330 clock_sec_t connection_secs = 0;
331 clock_usec_t connection_microsecs = 0;
332 char laddr_buf[ADDRESS_STR_LEN];
333 char faddr_buf[ADDRESS_STR_LEN];
334 in_port_t local_port;
335 in_port_t foreign_port;
336
337 if (inp == NULL || inp->inp_socket == NULL) {
338 return;
339 }
340 if ((inp->inp_flags2 & INP2_LOGGING_ENABLED) == 0) {
341 return;
342 }
343 /* Make sure the summary is logged once */
344 if (inp->inp_flags2 & INP2_LOGGED_SUMMARY) {
345 return;
346 }
347 inp->inp_flags2 |= INP2_LOGGED_SUMMARY;
348 inp->inp_flags2 &= ~INP2_LOGGING_ENABLED;
349
350 /* Do not log too much */
351 if (udp_log_is_rate_limited()) {
352 return;
353 }
354 so = inp->inp_socket;
355
356 local_port = inp->inp_lport;
357 foreign_port = inp->inp_fport;
358
359
360 /*
361 * inp_start_timestamp is when the UDP socket was open.
362 *
363 * inp_connect_timestamp is when the connection started on
364 */
365 uint64_t now = mach_continuous_time();
366 if (inp->inp_start_timestamp > 0) {
367 uint64_t duration = now - inp->inp_start_timestamp;
368
369 absolutetime_to_microtime(abstime: duration, secs: &duration_secs, microsecs: &duration_microsecs);
370 }
371 if (inp->inp_connect_timestamp > 0) {
372 uint64_t duration = now - inp->inp_connect_timestamp;
373
374 absolutetime_to_microtime(abstime: duration, secs: &connection_secs, microsecs: &connection_microsecs);
375 }
376
377 ifp = inp->inp_last_outifp != NULL ? inp->inp_last_outifp :
378 inp->inp_boundifp != NULL ? inp->inp_boundifp : NULL;
379
380 inp_log_addresses(inp, lbuf: laddr_buf, lbuflen: sizeof(laddr_buf), fbuf: faddr_buf, fbuflen: sizeof(faddr_buf));
381
382 /*
383 * Need to use 2 log messages because the size of the summary
384 */
385
386#define UDP_LOG_CONNECTION_SUMMARY_FMT \
387 "udp_connection_summary " \
388 UDP_LOG_COMMON_PCB_FMT \
389 "Duration: %lu.%03d sec " \
390 "Conn_Time: %lu.%03d sec " \
391 "bytes in/out: %llu/%llu " \
392 "pkts in/out: %llu/%llu " \
393 "so_error: %d " \
394 "svc/tc: %u " \
395 "flow: 0x%x"
396
397#define UDP_LOG_CONNECTION_SUMMARY_ARGS \
398 UDP_LOG_COMMON_PCB_ARGS, \
399 duration_secs, duration_microsecs / 1000, \
400 connection_secs, connection_microsecs / 1000, \
401 inp->inp_stat->rxbytes, inp->inp_stat->txbytes, \
402 inp->inp_stat->rxpackets, inp->inp_stat->txpackets, \
403 so->so_error, \
404 (so->so_flags1 & SOF1_TC_NET_SERV_TYPE) ? so->so_netsvctype : so->so_traffic_class, \
405 inp->inp_flowhash
406
407 os_log(OS_LOG_DEFAULT, UDP_LOG_CONNECTION_SUMMARY_FMT,
408 UDP_LOG_CONNECTION_SUMMARY_ARGS);
409#undef UDP_LOG_CONNECTION_SUMMARY_FMT
410#undef UDP_LOG_CONNECTION_SUMMARY_ARGS
411
412#define UDP_LOG_CONNECTION_SUMMARY_FMT \
413 "udp_connection_summary " \
414 UDP_LOG_COMMON_PCB_FMT \
415 "flowctl: %lluus (%llux) "
416
417#define UDP_LOG_CONNECTION_SUMMARY_ARGS \
418 UDP_LOG_COMMON_PCB_ARGS, \
419 inp->inp_fadv_total_time, \
420 inp->inp_fadv_cnt
421
422 os_log(OS_LOG_DEFAULT, UDP_LOG_CONNECTION_SUMMARY_FMT,
423 UDP_LOG_CONNECTION_SUMMARY_ARGS);
424#undef UDP_LOG_CONNECTION_SUMMARY_FMT
425#undef UDP_LOG_CONNECTION_SUMMARY_ARGS
426}
427