1290001Sglebius/*
2290001Sglebius * Copyright (C) 2004, 2005, 2007, 2008, 2012  Internet Systems Consortium, Inc. ("ISC")
3290001Sglebius * Copyright (C) 1999-2003  Internet Software Consortium.
4290001Sglebius *
5290001Sglebius * Permission to use, copy, modify, and/or distribute this software for any
6290001Sglebius * purpose with or without fee is hereby granted, provided that the above
7290001Sglebius * copyright notice and this permission notice appear in all copies.
8290001Sglebius *
9290001Sglebius * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10290001Sglebius * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11290001Sglebius * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12290001Sglebius * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13290001Sglebius * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14290001Sglebius * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15290001Sglebius * PERFORMANCE OF THIS SOFTWARE.
16290001Sglebius */
17290001Sglebius
18290001Sglebius/* $Id$ */
19290001Sglebius
20290001Sglebius#include <config.h>
21290001Sglebius
22290001Sglebius#include <sys/types.h>
23290001Sglebius
24290001Sglebius#if defined(HAVE_SYS_SYSCTL_H)
25290001Sglebius#if defined(HAVE_SYS_PARAM_H)
26290001Sglebius#include <sys/param.h>
27290001Sglebius#endif
28290001Sglebius#include <sys/sysctl.h>
29290001Sglebius#endif
30290001Sglebius
31290001Sglebius#include <errno.h>
32290001Sglebius#include <unistd.h>
33290001Sglebius
34290001Sglebius#include <isc/log.h>
35290001Sglebius#include <isc/msgs.h>
36290001Sglebius#include <isc/net.h>
37290001Sglebius#include <isc/once.h>
38290001Sglebius#include <isc/strerror.h>
39290001Sglebius#include <isc/string.h>
40290001Sglebius#include <isc/util.h>
41290001Sglebius
42290001Sglebius/*%
43290001Sglebius * Definitions about UDP port range specification.  This is a total mess of
44290001Sglebius * portability variants: some use sysctl (but the sysctl names vary), some use
45290001Sglebius * system-specific interfaces, some have the same interface for IPv4 and IPv6,
46290001Sglebius * some separate them, etc...
47290001Sglebius */
48290001Sglebius
49290001Sglebius/*%
50290001Sglebius * The last resort defaults: use all non well known port space
51290001Sglebius */
52290001Sglebius#ifndef ISC_NET_PORTRANGELOW
53290001Sglebius#define ISC_NET_PORTRANGELOW 1024
54290001Sglebius#endif	/* ISC_NET_PORTRANGELOW */
55290001Sglebius#ifndef ISC_NET_PORTRANGEHIGH
56290001Sglebius#define ISC_NET_PORTRANGEHIGH 65535
57290001Sglebius#endif	/* ISC_NET_PORTRANGEHIGH */
58290001Sglebius
59290001Sglebius#ifdef HAVE_SYSCTLBYNAME
60290001Sglebius
61290001Sglebius/*%
62290001Sglebius * sysctl variants
63290001Sglebius */
64290001Sglebius#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
65290001Sglebius#define USE_SYSCTL_PORTRANGE
66290001Sglebius#define SYSCTL_V4PORTRANGE_LOW	"net.inet.ip.portrange.hifirst"
67290001Sglebius#define SYSCTL_V4PORTRANGE_HIGH	"net.inet.ip.portrange.hilast"
68290001Sglebius#define SYSCTL_V6PORTRANGE_LOW	"net.inet.ip.portrange.hifirst"
69290001Sglebius#define SYSCTL_V6PORTRANGE_HIGH	"net.inet.ip.portrange.hilast"
70290001Sglebius#endif
71290001Sglebius
72290001Sglebius#ifdef __NetBSD__
73290001Sglebius#define USE_SYSCTL_PORTRANGE
74290001Sglebius#define SYSCTL_V4PORTRANGE_LOW	"net.inet.ip.anonportmin"
75290001Sglebius#define SYSCTL_V4PORTRANGE_HIGH	"net.inet.ip.anonportmax"
76290001Sglebius#define SYSCTL_V6PORTRANGE_LOW	"net.inet6.ip6.anonportmin"
77290001Sglebius#define SYSCTL_V6PORTRANGE_HIGH	"net.inet6.ip6.anonportmax"
78290001Sglebius#endif
79290001Sglebius
80290001Sglebius#else /* !HAVE_SYSCTLBYNAME */
81290001Sglebius
82290001Sglebius#ifdef __OpenBSD__
83290001Sglebius#define USE_SYSCTL_PORTRANGE
84290001Sglebius#define SYSCTL_V4PORTRANGE_LOW	{ CTL_NET, PF_INET, IPPROTO_IP, \
85290001Sglebius				  IPCTL_IPPORT_HIFIRSTAUTO }
86290001Sglebius#define SYSCTL_V4PORTRANGE_HIGH	{ CTL_NET, PF_INET, IPPROTO_IP, \
87290001Sglebius				  IPCTL_IPPORT_HILASTAUTO }
88290001Sglebius/* Same for IPv6 */
89290001Sglebius#define SYSCTL_V6PORTRANGE_LOW	SYSCTL_V4PORTRANGE_LOW
90290001Sglebius#define SYSCTL_V6PORTRANGE_HIGH	SYSCTL_V4PORTRANGE_HIGH
91290001Sglebius#endif
92290001Sglebius
93290001Sglebius#endif /* HAVE_SYSCTLBYNAME */
94290001Sglebius
95290001Sglebius#if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
96290001Sglebiusconst struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
97290001Sglebius#endif
98290001Sglebius
99290001Sglebius#if defined(ISC_PLATFORM_HAVEIPV6)
100290001Sglebius
101290001Sglebius# if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
102290001Sglebiusconst struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
103290001Sglebius# endif
104290001Sglebius
105290001Sglebius# if defined(WANT_IPV6)
106290001Sglebiusstatic isc_once_t 	once_ipv6only = ISC_ONCE_INIT;
107290001Sglebius# endif
108290001Sglebius
109290001Sglebius# if defined(ISC_PLATFORM_HAVEIPV6) && \
110290001Sglebius     defined(WANT_IPV6) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
111290001Sglebiusstatic isc_once_t 	once_ipv6pktinfo = ISC_ONCE_INIT;
112290001Sglebius# endif
113290001Sglebius#endif /* ISC_PLATFORM_HAVEIPV6 */
114290001Sglebius
115290001Sglebiusstatic isc_once_t 	once = ISC_ONCE_INIT;
116290001Sglebius
117290001Sglebiusstatic isc_result_t	ipv4_result = ISC_R_NOTFOUND;
118290001Sglebiusstatic isc_result_t	ipv6_result = ISC_R_NOTFOUND;
119290001Sglebiusstatic isc_result_t	unix_result = ISC_R_NOTFOUND;
120290001Sglebiusstatic isc_result_t	ipv6only_result = ISC_R_NOTFOUND;
121290001Sglebiusstatic isc_result_t	ipv6pktinfo_result = ISC_R_NOTFOUND;
122290001Sglebius
123290001Sglebiusstatic isc_result_t
124290001Sglebiustry_proto(int domain) {
125290001Sglebius	int s;
126290001Sglebius	isc_result_t result = ISC_R_SUCCESS;
127290001Sglebius	char strbuf[ISC_STRERRORSIZE];
128290001Sglebius
129290001Sglebius	s = socket(domain, SOCK_STREAM, 0);
130290001Sglebius	if (s == -1) {
131290001Sglebius		switch (errno) {
132290001Sglebius#ifdef EAFNOSUPPORT
133290001Sglebius		case EAFNOSUPPORT:
134290001Sglebius#endif
135290001Sglebius#ifdef EPROTONOSUPPORT
136290001Sglebius		case EPROTONOSUPPORT:
137290001Sglebius#endif
138290001Sglebius#ifdef EINVAL
139290001Sglebius		case EINVAL:
140290001Sglebius#endif
141290001Sglebius			return (ISC_R_NOTFOUND);
142290001Sglebius		default:
143290001Sglebius			isc__strerror(errno, strbuf, sizeof(strbuf));
144290001Sglebius			UNEXPECTED_ERROR(__FILE__, __LINE__,
145290001Sglebius					 "socket() %s: %s",
146290001Sglebius					 isc_msgcat_get(isc_msgcat,
147290001Sglebius							ISC_MSGSET_GENERAL,
148290001Sglebius							ISC_MSG_FAILED,
149290001Sglebius							"failed"),
150290001Sglebius					 strbuf);
151290001Sglebius			return (ISC_R_UNEXPECTED);
152290001Sglebius		}
153290001Sglebius	}
154290001Sglebius
155290001Sglebius#ifdef ISC_PLATFORM_HAVEIPV6
156290001Sglebius#ifdef WANT_IPV6
157290001Sglebius#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
158290001Sglebius	if (domain == PF_INET6) {
159290001Sglebius		struct sockaddr_in6 sin6;
160290001Sglebius		GETSOCKNAME_SOCKLEN_TYPE len;	/* NTP local change */
161290001Sglebius
162290001Sglebius		/*
163290001Sglebius		 * Check to see if IPv6 is broken, as is common on Linux.
164290001Sglebius		 */
165290001Sglebius		len = sizeof(sin6);
166290001Sglebius		if (getsockname(s, (struct sockaddr *)&sin6, &len) < 0)
167290001Sglebius		{
168290001Sglebius			isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
169290001Sglebius				      ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
170290001Sglebius				      "retrieving the address of an IPv6 "
171290001Sglebius				      "socket from the kernel failed.");
172290001Sglebius			isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
173290001Sglebius				      ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
174290001Sglebius				      "IPv6 is not supported.");
175290001Sglebius			result = ISC_R_NOTFOUND;
176290001Sglebius		} else {
177290001Sglebius			if (len == sizeof(struct sockaddr_in6))
178290001Sglebius				result = ISC_R_SUCCESS;
179290001Sglebius			else {
180290001Sglebius				isc_log_write(isc_lctx,
181290001Sglebius					      ISC_LOGCATEGORY_GENERAL,
182290001Sglebius					      ISC_LOGMODULE_SOCKET,
183290001Sglebius					      ISC_LOG_ERROR,
184290001Sglebius					      "IPv6 structures in kernel and "
185290001Sglebius					      "user space do not match.");
186290001Sglebius				isc_log_write(isc_lctx,
187290001Sglebius					      ISC_LOGCATEGORY_GENERAL,
188290001Sglebius					      ISC_LOGMODULE_SOCKET,
189290001Sglebius					      ISC_LOG_ERROR,
190290001Sglebius					      "IPv6 is not supported.");
191290001Sglebius				result = ISC_R_NOTFOUND;
192290001Sglebius			}
193290001Sglebius		}
194290001Sglebius	}
195290001Sglebius#endif
196290001Sglebius#endif
197290001Sglebius#endif
198290001Sglebius
199290001Sglebius	(void)close(s);
200290001Sglebius
201290001Sglebius	return (result);
202290001Sglebius}
203290001Sglebius
204290001Sglebiusstatic void
205290001Sglebiusinitialize_action(void) {
206290001Sglebius	ipv4_result = try_proto(PF_INET);
207290001Sglebius#ifdef ISC_PLATFORM_HAVEIPV6
208290001Sglebius#ifdef WANT_IPV6
209290001Sglebius#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
210290001Sglebius	ipv6_result = try_proto(PF_INET6);
211290001Sglebius#endif
212290001Sglebius#endif
213290001Sglebius#endif
214290001Sglebius#ifdef ISC_PLATFORM_HAVESYSUNH
215290001Sglebius	unix_result = try_proto(PF_UNIX);
216290001Sglebius#endif
217290001Sglebius}
218290001Sglebius
219290001Sglebiusstatic void
220290001Sglebiusinitialize(void) {
221290001Sglebius	RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
222290001Sglebius}
223290001Sglebius
224290001Sglebiusisc_result_t
225290001Sglebiusisc_net_probeipv4(void) {
226290001Sglebius	initialize();
227290001Sglebius	return (ipv4_result);
228290001Sglebius}
229290001Sglebius
230290001Sglebiusisc_result_t
231290001Sglebiusisc_net_probeipv6(void) {
232290001Sglebius	initialize();
233290001Sglebius	return (ipv6_result);
234290001Sglebius}
235290001Sglebius
236290001Sglebiusisc_result_t
237290001Sglebiusisc_net_probeunix(void) {
238290001Sglebius	initialize();
239290001Sglebius	return (unix_result);
240290001Sglebius}
241290001Sglebius
242290001Sglebius#ifdef ISC_PLATFORM_HAVEIPV6
243290001Sglebius#ifdef WANT_IPV6
244290001Sglebiusstatic void
245290001Sglebiustry_ipv6only(void) {
246290001Sglebius#ifdef IPV6_V6ONLY
247290001Sglebius	int s, on;
248290001Sglebius	char strbuf[ISC_STRERRORSIZE];
249290001Sglebius#endif
250290001Sglebius	isc_result_t result;
251290001Sglebius
252290001Sglebius	result = isc_net_probeipv6();
253290001Sglebius	if (result != ISC_R_SUCCESS) {
254290001Sglebius		ipv6only_result = result;
255290001Sglebius		return;
256290001Sglebius	}
257290001Sglebius
258290001Sglebius#ifndef IPV6_V6ONLY
259290001Sglebius	ipv6only_result = ISC_R_NOTFOUND;
260290001Sglebius	return;
261290001Sglebius#else
262290001Sglebius	/* check for TCP sockets */
263290001Sglebius	s = socket(PF_INET6, SOCK_STREAM, 0);
264290001Sglebius	if (s == -1) {
265290001Sglebius		isc__strerror(errno, strbuf, sizeof(strbuf));
266290001Sglebius		UNEXPECTED_ERROR(__FILE__, __LINE__,
267290001Sglebius				 "socket() %s: %s",
268290001Sglebius				 isc_msgcat_get(isc_msgcat,
269290001Sglebius						ISC_MSGSET_GENERAL,
270290001Sglebius						ISC_MSG_FAILED,
271290001Sglebius						"failed"),
272290001Sglebius				 strbuf);
273290001Sglebius		ipv6only_result = ISC_R_UNEXPECTED;
274290001Sglebius		return;
275290001Sglebius	}
276290001Sglebius
277290001Sglebius	on = 1;
278290001Sglebius	if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
279290001Sglebius		ipv6only_result = ISC_R_NOTFOUND;
280290001Sglebius		goto close;
281290001Sglebius	}
282290001Sglebius
283290001Sglebius	close(s);
284290001Sglebius
285290001Sglebius	/* check for UDP sockets */
286290001Sglebius	s = socket(PF_INET6, SOCK_DGRAM, 0);
287290001Sglebius	if (s == -1) {
288290001Sglebius		isc__strerror(errno, strbuf, sizeof(strbuf));
289290001Sglebius		UNEXPECTED_ERROR(__FILE__, __LINE__,
290290001Sglebius				 "socket() %s: %s",
291290001Sglebius				 isc_msgcat_get(isc_msgcat,
292290001Sglebius						ISC_MSGSET_GENERAL,
293290001Sglebius						ISC_MSG_FAILED,
294290001Sglebius						"failed"),
295290001Sglebius				 strbuf);
296290001Sglebius		ipv6only_result = ISC_R_UNEXPECTED;
297290001Sglebius		return;
298290001Sglebius	}
299290001Sglebius
300290001Sglebius	on = 1;
301290001Sglebius	if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
302290001Sglebius		ipv6only_result = ISC_R_NOTFOUND;
303290001Sglebius		goto close;
304290001Sglebius	}
305290001Sglebius
306290001Sglebius	ipv6only_result = ISC_R_SUCCESS;
307290001Sglebius
308290001Sglebiusclose:
309290001Sglebius	close(s);
310290001Sglebius	return;
311290001Sglebius#endif /* IPV6_V6ONLY */
312290001Sglebius}
313290001Sglebius
314290001Sglebiusstatic void
315290001Sglebiusinitialize_ipv6only(void) {
316290001Sglebius	RUNTIME_CHECK(isc_once_do(&once_ipv6only,
317290001Sglebius				  try_ipv6only) == ISC_R_SUCCESS);
318290001Sglebius}
319290001Sglebius
320290001Sglebius#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
321290001Sglebiusstatic void
322290001Sglebiustry_ipv6pktinfo(void) {
323290001Sglebius	int s, on;
324290001Sglebius	char strbuf[ISC_STRERRORSIZE];
325290001Sglebius	isc_result_t result;
326290001Sglebius	int optname;
327290001Sglebius
328290001Sglebius	result = isc_net_probeipv6();
329290001Sglebius	if (result != ISC_R_SUCCESS) {
330290001Sglebius		ipv6pktinfo_result = result;
331290001Sglebius		return;
332290001Sglebius	}
333290001Sglebius
334290001Sglebius	/* we only use this for UDP sockets */
335290001Sglebius	s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
336290001Sglebius	if (s == -1) {
337290001Sglebius		isc__strerror(errno, strbuf, sizeof(strbuf));
338290001Sglebius		UNEXPECTED_ERROR(__FILE__, __LINE__,
339290001Sglebius				 "socket() %s: %s",
340290001Sglebius				 isc_msgcat_get(isc_msgcat,
341290001Sglebius						ISC_MSGSET_GENERAL,
342290001Sglebius						ISC_MSG_FAILED,
343290001Sglebius						"failed"),
344290001Sglebius				 strbuf);
345290001Sglebius		ipv6pktinfo_result = ISC_R_UNEXPECTED;
346290001Sglebius		return;
347290001Sglebius	}
348290001Sglebius
349290001Sglebius#ifdef IPV6_RECVPKTINFO
350290001Sglebius	optname = IPV6_RECVPKTINFO;
351290001Sglebius#else
352290001Sglebius	optname = IPV6_PKTINFO;
353290001Sglebius#endif
354290001Sglebius	on = 1;
355290001Sglebius	if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
356290001Sglebius		ipv6pktinfo_result = ISC_R_NOTFOUND;
357290001Sglebius		goto close;
358290001Sglebius	}
359290001Sglebius
360290001Sglebius	ipv6pktinfo_result = ISC_R_SUCCESS;
361290001Sglebius
362290001Sglebiusclose:
363290001Sglebius	close(s);
364290001Sglebius	return;
365290001Sglebius}
366290001Sglebius
367290001Sglebiusstatic void
368290001Sglebiusinitialize_ipv6pktinfo(void) {
369290001Sglebius	RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
370290001Sglebius				  try_ipv6pktinfo) == ISC_R_SUCCESS);
371290001Sglebius}
372290001Sglebius#endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
373290001Sglebius#endif /* WANT_IPV6 */
374290001Sglebius#endif /* ISC_PLATFORM_HAVEIPV6 */
375290001Sglebius
376290001Sglebiusisc_result_t
377290001Sglebiusisc_net_probe_ipv6only(void) {
378290001Sglebius#ifdef ISC_PLATFORM_HAVEIPV6
379290001Sglebius#ifdef WANT_IPV6
380290001Sglebius	initialize_ipv6only();
381290001Sglebius#else
382290001Sglebius	ipv6only_result = ISC_R_NOTFOUND;
383290001Sglebius#endif
384290001Sglebius#endif
385290001Sglebius	return (ipv6only_result);
386290001Sglebius}
387290001Sglebius
388290001Sglebiusisc_result_t
389290001Sglebiusisc_net_probe_ipv6pktinfo(void) {
390290001Sglebius#ifdef ISC_PLATFORM_HAVEIPV6
391290001Sglebius#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
392290001Sglebius#ifdef WANT_IPV6
393290001Sglebius	initialize_ipv6pktinfo();
394290001Sglebius#else
395290001Sglebius	ipv6pktinfo_result = ISC_R_NOTFOUND;
396290001Sglebius#endif
397290001Sglebius#endif
398290001Sglebius#endif
399290001Sglebius	return (ipv6pktinfo_result);
400290001Sglebius}
401290001Sglebius
402290001Sglebius#if defined(USE_SYSCTL_PORTRANGE)
403290001Sglebius#if defined(HAVE_SYSCTLBYNAME)
404290001Sglebiusstatic isc_result_t
405290001Sglebiusgetudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
406290001Sglebius	int port_low, port_high;
407290001Sglebius	size_t portlen;
408290001Sglebius	const char *sysctlname_lowport, *sysctlname_hiport;
409290001Sglebius
410290001Sglebius	if (af == AF_INET) {
411290001Sglebius		sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW;
412290001Sglebius		sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH;
413290001Sglebius	} else {
414290001Sglebius		sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
415290001Sglebius		sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
416290001Sglebius	}
417290001Sglebius	portlen = sizeof(portlen);
418290001Sglebius	if (sysctlbyname(sysctlname_lowport, &port_low, &portlen,
419290001Sglebius			 NULL, 0) < 0) {
420290001Sglebius		return (ISC_R_FAILURE);
421290001Sglebius	}
422290001Sglebius	portlen = sizeof(portlen);
423290001Sglebius	if (sysctlbyname(sysctlname_hiport, &port_high, &portlen,
424290001Sglebius			 NULL, 0) < 0) {
425290001Sglebius		return (ISC_R_FAILURE);
426290001Sglebius	}
427290001Sglebius	if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
428290001Sglebius		return (ISC_R_RANGE);
429290001Sglebius
430290001Sglebius	*low = (in_port_t)port_low;
431290001Sglebius	*high = (in_port_t)port_high;
432290001Sglebius
433290001Sglebius	return (ISC_R_SUCCESS);
434290001Sglebius}
435290001Sglebius#else /* !HAVE_SYSCTLBYNAME */
436290001Sglebiusstatic isc_result_t
437290001Sglebiusgetudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
438290001Sglebius	int mib_lo4[4] = SYSCTL_V4PORTRANGE_LOW;
439290001Sglebius	int mib_hi4[4] = SYSCTL_V4PORTRANGE_HIGH;
440290001Sglebius	int mib_lo6[4] = SYSCTL_V6PORTRANGE_LOW;
441290001Sglebius	int mib_hi6[4] = SYSCTL_V6PORTRANGE_HIGH;
442290001Sglebius	int *mib_lo, *mib_hi, miblen;
443290001Sglebius	int port_low, port_high;
444290001Sglebius	size_t portlen;
445290001Sglebius
446290001Sglebius	if (af == AF_INET) {
447290001Sglebius		mib_lo = mib_lo4;
448290001Sglebius		mib_hi = mib_hi4;
449290001Sglebius		miblen = sizeof(mib_lo4) / sizeof(mib_lo4[0]);
450290001Sglebius	} else {
451290001Sglebius		mib_lo = mib_lo6;
452290001Sglebius		mib_hi = mib_hi6;
453290001Sglebius		miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]);
454290001Sglebius	}
455290001Sglebius
456290001Sglebius	portlen = sizeof(portlen);
457290001Sglebius	if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) {
458290001Sglebius		return (ISC_R_FAILURE);
459290001Sglebius	}
460290001Sglebius
461290001Sglebius	portlen = sizeof(portlen);
462290001Sglebius	if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) {
463290001Sglebius		return (ISC_R_FAILURE);
464290001Sglebius	}
465290001Sglebius
466290001Sglebius	if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
467290001Sglebius		return (ISC_R_RANGE);
468290001Sglebius
469290001Sglebius	*low = (in_port_t) port_low;
470290001Sglebius	*high = (in_port_t) port_high;
471290001Sglebius
472290001Sglebius	return (ISC_R_SUCCESS);
473290001Sglebius}
474290001Sglebius#endif /* HAVE_SYSCTLBYNAME */
475290001Sglebius#endif /* USE_SYSCTL_PORTRANGE */
476290001Sglebius
477290001Sglebiusisc_result_t
478290001Sglebiusisc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
479290001Sglebius	int result = ISC_R_FAILURE;
480290001Sglebius
481290001Sglebius	REQUIRE(low != NULL && high != NULL);
482290001Sglebius
483290001Sglebius#if defined(USE_SYSCTL_PORTRANGE)
484290001Sglebius	result = getudpportrange_sysctl(af, low, high);
485290001Sglebius#else
486290001Sglebius	UNUSED(af);
487290001Sglebius#endif
488290001Sglebius
489290001Sglebius	if (result != ISC_R_SUCCESS) {
490290001Sglebius		*low = ISC_NET_PORTRANGELOW;
491290001Sglebius		*high = ISC_NET_PORTRANGEHIGH;
492290001Sglebius	}
493290001Sglebius
494290001Sglebius	return (ISC_R_SUCCESS);	/* we currently never fail in this function */
495290001Sglebius}
496290001Sglebius
497290001Sglebiusvoid
498290001Sglebiusisc_net_disableipv4(void) {
499290001Sglebius	initialize();
500290001Sglebius	if (ipv4_result == ISC_R_SUCCESS)
501290001Sglebius		ipv4_result = ISC_R_DISABLED;
502290001Sglebius}
503290001Sglebius
504290001Sglebiusvoid
505290001Sglebiusisc_net_disableipv6(void) {
506290001Sglebius	initialize();
507290001Sglebius	if (ipv6_result == ISC_R_SUCCESS)
508290001Sglebius		ipv6_result = ISC_R_DISABLED;
509290001Sglebius}
510290001Sglebius
511290001Sglebiusvoid
512290001Sglebiusisc_net_enableipv4(void) {
513290001Sglebius	initialize();
514290001Sglebius	if (ipv4_result == ISC_R_DISABLED)
515290001Sglebius		ipv4_result = ISC_R_SUCCESS;
516290001Sglebius}
517290001Sglebius
518290001Sglebiusvoid
519290001Sglebiusisc_net_enableipv6(void) {
520290001Sglebius	initialize();
521290001Sglebius	if (ipv6_result == ISC_R_DISABLED)
522290001Sglebius		ipv6_result = ISC_R_SUCCESS;
523290001Sglebius}
524