xref: /xnu-12377.1.9/bsd/netinet/udp_log.c (revision f6217f891ac0bb64f3d375211650a4c1ff8ca1ea)
1 /*
2  * Copyright (c) 2023-2024 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 
45 SYSCTL_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_CONNECT | ULEF_DST_LOCAL | ULEF_DST_GW)
51 #else /* (DEVELOPMENT || DEBUG) */
52 #define UDP_LOG_ENABLE_DEFAULT \
53     (ULEF_CONNECT | ULEF_DST_LOCAL | ULEF_DST_GW)
54 #endif /* (DEVELOPMENT || DEBUG) */
55 
56 uint32_t udp_log_enable_flags = UDP_LOG_ENABLE_DEFAULT;
57 SYSCTL_UINT(_net_inet_udp_log, OID_AUTO, enable,
58     CTLFLAG_RW | CTLFLAG_LOCKED, &udp_log_enable_flags, 0, "");
59 
60 
61 /*
62  * The following is a help to describe the values of the flags
63  */
64 #define X(name, value, description, ...) #description ":" #value " "
65 SYSCTL_STRING(_net_inet_udp_log, OID_AUTO, enable_usage, CTLFLAG_RD | CTLFLAG_LOCKED,
66     UDP_ENABLE_FLAG_LIST, 0, "");
67 #undef X
68 
69 /*
70  *
71  */
72 static int sysctl_udp_log_port SYSCTL_HANDLER_ARGS;
73 
74 int udp_log_bind_anon_port = 0;
75 SYSCTL_INT(_net_inet_udp_log, OID_AUTO, bind_anon_port,
76     CTLFLAG_RW | CTLFLAG_LOCKED, &udp_log_bind_anon_port, 0, "");
77 
78 int udp_log_local_port_included = 0;
79 SYSCTL_PROC(_net_inet_udp_log, OID_AUTO, local_port_included,
80     CTLFLAG_RW | CTLFLAG_LOCKED,
81     &udp_log_local_port_included, 0, &sysctl_udp_log_port, "I", "");
82 
83 int udp_log_remote_port_included = 0;
84 SYSCTL_PROC(_net_inet_udp_log, OID_AUTO, remote_port_included,
85     CTLFLAG_RW | CTLFLAG_LOCKED,
86     &udp_log_remote_port_included, 0, &sysctl_udp_log_port, "I", "");
87 
88 int udp_log_local_port_excluded = 0;
89 SYSCTL_PROC(_net_inet_udp_log, OID_AUTO, local_port_excluded,
90     CTLFLAG_RW | CTLFLAG_LOCKED,
91     &udp_log_local_port_excluded, 0, &sysctl_udp_log_port, "I", "");
92 
93 int udp_log_remote_port_excluded = 0;
94 SYSCTL_PROC(_net_inet_udp_log, OID_AUTO, remote_port_excluded,
95     CTLFLAG_RW | CTLFLAG_LOCKED,
96     &udp_log_remote_port_excluded, 0, &sysctl_udp_log_port, "I", "");
97 
98 #define UDP_LOG_RATE_LIMIT 1000
99 static unsigned int udp_log_rate_limit = UDP_LOG_RATE_LIMIT;
100 SYSCTL_UINT(_net_inet_udp_log, OID_AUTO, rate_limit,
101     CTLFLAG_RW | CTLFLAG_LOCKED, &udp_log_rate_limit, 0, "");
102 
103 /* 1 minute by default */
104 #define UDP_LOG_RATE_DURATION 60
105 static unsigned int udp_log_rate_duration = UDP_LOG_RATE_DURATION;
106 SYSCTL_UINT(_net_inet_udp_log, OID_AUTO, rate_duration,
107     CTLFLAG_RW | CTLFLAG_LOCKED, &udp_log_rate_duration, 0, "");
108 
109 static unsigned long udp_log_rate_max = 0;
110 SYSCTL_ULONG(_net_inet_udp_log, OID_AUTO, rate_max,
111     CTLFLAG_RD | CTLFLAG_LOCKED, &udp_log_rate_max, "");
112 
113 static unsigned long udp_log_rate_exceeded_total = 0;
114 SYSCTL_ULONG(_net_inet_udp_log, OID_AUTO, rate_exceeded_total,
115     CTLFLAG_RD | CTLFLAG_LOCKED, &udp_log_rate_exceeded_total, "");
116 
117 static unsigned long udp_log_rate_current = 0;
118 SYSCTL_ULONG(_net_inet_udp_log, OID_AUTO, rate_current,
119     CTLFLAG_RD | CTLFLAG_LOCKED, &udp_log_rate_current, "");
120 
121 static bool udp_log_rate_exceeded_logged = false;
122 
123 static uint64_t udp_log_current_period = 0;
124 
125 #define ADDRESS_STR_LEN (MAX_IPv6_STR_LEN + 6)
126 
127 
128 #define UDP_LOG_COMMON_FMT \
129 	    "[%s:%u<->%s:%u] " \
130 	    "interface: %s " \
131 	    "(skipped: %lu)\n"
132 
133 #define UDP_LOG_COMMON_ARGS \
134 	laddr_buf, ntohs(local_port), faddr_buf, ntohs(foreign_port), \
135 	    ifp != NULL ? if_name(ifp) : "", \
136 	    udp_log_rate_exceeded_total
137 
138 #define UDP_LOG_COMMON_PCB_FMT \
139 	UDP_LOG_COMMON_FMT \
140 	"so_gencnt: %llu " \
141 	"so_state: 0x%04x " \
142 	"process: %s:%u "
143 
144 #define UDP_LOG_COMMON_PCB_ARGS \
145 	UDP_LOG_COMMON_ARGS, \
146 	so != NULL ? so->so_gencnt : 0, \
147 	so != NULL ? so->so_state : 0, \
148 	inp->inp_last_proc_name, so->last_pid
149 
150 /*
151  * Returns true when above the rate limit
152  */
153 static bool
udp_log_is_rate_limited(void)154 udp_log_is_rate_limited(void)
155 {
156 	uint64_t current_net_period = net_uptime();
157 
158 	/* When set to zero it means to reset to default */
159 	if (udp_log_rate_duration == 0) {
160 		udp_log_rate_duration = UDP_LOG_RATE_DURATION;
161 	}
162 	if (udp_log_rate_limit == 0) {
163 		udp_log_rate_duration = UDP_LOG_RATE_LIMIT;
164 	}
165 
166 	if (current_net_period > udp_log_current_period + udp_log_rate_duration) {
167 		if (udp_log_rate_current > udp_log_rate_max) {
168 			udp_log_rate_max = udp_log_rate_current;
169 		}
170 		udp_log_current_period = current_net_period;
171 		udp_log_rate_current = 0;
172 		udp_log_rate_exceeded_logged = false;
173 	}
174 
175 	udp_log_rate_current += 1;
176 
177 	if (udp_log_rate_current > (unsigned long) udp_log_rate_limit) {
178 		udp_log_rate_exceeded_total += 1;
179 		return true;
180 	}
181 
182 	return false;
183 }
184 
185 static bool
udp_log_port_allowed(struct inpcb * inp)186 udp_log_port_allowed(struct inpcb *inp)
187 {
188 	if (udp_log_local_port_included != 0 || udp_log_remote_port_included != 0) {
189 		if (ntohs(inp->inp_lport) == udp_log_local_port_included ||
190 		    ntohs(inp->inp_fport) == udp_log_remote_port_included) {
191 			return true;
192 		} else {
193 			return false;
194 		}
195 	}
196 	if (udp_log_local_port_excluded != 0 || udp_log_remote_port_excluded != 0) {
197 		if (ntohs(inp->inp_lport) == udp_log_local_port_excluded ||
198 		    ntohs(inp->inp_fport) == udp_log_remote_port_excluded) {
199 			return false;
200 		}
201 	}
202 
203 	return true;
204 }
205 
206 static inline void
udp_log_common(struct inpcb * inp,const char * event,int error)207 udp_log_common(struct inpcb *inp, const char *event, int error)
208 {
209 	struct socket *so = inp->inp_socket;
210 	struct ifnet *ifp;
211 	char laddr_buf[ADDRESS_STR_LEN];
212 	char faddr_buf[ADDRESS_STR_LEN];
213 	in_port_t local_port;
214 	in_port_t foreign_port;
215 
216 	/* Clear the logging flags as one may reconnect an UDP socket */
217 	inp->inp_flags2 &= ~INP2_LOGGED_SUMMARY;
218 	inp->inp_flags2 |= INP2_LOGGING_ENABLED;
219 
220 	so = inp->inp_socket;
221 
222 	local_port = inp->inp_lport;
223 	foreign_port = inp->inp_fport;
224 
225 	ifp = inp->inp_last_outifp != NULL ? inp->inp_last_outifp :
226 	    inp->inp_boundifp != NULL ? inp->inp_boundifp : NULL;
227 
228 	inp_log_addresses(inp, laddr_buf, sizeof(laddr_buf), faddr_buf, sizeof(faddr_buf));
229 
230 #define UDP_LOG_CONNECTION_FMT \
231 	    "udp %s: " \
232 	    UDP_LOG_COMMON_PCB_FMT \
233 	    "bytes in/out: %llu/%llu " \
234 	    "pkts in/out: %llu/%llu " \
235 	    "error: %d " \
236 	    "so_error: %d " \
237 	    "svc/tc: %u " \
238 	    "flow: 0x%x"
239 
240 #define UDP_LOG_CONNECTION_ARGS \
241 	    event, \
242 	    UDP_LOG_COMMON_PCB_ARGS, \
243 	    inp->inp_mstat.ms_total.ts_rxbytes, inp->inp_mstat.ms_total.ts_txbytes, \
244 	    inp->inp_mstat.ms_total.ts_rxpackets, inp->inp_mstat.ms_total.ts_txpackets, \
245 	    error, \
246 	    so->so_error, \
247 	    (so->so_flags1 & SOF1_TC_NET_SERV_TYPE) ? so->so_netsvctype : so->so_traffic_class, \
248 	    inp->inp_flowhash
249 
250 	os_log(OS_LOG_DEFAULT, UDP_LOG_CONNECTION_FMT,
251 	    UDP_LOG_CONNECTION_ARGS);
252 
253 #undef UDP_LOG_CONNECTION_FMT
254 #undef UDP_LOG_CONNECTION_ARGS
255 }
256 
257 __attribute__((noinline))
258 void
udp_log_bind(struct inpcb * inp,int error)259 udp_log_bind(struct inpcb *inp, int error)
260 {
261 	if (inp == NULL || inp->inp_socket == NULL) {
262 		return;
263 	}
264 	/* Do not log too much */
265 	if (udp_log_is_rate_limited()) {
266 		return;
267 	}
268 	/* Allow logging of bind errors regardless of the port */
269 	if (error == 0) {
270 		if (udp_log_bind_anon_port == 0 && (inp->inp_flags & INP_ANONPORT) != 0) {
271 			return;
272 		}
273 		if (udp_log_port_allowed(inp) == false) {
274 			return;
275 		}
276 	}
277 	udp_log_common(inp, "bind", error);
278 }
279 
280 __attribute__((noinline))
281 void
udp_log_connect(struct inpcb * inp,int error)282 udp_log_connect(struct inpcb *inp, int error)
283 {
284 	if (inp == NULL || inp->inp_socket == NULL) {
285 		return;
286 	}
287 	/* Do not log too much */
288 	if (udp_log_is_rate_limited()) {
289 		return;
290 	}
291 	/* Allow logging of connection errors regardless of the port */
292 	if (error == 0 && udp_log_port_allowed(inp) == false) {
293 		return;
294 	}
295 	udp_log_common(inp, "connect", error);
296 }
297 
298 __attribute__((noinline))
299 void
udp_log_connection_summary(struct inpcb * inp)300 udp_log_connection_summary(struct inpcb *inp)
301 {
302 	struct socket *so;
303 	struct ifnet *ifp;
304 	clock_sec_t duration_secs = 0;
305 	clock_usec_t duration_microsecs = 0;
306 	clock_sec_t connection_secs = 0;
307 	clock_usec_t connection_microsecs = 0;
308 	char laddr_buf[ADDRESS_STR_LEN];
309 	char faddr_buf[ADDRESS_STR_LEN];
310 	in_port_t local_port;
311 	in_port_t foreign_port;
312 
313 	if (inp == NULL || inp->inp_socket == NULL) {
314 		return;
315 	}
316 	if ((inp->inp_flags2 & INP2_LOGGING_ENABLED) == 0) {
317 		return;
318 	}
319 	/* Make sure the summary is logged once */
320 	if (inp->inp_flags2 & INP2_LOGGED_SUMMARY) {
321 		return;
322 	}
323 	inp->inp_flags2 |= INP2_LOGGED_SUMMARY;
324 	inp->inp_flags2 &= ~INP2_LOGGING_ENABLED;
325 
326 	/* UDP can be reconnected so clear the destination flags */
327 	inp->inp_log_flags = 0;
328 
329 	/* Do not log too much */
330 	if (udp_log_is_rate_limited()) {
331 		return;
332 	}
333 	so = inp->inp_socket;
334 
335 	local_port = inp->inp_lport;
336 	foreign_port = inp->inp_fport;
337 
338 	/*
339 	 * inp_start_timestamp is when the UDP socket was open.
340 	 *
341 	 * inp_connect_timestamp is when the connection started on
342 	 */
343 	uint64_t now = mach_continuous_time();
344 	if (inp->inp_start_timestamp > 0) {
345 		uint64_t duration = now - inp->inp_start_timestamp;
346 
347 		absolutetime_to_microtime(duration, &duration_secs, &duration_microsecs);
348 	}
349 	if (inp->inp_connect_timestamp > 0) {
350 		uint64_t duration = now - inp->inp_connect_timestamp;
351 
352 		absolutetime_to_microtime(duration, &connection_secs, &connection_microsecs);
353 	}
354 
355 	ifp = inp->inp_last_outifp != NULL ? inp->inp_last_outifp :
356 	    inp->inp_boundifp != NULL ? inp->inp_boundifp : NULL;
357 
358 	inp_log_addresses(inp, laddr_buf, sizeof(laddr_buf), faddr_buf, sizeof(faddr_buf));
359 
360 	/*
361 	 * Need to use 2 log messages because the size of the summary
362 	 */
363 
364 #define UDP_LOG_CONNECTION_SUMMARY_FMT \
365 	    "udp_connection_summary " \
366 	    UDP_LOG_COMMON_PCB_FMT \
367 	    "Duration: %lu.%03d sec " \
368 	    "Conn_Time: %lu.%03d sec " \
369 	    "bytes in/out: %llu/%llu " \
370 	    "pkts in/out: %llu/%llu " \
371 	    "rxnospace pkts/bytes: %llu/%llu " \
372 	    "so_error: %d " \
373 	    "svc/tc: %u " \
374 	    "flow: 0x%x " \
375 	    "flowctl: %lluus (%llux) "
376 
377 #define UDP_LOG_CONNECTION_SUMMARY_ARGS \
378 	    UDP_LOG_COMMON_PCB_ARGS, \
379 	    duration_secs, duration_microsecs / 1000, \
380 	    connection_secs, connection_microsecs / 1000, \
381 	    inp->inp_mstat.ms_total.ts_rxbytes, inp->inp_mstat.ms_total.ts_txbytes, \
382 	    inp->inp_mstat.ms_total.ts_rxpackets, inp->inp_mstat.ms_total.ts_txpackets, \
383 	    so->so_tc_stats[SO_STATS_SBNOSPACE].rxpackets, \
384 	    so->so_tc_stats[SO_STATS_SBNOSPACE].rxbytes, \
385 	    so->so_error, \
386 	    (so->so_flags1 & SOF1_TC_NET_SERV_TYPE) ? so->so_netsvctype : so->so_traffic_class, \
387 	    inp->inp_flowhash, \
388 	    inp->inp_fadv_total_time, \
389 	    inp->inp_fadv_cnt
390 
391 	os_log(OS_LOG_DEFAULT, UDP_LOG_CONNECTION_SUMMARY_FMT,
392 	    UDP_LOG_CONNECTION_SUMMARY_ARGS);
393 #undef UDP_LOG_CONNECTION_SUMMARY_FMT
394 #undef UDP_LOG_CONNECTION_SUMMARY_ARGS
395 }
396 
397 __attribute__((noinline))
398 void
udp_log_message(const char * func_name,int line_no,struct inpcb * inp,const char * format,...)399 udp_log_message(const char *func_name, int line_no, struct inpcb *inp, const char *format, ...)
400 {
401 	struct socket *so;
402 	struct ifnet *ifp;
403 	char laddr_buf[ADDRESS_STR_LEN];
404 	char faddr_buf[ADDRESS_STR_LEN];
405 	in_port_t local_port;
406 	in_port_t foreign_port;
407 	char message[256];
408 
409 	if (inp == NULL || inp->inp_socket == NULL) {
410 		return;
411 	}
412 
413 	/* Do not log too much */
414 	if (udp_log_is_rate_limited()) {
415 		return;
416 	}
417 
418 	if (!udp_log_port_allowed(inp)) {
419 		return;
420 	}
421 
422 	so = inp->inp_socket;
423 
424 	local_port = inp->inp_lport;
425 	foreign_port = inp->inp_fport;
426 
427 	ifp = inp->inp_last_outifp != NULL ? inp->inp_last_outifp :
428 	    inp->inp_boundifp != NULL ? inp->inp_boundifp : NULL;
429 
430 	inp_log_addresses(inp, laddr_buf, sizeof(laddr_buf), faddr_buf, sizeof(faddr_buf));
431 
432 	va_list ap;
433 	va_start(ap, format);
434 	vsnprintf(message, sizeof(message), format, ap);
435 	va_end(ap);
436 
437 #define UDP_LOG_MESSAGE_FMT \
438 	    "udp (%s:%d): " \
439 	    UDP_LOG_COMMON_PCB_FMT \
440 	    "%s"
441 
442 #define UDP_LOG_MESSAGE_ARGS \
443 	    func_name, line_no, \
444 	    UDP_LOG_COMMON_PCB_ARGS, \
445 	    message
446 
447 	os_log(OS_LOG_DEFAULT, UDP_LOG_MESSAGE_FMT,
448 	    UDP_LOG_MESSAGE_ARGS);
449 
450 #undef UDP_LOG_MESSAGE_FMT
451 #undef UDP_LOG_MESSAGE_ARGS
452 }
453 
454 static bool
udp_log_pkt_addresses(void * hdr,bool outgoing,char * __sized_by (lbuflen)lbuf,socklen_t lbuflen,char * __sized_by (fbuflen)fbuf,socklen_t fbuflen)455 udp_log_pkt_addresses(void *hdr, bool outgoing,
456     char *__sized_by(lbuflen) lbuf, socklen_t lbuflen,
457     char *__sized_by(fbuflen) fbuf, socklen_t fbuflen)
458 {
459 	bool isipv6;
460 
461 	isipv6 = (((struct ip *)hdr)->ip_v == 6);
462 
463 	if (isipv6) {
464 		struct ip6_hdr *ip6 = (struct ip6_hdr *)hdr;
465 		struct in6_addr src_addr6 = ip6->ip6_src;
466 		struct in6_addr dst_addr6 = ip6->ip6_dst;
467 
468 #pragma clang diagnostic push
469 #pragma clang diagnostic ignored "-Waddress-of-packed-member"
470 		if (memcmp(&src_addr6, &in6addr_loopback, sizeof(struct in6_addr)) == 0 ||
471 		    memcmp(&dst_addr6, &in6addr_loopback, sizeof(struct in6_addr)) == 0) {
472 			if (!(udp_log_enable_flags & ULEF_DST_LOOPBACK)) {
473 				return false;
474 			}
475 		}
476 #pragma clang diagnostic pop
477 
478 		if (IN6_IS_ADDR_LINKLOCAL(&src_addr6)) {
479 			src_addr6.s6_addr16[1] = 0;
480 		}
481 		if (IN6_IS_ADDR_LINKLOCAL(&dst_addr6)) {
482 			dst_addr6.s6_addr16[1] = 0;
483 		}
484 
485 		if (inp_log_privacy != 0) {
486 			strlcpy(lbuf, "<IPv6-redacted>", lbuflen);
487 			strlcpy(fbuf, "<IPv6-redacted>", fbuflen);
488 		} else if (outgoing) {
489 			inet_ntop(AF_INET6, &src_addr6, lbuf, lbuflen);
490 			inet_ntop(AF_INET6, &dst_addr6, fbuf, fbuflen);
491 		} else {
492 			inet_ntop(AF_INET6, &dst_addr6, lbuf, lbuflen);
493 			inet_ntop(AF_INET6, &src_addr6, fbuf, fbuflen);
494 		}
495 	} else {
496 		struct ip *ip = (struct ip *)hdr;
497 
498 		if (ntohl(ip->ip_src.s_addr) == INADDR_LOOPBACK ||
499 		    ntohl(ip->ip_dst.s_addr) == INADDR_LOOPBACK) {
500 			if (!(udp_log_enable_flags & ULEF_DST_LOOPBACK)) {
501 				return false;
502 			}
503 		}
504 
505 		if (inp_log_privacy != 0) {
506 			strlcpy(lbuf, "<IPv4-redacted>", lbuflen);
507 			strlcpy(fbuf, "<IPv4-redacted>", fbuflen);
508 		} else if (outgoing) {
509 			inet_ntop(AF_INET, (void *)&ip->ip_src.s_addr, lbuf, lbuflen);
510 			inet_ntop(AF_INET, (void *)&ip->ip_dst.s_addr, fbuf, fbuflen);
511 		} else {
512 			inet_ntop(AF_INET, (void *)&ip->ip_dst.s_addr, lbuf, lbuflen);
513 			inet_ntop(AF_INET, (void *)&ip->ip_src.s_addr, fbuf, fbuflen);
514 		}
515 	}
516 	return true;
517 }
518 
519 __attribute__((noinline))
520 void
udp_log_drop_pcb(void * hdr,struct udphdr * uh,struct inpcb * inp,bool outgoing,const char * reason)521 udp_log_drop_pcb(void *hdr, struct udphdr *uh, struct inpcb *inp, bool outgoing, const char *reason)
522 {
523 	struct socket *so;
524 	struct ifnet *ifp;
525 	char laddr_buf[ADDRESS_STR_LEN];
526 	char faddr_buf[ADDRESS_STR_LEN];
527 	in_port_t local_port;
528 	in_port_t foreign_port;
529 	const char *direction = "";
530 
531 	if (inp == NULL) {
532 		return;
533 	}
534 	so = inp->inp_socket;
535 	if (so == NULL) {
536 		return;
537 	}
538 
539 	/* Do not log common drops after the connection termination is logged */
540 	if ((inp->inp_flags2 & INP2_LOGGED_SUMMARY) && ((so->so_state & SS_NOFDREF) ||
541 	    (so->so_flags & SOF_DEFUNCT) || (so->so_state & SS_CANTRCVMORE))) {
542 		return;
543 	}
544 
545 	/* Do not log too much */
546 	if (udp_log_is_rate_limited()) {
547 		return;
548 	}
549 
550 	/* Use the packet addresses when in the data path */
551 	if (hdr != NULL && uh != NULL) {
552 		if (outgoing) {
553 			local_port = uh->uh_sport;
554 			foreign_port = uh->uh_dport;
555 			direction = "outgoing ";
556 		} else {
557 			local_port = uh->uh_dport;
558 			foreign_port = uh->uh_sport;
559 			direction = "incoming ";
560 		}
561 		(void) udp_log_pkt_addresses(hdr, outgoing, laddr_buf, sizeof(laddr_buf), faddr_buf, sizeof(faddr_buf));
562 	} else {
563 		local_port = inp->inp_lport;
564 		foreign_port = inp->inp_fport;
565 		inp_log_addresses(inp, laddr_buf, sizeof(laddr_buf), faddr_buf, sizeof(faddr_buf));
566 	}
567 
568 	ifp = inp->inp_last_outifp != NULL ? inp->inp_last_outifp :
569 	    inp->inp_boundifp != NULL ? inp->inp_boundifp : NULL;
570 
571 #define UDP_LOG_DROP_PCB_FMT \
572 	    "udp drop %s" \
573 	    UDP_LOG_COMMON_PCB_FMT \
574 	    "so_error: %d " \
575 	    "reason: %s"
576 
577 #define UDP_LOG_DROP_PCB_ARGS \
578 	    direction, \
579 	    UDP_LOG_COMMON_PCB_ARGS, \
580 	    so->so_error, \
581 	    reason
582 
583 	os_log(OS_LOG_DEFAULT, UDP_LOG_DROP_PCB_FMT,
584 	    UDP_LOG_DROP_PCB_ARGS);
585 #undef UDP_LOG_DROP_PCB_FMT
586 #undef UDP_LOG_DROP_PCB_ARGS
587 }
588 static int
589 sysctl_udp_log_port SYSCTL_HANDLER_ARGS
590 {
591 #pragma unused(arg1, arg2)
592 	int error;
593 	int new_value = *(uint16_t *)oidp->oid_arg1;
594 
595 	error = sysctl_handle_int(oidp, &new_value, 0, req);
596 	if (error == 0) {
597 		if (new_value < 0 || new_value > UINT16_MAX) {
598 			return EINVAL;
599 		}
600 		*(int *)oidp->oid_arg1 = new_value;
601 	}
602 	return error;
603 }
604