xref: /netbsd-src/external/bsd/ntp/dist/libntp/lib/isc/unix/net.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: net.c,v 1.2 2024/08/18 20:47:16 christos Exp $	*/
2897be3a4Schristos 
3897be3a4Schristos /*
4897be3a4Schristos  * Copyright (C) 2004, 2005, 2007, 2008, 2012  Internet Systems Consortium, Inc. ("ISC")
5897be3a4Schristos  * Copyright (C) 1999-2003  Internet Software Consortium.
6897be3a4Schristos  *
7897be3a4Schristos  * Permission to use, copy, modify, and/or distribute this software for any
8897be3a4Schristos  * purpose with or without fee is hereby granted, provided that the above
9897be3a4Schristos  * copyright notice and this permission notice appear in all copies.
10897be3a4Schristos  *
11897be3a4Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12897be3a4Schristos  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13897be3a4Schristos  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14897be3a4Schristos  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15897be3a4Schristos  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16897be3a4Schristos  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17897be3a4Schristos  * PERFORMANCE OF THIS SOFTWARE.
18897be3a4Schristos  */
19897be3a4Schristos 
20897be3a4Schristos /* Id */
21897be3a4Schristos 
22897be3a4Schristos #include <config.h>
23897be3a4Schristos 
24897be3a4Schristos #include <sys/types.h>
25897be3a4Schristos 
26897be3a4Schristos #if defined(HAVE_SYS_SYSCTL_H)
27897be3a4Schristos #if defined(HAVE_SYS_PARAM_H)
28897be3a4Schristos #include <sys/param.h>
29897be3a4Schristos #endif
30897be3a4Schristos #include <sys/sysctl.h>
31897be3a4Schristos #endif
32897be3a4Schristos 
33897be3a4Schristos #include <errno.h>
34897be3a4Schristos #include <unistd.h>
35897be3a4Schristos 
36897be3a4Schristos #include <isc/log.h>
37897be3a4Schristos #include <isc/msgs.h>
38897be3a4Schristos #include <isc/net.h>
39897be3a4Schristos #include <isc/once.h>
40897be3a4Schristos #include <isc/strerror.h>
41897be3a4Schristos #include <isc/string.h>
42897be3a4Schristos #include <isc/util.h>
43897be3a4Schristos 
44897be3a4Schristos /*%
45897be3a4Schristos  * Definitions about UDP port range specification.  This is a total mess of
46897be3a4Schristos  * portability variants: some use sysctl (but the sysctl names vary), some use
47897be3a4Schristos  * system-specific interfaces, some have the same interface for IPv4 and IPv6,
48897be3a4Schristos  * some separate them, etc...
49897be3a4Schristos  */
50897be3a4Schristos 
51897be3a4Schristos /*%
52897be3a4Schristos  * The last resort defaults: use all non well known port space
53897be3a4Schristos  */
54897be3a4Schristos #ifndef ISC_NET_PORTRANGELOW
55897be3a4Schristos #define ISC_NET_PORTRANGELOW 1024
56897be3a4Schristos #endif	/* ISC_NET_PORTRANGELOW */
57897be3a4Schristos #ifndef ISC_NET_PORTRANGEHIGH
58897be3a4Schristos #define ISC_NET_PORTRANGEHIGH 65535
59897be3a4Schristos #endif	/* ISC_NET_PORTRANGEHIGH */
60897be3a4Schristos 
61897be3a4Schristos #ifdef HAVE_SYSCTLBYNAME
62897be3a4Schristos 
63897be3a4Schristos /*%
64897be3a4Schristos  * sysctl variants
65897be3a4Schristos  */
66897be3a4Schristos #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
67897be3a4Schristos #define USE_SYSCTL_PORTRANGE
68897be3a4Schristos #define SYSCTL_V4PORTRANGE_LOW	"net.inet.ip.portrange.hifirst"
69897be3a4Schristos #define SYSCTL_V4PORTRANGE_HIGH	"net.inet.ip.portrange.hilast"
70897be3a4Schristos #define SYSCTL_V6PORTRANGE_LOW	"net.inet.ip.portrange.hifirst"
71897be3a4Schristos #define SYSCTL_V6PORTRANGE_HIGH	"net.inet.ip.portrange.hilast"
72897be3a4Schristos #endif
73897be3a4Schristos 
74897be3a4Schristos #ifdef __NetBSD__
75897be3a4Schristos #define USE_SYSCTL_PORTRANGE
76897be3a4Schristos #define SYSCTL_V4PORTRANGE_LOW	"net.inet.ip.anonportmin"
77897be3a4Schristos #define SYSCTL_V4PORTRANGE_HIGH	"net.inet.ip.anonportmax"
78897be3a4Schristos #define SYSCTL_V6PORTRANGE_LOW	"net.inet6.ip6.anonportmin"
79897be3a4Schristos #define SYSCTL_V6PORTRANGE_HIGH	"net.inet6.ip6.anonportmax"
80897be3a4Schristos #endif
81897be3a4Schristos 
82897be3a4Schristos #else /* !HAVE_SYSCTLBYNAME */
83897be3a4Schristos 
84897be3a4Schristos #ifdef __OpenBSD__
85897be3a4Schristos #define USE_SYSCTL_PORTRANGE
86897be3a4Schristos #define SYSCTL_V4PORTRANGE_LOW	{ CTL_NET, PF_INET, IPPROTO_IP, \
87897be3a4Schristos 				  IPCTL_IPPORT_HIFIRSTAUTO }
88897be3a4Schristos #define SYSCTL_V4PORTRANGE_HIGH	{ CTL_NET, PF_INET, IPPROTO_IP, \
89897be3a4Schristos 				  IPCTL_IPPORT_HILASTAUTO }
90897be3a4Schristos /* Same for IPv6 */
91897be3a4Schristos #define SYSCTL_V6PORTRANGE_LOW	SYSCTL_V4PORTRANGE_LOW
92897be3a4Schristos #define SYSCTL_V6PORTRANGE_HIGH	SYSCTL_V4PORTRANGE_HIGH
93897be3a4Schristos #endif
94897be3a4Schristos 
95897be3a4Schristos #endif /* HAVE_SYSCTLBYNAME */
96897be3a4Schristos 
97897be3a4Schristos #if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
98897be3a4Schristos const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
99897be3a4Schristos #endif
100897be3a4Schristos 
101897be3a4Schristos #if defined(ISC_PLATFORM_HAVEIPV6)
102897be3a4Schristos 
103897be3a4Schristos # if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
104897be3a4Schristos const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
105897be3a4Schristos # endif
106897be3a4Schristos 
107897be3a4Schristos # if defined(WANT_IPV6)
108897be3a4Schristos static isc_once_t 	once_ipv6only = ISC_ONCE_INIT;
109897be3a4Schristos # endif
110897be3a4Schristos 
111897be3a4Schristos # if defined(ISC_PLATFORM_HAVEIPV6) && \
112897be3a4Schristos      defined(WANT_IPV6) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
113897be3a4Schristos static isc_once_t 	once_ipv6pktinfo = ISC_ONCE_INIT;
114897be3a4Schristos # endif
115897be3a4Schristos #endif /* ISC_PLATFORM_HAVEIPV6 */
116897be3a4Schristos 
117897be3a4Schristos static isc_once_t 	once = ISC_ONCE_INIT;
118897be3a4Schristos 
119897be3a4Schristos static isc_result_t	ipv4_result = ISC_R_NOTFOUND;
120897be3a4Schristos static isc_result_t	ipv6_result = ISC_R_NOTFOUND;
121897be3a4Schristos static isc_result_t	unix_result = ISC_R_NOTFOUND;
122897be3a4Schristos static isc_result_t	ipv6only_result = ISC_R_NOTFOUND;
123897be3a4Schristos static isc_result_t	ipv6pktinfo_result = ISC_R_NOTFOUND;
124897be3a4Schristos 
125897be3a4Schristos static isc_result_t
126897be3a4Schristos try_proto(int domain) {
127897be3a4Schristos 	int s;
128897be3a4Schristos 	isc_result_t result = ISC_R_SUCCESS;
129897be3a4Schristos 	char strbuf[ISC_STRERRORSIZE];
130897be3a4Schristos 
131897be3a4Schristos 	s = socket(domain, SOCK_STREAM, 0);
132897be3a4Schristos 	if (s == -1) {
133897be3a4Schristos 		switch (errno) {
134897be3a4Schristos #ifdef EAFNOSUPPORT
135897be3a4Schristos 		case EAFNOSUPPORT:
136897be3a4Schristos #endif
137897be3a4Schristos #ifdef EPROTONOSUPPORT
138897be3a4Schristos 		case EPROTONOSUPPORT:
139897be3a4Schristos #endif
140897be3a4Schristos #ifdef EINVAL
141897be3a4Schristos 		case EINVAL:
142897be3a4Schristos #endif
143897be3a4Schristos 			return (ISC_R_NOTFOUND);
144897be3a4Schristos 		default:
145897be3a4Schristos 			isc__strerror(errno, strbuf, sizeof(strbuf));
146897be3a4Schristos 			UNEXPECTED_ERROR(__FILE__, __LINE__,
147897be3a4Schristos 					 "socket() %s: %s",
148897be3a4Schristos 					 isc_msgcat_get(isc_msgcat,
149897be3a4Schristos 							ISC_MSGSET_GENERAL,
150897be3a4Schristos 							ISC_MSG_FAILED,
151897be3a4Schristos 							"failed"),
152897be3a4Schristos 					 strbuf);
153897be3a4Schristos 			return (ISC_R_UNEXPECTED);
154897be3a4Schristos 		}
155897be3a4Schristos 	}
156897be3a4Schristos 
157897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIPV6
158897be3a4Schristos #ifdef WANT_IPV6
159897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
160897be3a4Schristos 	if (domain == PF_INET6) {
161897be3a4Schristos 		struct sockaddr_in6 sin6;
162897be3a4Schristos 		GETSOCKNAME_SOCKLEN_TYPE len;	/* NTP local change */
163897be3a4Schristos 
164897be3a4Schristos 		/*
165897be3a4Schristos 		 * Check to see if IPv6 is broken, as is common on Linux.
166897be3a4Schristos 		 */
167897be3a4Schristos 		len = sizeof(sin6);
168897be3a4Schristos 		if (getsockname(s, (struct sockaddr *)&sin6, &len) < 0)
169897be3a4Schristos 		{
170897be3a4Schristos 			isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
171897be3a4Schristos 				      ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
172897be3a4Schristos 				      "retrieving the address of an IPv6 "
173897be3a4Schristos 				      "socket from the kernel failed.");
174897be3a4Schristos 			isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
175897be3a4Schristos 				      ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
176897be3a4Schristos 				      "IPv6 is not supported.");
177897be3a4Schristos 			result = ISC_R_NOTFOUND;
178897be3a4Schristos 		} else {
179897be3a4Schristos 			if (len == sizeof(struct sockaddr_in6))
180897be3a4Schristos 				result = ISC_R_SUCCESS;
181897be3a4Schristos 			else {
182897be3a4Schristos 				isc_log_write(isc_lctx,
183897be3a4Schristos 					      ISC_LOGCATEGORY_GENERAL,
184897be3a4Schristos 					      ISC_LOGMODULE_SOCKET,
185897be3a4Schristos 					      ISC_LOG_ERROR,
186897be3a4Schristos 					      "IPv6 structures in kernel and "
187897be3a4Schristos 					      "user space do not match.");
188897be3a4Schristos 				isc_log_write(isc_lctx,
189897be3a4Schristos 					      ISC_LOGCATEGORY_GENERAL,
190897be3a4Schristos 					      ISC_LOGMODULE_SOCKET,
191897be3a4Schristos 					      ISC_LOG_ERROR,
192897be3a4Schristos 					      "IPv6 is not supported.");
193897be3a4Schristos 				result = ISC_R_NOTFOUND;
194897be3a4Schristos 			}
195897be3a4Schristos 		}
196897be3a4Schristos 	}
197897be3a4Schristos #endif
198897be3a4Schristos #endif
199897be3a4Schristos #endif
200897be3a4Schristos 
201897be3a4Schristos 	(void)close(s);
202897be3a4Schristos 
203897be3a4Schristos 	return (result);
204897be3a4Schristos }
205897be3a4Schristos 
206897be3a4Schristos static void
207897be3a4Schristos initialize_action(void) {
208897be3a4Schristos 	ipv4_result = try_proto(PF_INET);
209897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIPV6
210897be3a4Schristos #ifdef WANT_IPV6
211897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
212897be3a4Schristos 	ipv6_result = try_proto(PF_INET6);
213897be3a4Schristos #endif
214897be3a4Schristos #endif
215897be3a4Schristos #endif
216897be3a4Schristos #ifdef ISC_PLATFORM_HAVESYSUNH
217897be3a4Schristos 	unix_result = try_proto(PF_UNIX);
218897be3a4Schristos #endif
219897be3a4Schristos }
220897be3a4Schristos 
221897be3a4Schristos static void
222897be3a4Schristos initialize(void) {
223897be3a4Schristos 	RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
224897be3a4Schristos }
225897be3a4Schristos 
226897be3a4Schristos isc_result_t
227897be3a4Schristos isc_net_probeipv4(void) {
228897be3a4Schristos 	initialize();
229897be3a4Schristos 	return (ipv4_result);
230897be3a4Schristos }
231897be3a4Schristos 
232897be3a4Schristos isc_result_t
233897be3a4Schristos isc_net_probeipv6(void) {
234897be3a4Schristos 	initialize();
235897be3a4Schristos 	return (ipv6_result);
236897be3a4Schristos }
237897be3a4Schristos 
238897be3a4Schristos isc_result_t
239897be3a4Schristos isc_net_probeunix(void) {
240897be3a4Schristos 	initialize();
241897be3a4Schristos 	return (unix_result);
242897be3a4Schristos }
243897be3a4Schristos 
244897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIPV6
245897be3a4Schristos #ifdef WANT_IPV6
246897be3a4Schristos static void
247897be3a4Schristos try_ipv6only(void) {
248897be3a4Schristos #ifdef IPV6_V6ONLY
249897be3a4Schristos 	int s, on;
250897be3a4Schristos 	char strbuf[ISC_STRERRORSIZE];
251897be3a4Schristos #endif
252897be3a4Schristos 	isc_result_t result;
253897be3a4Schristos 
254897be3a4Schristos 	result = isc_net_probeipv6();
255897be3a4Schristos 	if (result != ISC_R_SUCCESS) {
256897be3a4Schristos 		ipv6only_result = result;
257897be3a4Schristos 		return;
258897be3a4Schristos 	}
259897be3a4Schristos 
260897be3a4Schristos #ifndef IPV6_V6ONLY
261897be3a4Schristos 	ipv6only_result = ISC_R_NOTFOUND;
262897be3a4Schristos 	return;
263897be3a4Schristos #else
264897be3a4Schristos 	/* check for TCP sockets */
265897be3a4Schristos 	s = socket(PF_INET6, SOCK_STREAM, 0);
266897be3a4Schristos 	if (s == -1) {
267897be3a4Schristos 		isc__strerror(errno, strbuf, sizeof(strbuf));
268897be3a4Schristos 		UNEXPECTED_ERROR(__FILE__, __LINE__,
269897be3a4Schristos 				 "socket() %s: %s",
270897be3a4Schristos 				 isc_msgcat_get(isc_msgcat,
271897be3a4Schristos 						ISC_MSGSET_GENERAL,
272897be3a4Schristos 						ISC_MSG_FAILED,
273897be3a4Schristos 						"failed"),
274897be3a4Schristos 				 strbuf);
275897be3a4Schristos 		ipv6only_result = ISC_R_UNEXPECTED;
276897be3a4Schristos 		return;
277897be3a4Schristos 	}
278897be3a4Schristos 
279897be3a4Schristos 	on = 1;
280897be3a4Schristos 	if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
281897be3a4Schristos 		ipv6only_result = ISC_R_NOTFOUND;
282897be3a4Schristos 		goto close;
283897be3a4Schristos 	}
284897be3a4Schristos 
285897be3a4Schristos 	close(s);
286897be3a4Schristos 
287897be3a4Schristos 	/* check for UDP sockets */
288897be3a4Schristos 	s = socket(PF_INET6, SOCK_DGRAM, 0);
289897be3a4Schristos 	if (s == -1) {
290897be3a4Schristos 		isc__strerror(errno, strbuf, sizeof(strbuf));
291897be3a4Schristos 		UNEXPECTED_ERROR(__FILE__, __LINE__,
292897be3a4Schristos 				 "socket() %s: %s",
293897be3a4Schristos 				 isc_msgcat_get(isc_msgcat,
294897be3a4Schristos 						ISC_MSGSET_GENERAL,
295897be3a4Schristos 						ISC_MSG_FAILED,
296897be3a4Schristos 						"failed"),
297897be3a4Schristos 				 strbuf);
298897be3a4Schristos 		ipv6only_result = ISC_R_UNEXPECTED;
299897be3a4Schristos 		return;
300897be3a4Schristos 	}
301897be3a4Schristos 
302897be3a4Schristos 	on = 1;
303897be3a4Schristos 	if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
304897be3a4Schristos 		ipv6only_result = ISC_R_NOTFOUND;
305897be3a4Schristos 		goto close;
306897be3a4Schristos 	}
307897be3a4Schristos 
308897be3a4Schristos 	ipv6only_result = ISC_R_SUCCESS;
309897be3a4Schristos 
310897be3a4Schristos close:
311897be3a4Schristos 	close(s);
312897be3a4Schristos 	return;
313897be3a4Schristos #endif /* IPV6_V6ONLY */
314897be3a4Schristos }
315897be3a4Schristos 
316897be3a4Schristos static void
317897be3a4Schristos initialize_ipv6only(void) {
318897be3a4Schristos 	RUNTIME_CHECK(isc_once_do(&once_ipv6only,
319897be3a4Schristos 				  try_ipv6only) == ISC_R_SUCCESS);
320897be3a4Schristos }
321897be3a4Schristos 
322897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
323897be3a4Schristos static void
324897be3a4Schristos try_ipv6pktinfo(void) {
325897be3a4Schristos 	int s, on;
326897be3a4Schristos 	char strbuf[ISC_STRERRORSIZE];
327897be3a4Schristos 	isc_result_t result;
328897be3a4Schristos 	int optname;
329897be3a4Schristos 
330897be3a4Schristos 	result = isc_net_probeipv6();
331897be3a4Schristos 	if (result != ISC_R_SUCCESS) {
332897be3a4Schristos 		ipv6pktinfo_result = result;
333897be3a4Schristos 		return;
334897be3a4Schristos 	}
335897be3a4Schristos 
336897be3a4Schristos 	/* we only use this for UDP sockets */
337897be3a4Schristos 	s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
338897be3a4Schristos 	if (s == -1) {
339897be3a4Schristos 		isc__strerror(errno, strbuf, sizeof(strbuf));
340897be3a4Schristos 		UNEXPECTED_ERROR(__FILE__, __LINE__,
341897be3a4Schristos 				 "socket() %s: %s",
342897be3a4Schristos 				 isc_msgcat_get(isc_msgcat,
343897be3a4Schristos 						ISC_MSGSET_GENERAL,
344897be3a4Schristos 						ISC_MSG_FAILED,
345897be3a4Schristos 						"failed"),
346897be3a4Schristos 				 strbuf);
347897be3a4Schristos 		ipv6pktinfo_result = ISC_R_UNEXPECTED;
348897be3a4Schristos 		return;
349897be3a4Schristos 	}
350897be3a4Schristos 
351897be3a4Schristos #ifdef IPV6_RECVPKTINFO
352897be3a4Schristos 	optname = IPV6_RECVPKTINFO;
353897be3a4Schristos #else
354897be3a4Schristos 	optname = IPV6_PKTINFO;
355897be3a4Schristos #endif
356897be3a4Schristos 	on = 1;
357897be3a4Schristos 	if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
358897be3a4Schristos 		ipv6pktinfo_result = ISC_R_NOTFOUND;
359897be3a4Schristos 		goto close;
360897be3a4Schristos 	}
361897be3a4Schristos 
362897be3a4Schristos 	ipv6pktinfo_result = ISC_R_SUCCESS;
363897be3a4Schristos 
364897be3a4Schristos close:
365897be3a4Schristos 	close(s);
366897be3a4Schristos 	return;
367897be3a4Schristos }
368897be3a4Schristos 
369897be3a4Schristos static void
370897be3a4Schristos initialize_ipv6pktinfo(void) {
371897be3a4Schristos 	RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
372897be3a4Schristos 				  try_ipv6pktinfo) == ISC_R_SUCCESS);
373897be3a4Schristos }
374897be3a4Schristos #endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
375897be3a4Schristos #endif /* WANT_IPV6 */
376897be3a4Schristos #endif /* ISC_PLATFORM_HAVEIPV6 */
377897be3a4Schristos 
378897be3a4Schristos isc_result_t
379897be3a4Schristos isc_net_probe_ipv6only(void) {
380897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIPV6
381897be3a4Schristos #ifdef WANT_IPV6
382897be3a4Schristos 	initialize_ipv6only();
383897be3a4Schristos #else
384897be3a4Schristos 	ipv6only_result = ISC_R_NOTFOUND;
385897be3a4Schristos #endif
386897be3a4Schristos #endif
387897be3a4Schristos 	return (ipv6only_result);
388897be3a4Schristos }
389897be3a4Schristos 
390897be3a4Schristos isc_result_t
391897be3a4Schristos isc_net_probe_ipv6pktinfo(void) {
392897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIPV6
393897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
394897be3a4Schristos #ifdef WANT_IPV6
395897be3a4Schristos 	initialize_ipv6pktinfo();
396897be3a4Schristos #else
397897be3a4Schristos 	ipv6pktinfo_result = ISC_R_NOTFOUND;
398897be3a4Schristos #endif
399897be3a4Schristos #endif
400897be3a4Schristos #endif
401897be3a4Schristos 	return (ipv6pktinfo_result);
402897be3a4Schristos }
403897be3a4Schristos 
404897be3a4Schristos #if defined(USE_SYSCTL_PORTRANGE)
405897be3a4Schristos #if defined(HAVE_SYSCTLBYNAME)
406897be3a4Schristos static isc_result_t
407897be3a4Schristos getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
408897be3a4Schristos 	int port_low, port_high;
409897be3a4Schristos 	size_t portlen;
410897be3a4Schristos 	const char *sysctlname_lowport, *sysctlname_hiport;
411897be3a4Schristos 
412897be3a4Schristos 	if (af == AF_INET) {
413897be3a4Schristos 		sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW;
414897be3a4Schristos 		sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH;
415897be3a4Schristos 	} else {
416897be3a4Schristos 		sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
417897be3a4Schristos 		sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
418897be3a4Schristos 	}
419897be3a4Schristos 	portlen = sizeof(portlen);
420897be3a4Schristos 	if (sysctlbyname(sysctlname_lowport, &port_low, &portlen,
421897be3a4Schristos 			 NULL, 0) < 0) {
422897be3a4Schristos 		return (ISC_R_FAILURE);
423897be3a4Schristos 	}
424897be3a4Schristos 	portlen = sizeof(portlen);
425897be3a4Schristos 	if (sysctlbyname(sysctlname_hiport, &port_high, &portlen,
426897be3a4Schristos 			 NULL, 0) < 0) {
427897be3a4Schristos 		return (ISC_R_FAILURE);
428897be3a4Schristos 	}
429897be3a4Schristos 	if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
430897be3a4Schristos 		return (ISC_R_RANGE);
431897be3a4Schristos 
432897be3a4Schristos 	*low = (in_port_t)port_low;
433897be3a4Schristos 	*high = (in_port_t)port_high;
434897be3a4Schristos 
435897be3a4Schristos 	return (ISC_R_SUCCESS);
436897be3a4Schristos }
437897be3a4Schristos #else /* !HAVE_SYSCTLBYNAME */
438897be3a4Schristos static isc_result_t
439897be3a4Schristos getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
440897be3a4Schristos 	int mib_lo4[4] = SYSCTL_V4PORTRANGE_LOW;
441897be3a4Schristos 	int mib_hi4[4] = SYSCTL_V4PORTRANGE_HIGH;
442897be3a4Schristos 	int mib_lo6[4] = SYSCTL_V6PORTRANGE_LOW;
443897be3a4Schristos 	int mib_hi6[4] = SYSCTL_V6PORTRANGE_HIGH;
444897be3a4Schristos 	int *mib_lo, *mib_hi, miblen;
445897be3a4Schristos 	int port_low, port_high;
446897be3a4Schristos 	size_t portlen;
447897be3a4Schristos 
448897be3a4Schristos 	if (af == AF_INET) {
449897be3a4Schristos 		mib_lo = mib_lo4;
450897be3a4Schristos 		mib_hi = mib_hi4;
451897be3a4Schristos 		miblen = sizeof(mib_lo4) / sizeof(mib_lo4[0]);
452897be3a4Schristos 	} else {
453897be3a4Schristos 		mib_lo = mib_lo6;
454897be3a4Schristos 		mib_hi = mib_hi6;
455897be3a4Schristos 		miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]);
456897be3a4Schristos 	}
457897be3a4Schristos 
458897be3a4Schristos 	portlen = sizeof(portlen);
459897be3a4Schristos 	if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) {
460897be3a4Schristos 		return (ISC_R_FAILURE);
461897be3a4Schristos 	}
462897be3a4Schristos 
463897be3a4Schristos 	portlen = sizeof(portlen);
464897be3a4Schristos 	if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) {
465897be3a4Schristos 		return (ISC_R_FAILURE);
466897be3a4Schristos 	}
467897be3a4Schristos 
468897be3a4Schristos 	if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
469897be3a4Schristos 		return (ISC_R_RANGE);
470897be3a4Schristos 
471897be3a4Schristos 	*low = (in_port_t) port_low;
472897be3a4Schristos 	*high = (in_port_t) port_high;
473897be3a4Schristos 
474897be3a4Schristos 	return (ISC_R_SUCCESS);
475897be3a4Schristos }
476897be3a4Schristos #endif /* HAVE_SYSCTLBYNAME */
477897be3a4Schristos #endif /* USE_SYSCTL_PORTRANGE */
478897be3a4Schristos 
479897be3a4Schristos isc_result_t
480897be3a4Schristos isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
481897be3a4Schristos 	int result = ISC_R_FAILURE;
482897be3a4Schristos 
483897be3a4Schristos 	REQUIRE(low != NULL && high != NULL);
484897be3a4Schristos 
485897be3a4Schristos #if defined(USE_SYSCTL_PORTRANGE)
486897be3a4Schristos 	result = getudpportrange_sysctl(af, low, high);
487897be3a4Schristos #else
488897be3a4Schristos 	UNUSED(af);
489897be3a4Schristos #endif
490897be3a4Schristos 
491897be3a4Schristos 	if (result != ISC_R_SUCCESS) {
492897be3a4Schristos 		*low = ISC_NET_PORTRANGELOW;
493897be3a4Schristos 		*high = ISC_NET_PORTRANGEHIGH;
494897be3a4Schristos 	}
495897be3a4Schristos 
496897be3a4Schristos 	return (ISC_R_SUCCESS);	/* we currently never fail in this function */
497897be3a4Schristos }
498897be3a4Schristos 
499897be3a4Schristos void
500897be3a4Schristos isc_net_disableipv4(void) {
501897be3a4Schristos 	initialize();
502897be3a4Schristos 	if (ipv4_result == ISC_R_SUCCESS)
503897be3a4Schristos 		ipv4_result = ISC_R_DISABLED;
504897be3a4Schristos }
505897be3a4Schristos 
506897be3a4Schristos void
507897be3a4Schristos isc_net_disableipv6(void) {
508897be3a4Schristos 	initialize();
509897be3a4Schristos 	if (ipv6_result == ISC_R_SUCCESS)
510897be3a4Schristos 		ipv6_result = ISC_R_DISABLED;
511897be3a4Schristos }
512897be3a4Schristos 
513897be3a4Schristos void
514897be3a4Schristos isc_net_enableipv4(void) {
515897be3a4Schristos 	initialize();
516897be3a4Schristos 	if (ipv4_result == ISC_R_DISABLED)
517897be3a4Schristos 		ipv4_result = ISC_R_SUCCESS;
518897be3a4Schristos }
519897be3a4Schristos 
520897be3a4Schristos void
521897be3a4Schristos isc_net_enableipv6(void) {
522897be3a4Schristos 	initialize();
523897be3a4Schristos 	if (ipv6_result == ISC_R_DISABLED)
524897be3a4Schristos 		ipv6_result = ISC_R_SUCCESS;
525897be3a4Schristos }
526