1*00b67f09SDavid van Moolenbroek /* $NetBSD: net.c,v 1.8 2015/07/08 17:29:00 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004, 2005, 2007, 2008, 2012-2015 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 1999-2003 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek #include <config.h>
23*00b67f09SDavid van Moolenbroek
24*00b67f09SDavid van Moolenbroek #include <sys/types.h>
25*00b67f09SDavid van Moolenbroek
26*00b67f09SDavid van Moolenbroek #if defined(HAVE_SYS_SYSCTL_H)
27*00b67f09SDavid van Moolenbroek #if defined(HAVE_SYS_PARAM_H)
28*00b67f09SDavid van Moolenbroek #include <sys/param.h>
29*00b67f09SDavid van Moolenbroek #endif
30*00b67f09SDavid van Moolenbroek #include <sys/sysctl.h>
31*00b67f09SDavid van Moolenbroek #endif
32*00b67f09SDavid van Moolenbroek #include <sys/uio.h>
33*00b67f09SDavid van Moolenbroek
34*00b67f09SDavid van Moolenbroek #include <errno.h>
35*00b67f09SDavid van Moolenbroek #include <unistd.h>
36*00b67f09SDavid van Moolenbroek #include <fcntl.h>
37*00b67f09SDavid van Moolenbroek
38*00b67f09SDavid van Moolenbroek #include <isc/log.h>
39*00b67f09SDavid van Moolenbroek #include <isc/msgs.h>
40*00b67f09SDavid van Moolenbroek #include <isc/net.h>
41*00b67f09SDavid van Moolenbroek #include <isc/netdb.h>
42*00b67f09SDavid van Moolenbroek #include <isc/once.h>
43*00b67f09SDavid van Moolenbroek #include <isc/strerror.h>
44*00b67f09SDavid van Moolenbroek #include <isc/string.h>
45*00b67f09SDavid van Moolenbroek #include <isc/util.h>
46*00b67f09SDavid van Moolenbroek
47*00b67f09SDavid van Moolenbroek #ifndef ISC_SOCKADDR_LEN_T
48*00b67f09SDavid van Moolenbroek #define ISC_SOCKADDR_LEN_T unsigned int
49*00b67f09SDavid van Moolenbroek #endif
50*00b67f09SDavid van Moolenbroek
51*00b67f09SDavid van Moolenbroek /*%
52*00b67f09SDavid van Moolenbroek * Definitions about UDP port range specification. This is a total mess of
53*00b67f09SDavid van Moolenbroek * portability variants: some use sysctl (but the sysctl names vary), some use
54*00b67f09SDavid van Moolenbroek * system-specific interfaces, some have the same interface for IPv4 and IPv6,
55*00b67f09SDavid van Moolenbroek * some separate them, etc...
56*00b67f09SDavid van Moolenbroek */
57*00b67f09SDavid van Moolenbroek
58*00b67f09SDavid van Moolenbroek /*%
59*00b67f09SDavid van Moolenbroek * The last resort defaults: use all non well known port space
60*00b67f09SDavid van Moolenbroek */
61*00b67f09SDavid van Moolenbroek #ifndef ISC_NET_PORTRANGELOW
62*00b67f09SDavid van Moolenbroek #define ISC_NET_PORTRANGELOW 1024
63*00b67f09SDavid van Moolenbroek #endif /* ISC_NET_PORTRANGELOW */
64*00b67f09SDavid van Moolenbroek #ifndef ISC_NET_PORTRANGEHIGH
65*00b67f09SDavid van Moolenbroek #define ISC_NET_PORTRANGEHIGH 65535
66*00b67f09SDavid van Moolenbroek #endif /* ISC_NET_PORTRANGEHIGH */
67*00b67f09SDavid van Moolenbroek
68*00b67f09SDavid van Moolenbroek #ifdef HAVE_SYSCTLBYNAME
69*00b67f09SDavid van Moolenbroek
70*00b67f09SDavid van Moolenbroek /*%
71*00b67f09SDavid van Moolenbroek * sysctl variants
72*00b67f09SDavid van Moolenbroek */
73*00b67f09SDavid van Moolenbroek #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
74*00b67f09SDavid van Moolenbroek #define USE_SYSCTL_PORTRANGE
75*00b67f09SDavid van Moolenbroek #define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.portrange.hifirst"
76*00b67f09SDavid van Moolenbroek #define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
77*00b67f09SDavid van Moolenbroek #define SYSCTL_V6PORTRANGE_LOW "net.inet.ip.portrange.hifirst"
78*00b67f09SDavid van Moolenbroek #define SYSCTL_V6PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
79*00b67f09SDavid van Moolenbroek #endif
80*00b67f09SDavid van Moolenbroek
81*00b67f09SDavid van Moolenbroek #ifdef __NetBSD__
82*00b67f09SDavid van Moolenbroek #define USE_SYSCTL_PORTRANGE
83*00b67f09SDavid van Moolenbroek #define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.anonportmin"
84*00b67f09SDavid van Moolenbroek #define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.anonportmax"
85*00b67f09SDavid van Moolenbroek #define SYSCTL_V6PORTRANGE_LOW "net.inet6.ip6.anonportmin"
86*00b67f09SDavid van Moolenbroek #define SYSCTL_V6PORTRANGE_HIGH "net.inet6.ip6.anonportmax"
87*00b67f09SDavid van Moolenbroek #endif
88*00b67f09SDavid van Moolenbroek
89*00b67f09SDavid van Moolenbroek #else /* !HAVE_SYSCTLBYNAME */
90*00b67f09SDavid van Moolenbroek
91*00b67f09SDavid van Moolenbroek #ifdef __OpenBSD__
92*00b67f09SDavid van Moolenbroek #define USE_SYSCTL_PORTRANGE
93*00b67f09SDavid van Moolenbroek #define SYSCTL_V4PORTRANGE_LOW { CTL_NET, PF_INET, IPPROTO_IP, \
94*00b67f09SDavid van Moolenbroek IPCTL_IPPORT_HIFIRSTAUTO }
95*00b67f09SDavid van Moolenbroek #define SYSCTL_V4PORTRANGE_HIGH { CTL_NET, PF_INET, IPPROTO_IP, \
96*00b67f09SDavid van Moolenbroek IPCTL_IPPORT_HILASTAUTO }
97*00b67f09SDavid van Moolenbroek /* Same for IPv6 */
98*00b67f09SDavid van Moolenbroek #define SYSCTL_V6PORTRANGE_LOW SYSCTL_V4PORTRANGE_LOW
99*00b67f09SDavid van Moolenbroek #define SYSCTL_V6PORTRANGE_HIGH SYSCTL_V4PORTRANGE_HIGH
100*00b67f09SDavid van Moolenbroek #endif
101*00b67f09SDavid van Moolenbroek
102*00b67f09SDavid van Moolenbroek #endif /* HAVE_SYSCTLBYNAME */
103*00b67f09SDavid van Moolenbroek
104*00b67f09SDavid van Moolenbroek #if defined(ISC_PLATFORM_HAVEIPV6)
105*00b67f09SDavid van Moolenbroek # if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
106*00b67f09SDavid van Moolenbroek const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
107*00b67f09SDavid van Moolenbroek # endif
108*00b67f09SDavid van Moolenbroek
109*00b67f09SDavid van Moolenbroek # if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
110*00b67f09SDavid van Moolenbroek const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
111*00b67f09SDavid van Moolenbroek # endif
112*00b67f09SDavid van Moolenbroek
113*00b67f09SDavid van Moolenbroek # if defined(WANT_IPV6)
114*00b67f09SDavid van Moolenbroek static isc_once_t once_ipv6only = ISC_ONCE_INIT;
115*00b67f09SDavid van Moolenbroek # endif
116*00b67f09SDavid van Moolenbroek
117*00b67f09SDavid van Moolenbroek # if defined(ISC_PLATFORM_HAVEIN6PKTINFO)
118*00b67f09SDavid van Moolenbroek static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
119*00b67f09SDavid van Moolenbroek # endif
120*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_HAVEIPV6 */
121*00b67f09SDavid van Moolenbroek
122*00b67f09SDavid van Moolenbroek static isc_once_t once = ISC_ONCE_INIT;
123*00b67f09SDavid van Moolenbroek static isc_once_t once_dscp = ISC_ONCE_INIT;
124*00b67f09SDavid van Moolenbroek
125*00b67f09SDavid van Moolenbroek static isc_result_t ipv4_result = ISC_R_NOTFOUND;
126*00b67f09SDavid van Moolenbroek static isc_result_t ipv6_result = ISC_R_NOTFOUND;
127*00b67f09SDavid van Moolenbroek static isc_result_t unix_result = ISC_R_NOTFOUND;
128*00b67f09SDavid van Moolenbroek static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
129*00b67f09SDavid van Moolenbroek static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
130*00b67f09SDavid van Moolenbroek static unsigned int dscp_result = 0;
131*00b67f09SDavid van Moolenbroek
132*00b67f09SDavid van Moolenbroek static isc_result_t
try_proto(int domain)133*00b67f09SDavid van Moolenbroek try_proto(int domain) {
134*00b67f09SDavid van Moolenbroek int s;
135*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
136*00b67f09SDavid van Moolenbroek char strbuf[ISC_STRERRORSIZE];
137*00b67f09SDavid van Moolenbroek
138*00b67f09SDavid van Moolenbroek s = socket(domain, SOCK_STREAM, 0);
139*00b67f09SDavid van Moolenbroek if (s == -1) {
140*00b67f09SDavid van Moolenbroek switch (errno) {
141*00b67f09SDavid van Moolenbroek #ifdef EAFNOSUPPORT
142*00b67f09SDavid van Moolenbroek case EAFNOSUPPORT:
143*00b67f09SDavid van Moolenbroek #endif
144*00b67f09SDavid van Moolenbroek #ifdef EPROTONOSUPPORT
145*00b67f09SDavid van Moolenbroek case EPROTONOSUPPORT:
146*00b67f09SDavid van Moolenbroek #endif
147*00b67f09SDavid van Moolenbroek #ifdef EINVAL
148*00b67f09SDavid van Moolenbroek case EINVAL:
149*00b67f09SDavid van Moolenbroek #endif
150*00b67f09SDavid van Moolenbroek return (ISC_R_NOTFOUND);
151*00b67f09SDavid van Moolenbroek default:
152*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
153*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__,
154*00b67f09SDavid van Moolenbroek "socket() %s: %s",
155*00b67f09SDavid van Moolenbroek isc_msgcat_get(isc_msgcat,
156*00b67f09SDavid van Moolenbroek ISC_MSGSET_GENERAL,
157*00b67f09SDavid van Moolenbroek ISC_MSG_FAILED,
158*00b67f09SDavid van Moolenbroek "failed"),
159*00b67f09SDavid van Moolenbroek strbuf);
160*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
161*00b67f09SDavid van Moolenbroek }
162*00b67f09SDavid van Moolenbroek }
163*00b67f09SDavid van Moolenbroek
164*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVEIPV6
165*00b67f09SDavid van Moolenbroek #ifdef WANT_IPV6
166*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
167*00b67f09SDavid van Moolenbroek if (domain == PF_INET6) {
168*00b67f09SDavid van Moolenbroek struct sockaddr_in6 sin6;
169*00b67f09SDavid van Moolenbroek unsigned int len;
170*00b67f09SDavid van Moolenbroek
171*00b67f09SDavid van Moolenbroek /*
172*00b67f09SDavid van Moolenbroek * Check to see if IPv6 is broken, as is common on Linux.
173*00b67f09SDavid van Moolenbroek */
174*00b67f09SDavid van Moolenbroek len = sizeof(sin6);
175*00b67f09SDavid van Moolenbroek if (getsockname(s, (struct sockaddr *)&sin6, (void *)&len) < 0)
176*00b67f09SDavid van Moolenbroek {
177*00b67f09SDavid van Moolenbroek isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
178*00b67f09SDavid van Moolenbroek ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
179*00b67f09SDavid van Moolenbroek "retrieving the address of an IPv6 "
180*00b67f09SDavid van Moolenbroek "socket from the kernel failed.");
181*00b67f09SDavid van Moolenbroek isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
182*00b67f09SDavid van Moolenbroek ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
183*00b67f09SDavid van Moolenbroek "IPv6 is not supported.");
184*00b67f09SDavid van Moolenbroek result = ISC_R_NOTFOUND;
185*00b67f09SDavid van Moolenbroek } else {
186*00b67f09SDavid van Moolenbroek if (len == sizeof(struct sockaddr_in6))
187*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
188*00b67f09SDavid van Moolenbroek else {
189*00b67f09SDavid van Moolenbroek isc_log_write(isc_lctx,
190*00b67f09SDavid van Moolenbroek ISC_LOGCATEGORY_GENERAL,
191*00b67f09SDavid van Moolenbroek ISC_LOGMODULE_SOCKET,
192*00b67f09SDavid van Moolenbroek ISC_LOG_ERROR,
193*00b67f09SDavid van Moolenbroek "IPv6 structures in kernel and "
194*00b67f09SDavid van Moolenbroek "user space do not match.");
195*00b67f09SDavid van Moolenbroek isc_log_write(isc_lctx,
196*00b67f09SDavid van Moolenbroek ISC_LOGCATEGORY_GENERAL,
197*00b67f09SDavid van Moolenbroek ISC_LOGMODULE_SOCKET,
198*00b67f09SDavid van Moolenbroek ISC_LOG_ERROR,
199*00b67f09SDavid van Moolenbroek "IPv6 is not supported.");
200*00b67f09SDavid van Moolenbroek result = ISC_R_NOTFOUND;
201*00b67f09SDavid van Moolenbroek }
202*00b67f09SDavid van Moolenbroek }
203*00b67f09SDavid van Moolenbroek }
204*00b67f09SDavid van Moolenbroek #endif
205*00b67f09SDavid van Moolenbroek #endif
206*00b67f09SDavid van Moolenbroek #endif
207*00b67f09SDavid van Moolenbroek
208*00b67f09SDavid van Moolenbroek (void)close(s);
209*00b67f09SDavid van Moolenbroek
210*00b67f09SDavid van Moolenbroek return (result);
211*00b67f09SDavid van Moolenbroek }
212*00b67f09SDavid van Moolenbroek
213*00b67f09SDavid van Moolenbroek static void
initialize_action(void)214*00b67f09SDavid van Moolenbroek initialize_action(void) {
215*00b67f09SDavid van Moolenbroek ipv4_result = try_proto(PF_INET);
216*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVEIPV6
217*00b67f09SDavid van Moolenbroek #ifdef WANT_IPV6
218*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
219*00b67f09SDavid van Moolenbroek ipv6_result = try_proto(PF_INET6);
220*00b67f09SDavid van Moolenbroek #endif
221*00b67f09SDavid van Moolenbroek #endif
222*00b67f09SDavid van Moolenbroek #endif
223*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVESYSUNH
224*00b67f09SDavid van Moolenbroek unix_result = try_proto(PF_UNIX);
225*00b67f09SDavid van Moolenbroek #endif
226*00b67f09SDavid van Moolenbroek }
227*00b67f09SDavid van Moolenbroek
228*00b67f09SDavid van Moolenbroek static void
initialize(void)229*00b67f09SDavid van Moolenbroek initialize(void) {
230*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
231*00b67f09SDavid van Moolenbroek }
232*00b67f09SDavid van Moolenbroek
233*00b67f09SDavid van Moolenbroek isc_result_t
isc_net_probeipv4(void)234*00b67f09SDavid van Moolenbroek isc_net_probeipv4(void) {
235*00b67f09SDavid van Moolenbroek initialize();
236*00b67f09SDavid van Moolenbroek return (ipv4_result);
237*00b67f09SDavid van Moolenbroek }
238*00b67f09SDavid van Moolenbroek
239*00b67f09SDavid van Moolenbroek isc_result_t
isc_net_probeipv6(void)240*00b67f09SDavid van Moolenbroek isc_net_probeipv6(void) {
241*00b67f09SDavid van Moolenbroek initialize();
242*00b67f09SDavid van Moolenbroek return (ipv6_result);
243*00b67f09SDavid van Moolenbroek }
244*00b67f09SDavid van Moolenbroek
245*00b67f09SDavid van Moolenbroek isc_result_t
isc_net_probeunix(void)246*00b67f09SDavid van Moolenbroek isc_net_probeunix(void) {
247*00b67f09SDavid van Moolenbroek initialize();
248*00b67f09SDavid van Moolenbroek return (unix_result);
249*00b67f09SDavid van Moolenbroek }
250*00b67f09SDavid van Moolenbroek
251*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVEIPV6
252*00b67f09SDavid van Moolenbroek #ifdef WANT_IPV6
253*00b67f09SDavid van Moolenbroek static void
try_ipv6only(void)254*00b67f09SDavid van Moolenbroek try_ipv6only(void) {
255*00b67f09SDavid van Moolenbroek #ifdef IPV6_V6ONLY
256*00b67f09SDavid van Moolenbroek int s, on;
257*00b67f09SDavid van Moolenbroek char strbuf[ISC_STRERRORSIZE];
258*00b67f09SDavid van Moolenbroek #endif
259*00b67f09SDavid van Moolenbroek isc_result_t result;
260*00b67f09SDavid van Moolenbroek
261*00b67f09SDavid van Moolenbroek result = isc_net_probeipv6();
262*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
263*00b67f09SDavid van Moolenbroek ipv6only_result = result;
264*00b67f09SDavid van Moolenbroek return;
265*00b67f09SDavid van Moolenbroek }
266*00b67f09SDavid van Moolenbroek
267*00b67f09SDavid van Moolenbroek #ifndef IPV6_V6ONLY
268*00b67f09SDavid van Moolenbroek ipv6only_result = ISC_R_NOTFOUND;
269*00b67f09SDavid van Moolenbroek return;
270*00b67f09SDavid van Moolenbroek #else
271*00b67f09SDavid van Moolenbroek /* check for TCP sockets */
272*00b67f09SDavid van Moolenbroek s = socket(PF_INET6, SOCK_STREAM, 0);
273*00b67f09SDavid van Moolenbroek if (s == -1) {
274*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
275*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__,
276*00b67f09SDavid van Moolenbroek "socket() %s: %s",
277*00b67f09SDavid van Moolenbroek isc_msgcat_get(isc_msgcat,
278*00b67f09SDavid van Moolenbroek ISC_MSGSET_GENERAL,
279*00b67f09SDavid van Moolenbroek ISC_MSG_FAILED,
280*00b67f09SDavid van Moolenbroek "failed"),
281*00b67f09SDavid van Moolenbroek strbuf);
282*00b67f09SDavid van Moolenbroek ipv6only_result = ISC_R_UNEXPECTED;
283*00b67f09SDavid van Moolenbroek return;
284*00b67f09SDavid van Moolenbroek }
285*00b67f09SDavid van Moolenbroek
286*00b67f09SDavid van Moolenbroek on = 1;
287*00b67f09SDavid van Moolenbroek if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
288*00b67f09SDavid van Moolenbroek ipv6only_result = ISC_R_NOTFOUND;
289*00b67f09SDavid van Moolenbroek goto close;
290*00b67f09SDavid van Moolenbroek }
291*00b67f09SDavid van Moolenbroek
292*00b67f09SDavid van Moolenbroek close(s);
293*00b67f09SDavid van Moolenbroek
294*00b67f09SDavid van Moolenbroek /* check for UDP sockets */
295*00b67f09SDavid van Moolenbroek s = socket(PF_INET6, SOCK_DGRAM, 0);
296*00b67f09SDavid van Moolenbroek if (s == -1) {
297*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
298*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__,
299*00b67f09SDavid van Moolenbroek "socket() %s: %s",
300*00b67f09SDavid van Moolenbroek isc_msgcat_get(isc_msgcat,
301*00b67f09SDavid van Moolenbroek ISC_MSGSET_GENERAL,
302*00b67f09SDavid van Moolenbroek ISC_MSG_FAILED,
303*00b67f09SDavid van Moolenbroek "failed"),
304*00b67f09SDavid van Moolenbroek strbuf);
305*00b67f09SDavid van Moolenbroek ipv6only_result = ISC_R_UNEXPECTED;
306*00b67f09SDavid van Moolenbroek return;
307*00b67f09SDavid van Moolenbroek }
308*00b67f09SDavid van Moolenbroek
309*00b67f09SDavid van Moolenbroek on = 1;
310*00b67f09SDavid van Moolenbroek if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
311*00b67f09SDavid van Moolenbroek ipv6only_result = ISC_R_NOTFOUND;
312*00b67f09SDavid van Moolenbroek goto close;
313*00b67f09SDavid van Moolenbroek }
314*00b67f09SDavid van Moolenbroek
315*00b67f09SDavid van Moolenbroek ipv6only_result = ISC_R_SUCCESS;
316*00b67f09SDavid van Moolenbroek
317*00b67f09SDavid van Moolenbroek close:
318*00b67f09SDavid van Moolenbroek close(s);
319*00b67f09SDavid van Moolenbroek return;
320*00b67f09SDavid van Moolenbroek #endif /* IPV6_V6ONLY */
321*00b67f09SDavid van Moolenbroek }
322*00b67f09SDavid van Moolenbroek
323*00b67f09SDavid van Moolenbroek static void
initialize_ipv6only(void)324*00b67f09SDavid van Moolenbroek initialize_ipv6only(void) {
325*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(isc_once_do(&once_ipv6only,
326*00b67f09SDavid van Moolenbroek try_ipv6only) == ISC_R_SUCCESS);
327*00b67f09SDavid van Moolenbroek }
328*00b67f09SDavid van Moolenbroek #endif /* WANT_IPV6 */
329*00b67f09SDavid van Moolenbroek
330*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
331*00b67f09SDavid van Moolenbroek #ifdef WANT_IPV6
332*00b67f09SDavid van Moolenbroek static void
try_ipv6pktinfo(void)333*00b67f09SDavid van Moolenbroek try_ipv6pktinfo(void) {
334*00b67f09SDavid van Moolenbroek int s, on;
335*00b67f09SDavid van Moolenbroek char strbuf[ISC_STRERRORSIZE];
336*00b67f09SDavid van Moolenbroek isc_result_t result;
337*00b67f09SDavid van Moolenbroek int optname;
338*00b67f09SDavid van Moolenbroek
339*00b67f09SDavid van Moolenbroek result = isc_net_probeipv6();
340*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
341*00b67f09SDavid van Moolenbroek ipv6pktinfo_result = result;
342*00b67f09SDavid van Moolenbroek return;
343*00b67f09SDavid van Moolenbroek }
344*00b67f09SDavid van Moolenbroek
345*00b67f09SDavid van Moolenbroek /* we only use this for UDP sockets */
346*00b67f09SDavid van Moolenbroek s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
347*00b67f09SDavid van Moolenbroek if (s == -1) {
348*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
349*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__,
350*00b67f09SDavid van Moolenbroek "socket() %s: %s",
351*00b67f09SDavid van Moolenbroek isc_msgcat_get(isc_msgcat,
352*00b67f09SDavid van Moolenbroek ISC_MSGSET_GENERAL,
353*00b67f09SDavid van Moolenbroek ISC_MSG_FAILED,
354*00b67f09SDavid van Moolenbroek "failed"),
355*00b67f09SDavid van Moolenbroek strbuf);
356*00b67f09SDavid van Moolenbroek ipv6pktinfo_result = ISC_R_UNEXPECTED;
357*00b67f09SDavid van Moolenbroek return;
358*00b67f09SDavid van Moolenbroek }
359*00b67f09SDavid van Moolenbroek
360*00b67f09SDavid van Moolenbroek #ifdef IPV6_RECVPKTINFO
361*00b67f09SDavid van Moolenbroek optname = IPV6_RECVPKTINFO;
362*00b67f09SDavid van Moolenbroek #else
363*00b67f09SDavid van Moolenbroek optname = IPV6_PKTINFO;
364*00b67f09SDavid van Moolenbroek #endif
365*00b67f09SDavid van Moolenbroek on = 1;
366*00b67f09SDavid van Moolenbroek if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
367*00b67f09SDavid van Moolenbroek ipv6pktinfo_result = ISC_R_NOTFOUND;
368*00b67f09SDavid van Moolenbroek goto close;
369*00b67f09SDavid van Moolenbroek }
370*00b67f09SDavid van Moolenbroek
371*00b67f09SDavid van Moolenbroek ipv6pktinfo_result = ISC_R_SUCCESS;
372*00b67f09SDavid van Moolenbroek
373*00b67f09SDavid van Moolenbroek close:
374*00b67f09SDavid van Moolenbroek close(s);
375*00b67f09SDavid van Moolenbroek return;
376*00b67f09SDavid van Moolenbroek }
377*00b67f09SDavid van Moolenbroek
378*00b67f09SDavid van Moolenbroek static void
initialize_ipv6pktinfo(void)379*00b67f09SDavid van Moolenbroek initialize_ipv6pktinfo(void) {
380*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
381*00b67f09SDavid van Moolenbroek try_ipv6pktinfo) == ISC_R_SUCCESS);
382*00b67f09SDavid van Moolenbroek }
383*00b67f09SDavid van Moolenbroek #endif /* WANT_IPV6 */
384*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
385*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_HAVEIPV6 */
386*00b67f09SDavid van Moolenbroek
387*00b67f09SDavid van Moolenbroek isc_result_t
isc_net_probe_ipv6only(void)388*00b67f09SDavid van Moolenbroek isc_net_probe_ipv6only(void) {
389*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVEIPV6
390*00b67f09SDavid van Moolenbroek #ifdef WANT_IPV6
391*00b67f09SDavid van Moolenbroek initialize_ipv6only();
392*00b67f09SDavid van Moolenbroek #else
393*00b67f09SDavid van Moolenbroek ipv6only_result = ISC_R_NOTFOUND;
394*00b67f09SDavid van Moolenbroek #endif
395*00b67f09SDavid van Moolenbroek #endif
396*00b67f09SDavid van Moolenbroek return (ipv6only_result);
397*00b67f09SDavid van Moolenbroek }
398*00b67f09SDavid van Moolenbroek
399*00b67f09SDavid van Moolenbroek isc_result_t
isc_net_probe_ipv6pktinfo(void)400*00b67f09SDavid van Moolenbroek isc_net_probe_ipv6pktinfo(void) {
401*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVEIPV6
402*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
403*00b67f09SDavid van Moolenbroek #ifdef WANT_IPV6
404*00b67f09SDavid van Moolenbroek initialize_ipv6pktinfo();
405*00b67f09SDavid van Moolenbroek #else
406*00b67f09SDavid van Moolenbroek ipv6pktinfo_result = ISC_R_NOTFOUND;
407*00b67f09SDavid van Moolenbroek #endif
408*00b67f09SDavid van Moolenbroek #endif
409*00b67f09SDavid van Moolenbroek #endif
410*00b67f09SDavid van Moolenbroek return (ipv6pktinfo_result);
411*00b67f09SDavid van Moolenbroek }
412*00b67f09SDavid van Moolenbroek
413*00b67f09SDavid van Moolenbroek static inline ISC_SOCKADDR_LEN_T
cmsg_len(ISC_SOCKADDR_LEN_T len)414*00b67f09SDavid van Moolenbroek cmsg_len(ISC_SOCKADDR_LEN_T len) {
415*00b67f09SDavid van Moolenbroek #ifdef CMSG_LEN
416*00b67f09SDavid van Moolenbroek return (CMSG_LEN(len));
417*00b67f09SDavid van Moolenbroek #else
418*00b67f09SDavid van Moolenbroek ISC_SOCKADDR_LEN_T hdrlen;
419*00b67f09SDavid van Moolenbroek
420*00b67f09SDavid van Moolenbroek /*
421*00b67f09SDavid van Moolenbroek * Cast NULL so that any pointer arithmetic performed by CMSG_DATA
422*00b67f09SDavid van Moolenbroek * is correct.
423*00b67f09SDavid van Moolenbroek */
424*00b67f09SDavid van Moolenbroek hdrlen = (ISC_SOCKADDR_LEN_T)CMSG_DATA(((struct cmsghdr *)NULL));
425*00b67f09SDavid van Moolenbroek return (hdrlen + len);
426*00b67f09SDavid van Moolenbroek #endif
427*00b67f09SDavid van Moolenbroek }
428*00b67f09SDavid van Moolenbroek
429*00b67f09SDavid van Moolenbroek static inline ISC_SOCKADDR_LEN_T
cmsg_space(ISC_SOCKADDR_LEN_T len)430*00b67f09SDavid van Moolenbroek cmsg_space(ISC_SOCKADDR_LEN_T len) {
431*00b67f09SDavid van Moolenbroek #ifdef CMSG_SPACE
432*00b67f09SDavid van Moolenbroek return (CMSG_SPACE(len));
433*00b67f09SDavid van Moolenbroek #else
434*00b67f09SDavid van Moolenbroek struct msghdr msg;
435*00b67f09SDavid van Moolenbroek struct cmsghdr *cmsgp;
436*00b67f09SDavid van Moolenbroek /*
437*00b67f09SDavid van Moolenbroek * XXX: The buffer length is an ad-hoc value, but should be enough
438*00b67f09SDavid van Moolenbroek * in a practical sense.
439*00b67f09SDavid van Moolenbroek */
440*00b67f09SDavid van Moolenbroek char dummybuf[sizeof(struct cmsghdr) + 1024];
441*00b67f09SDavid van Moolenbroek
442*00b67f09SDavid van Moolenbroek memset(&msg, 0, sizeof(msg));
443*00b67f09SDavid van Moolenbroek msg.msg_control = dummybuf;
444*00b67f09SDavid van Moolenbroek msg.msg_controllen = sizeof(dummybuf);
445*00b67f09SDavid van Moolenbroek
446*00b67f09SDavid van Moolenbroek cmsgp = (struct cmsghdr *)dummybuf;
447*00b67f09SDavid van Moolenbroek cmsgp->cmsg_len = cmsg_len(len);
448*00b67f09SDavid van Moolenbroek
449*00b67f09SDavid van Moolenbroek cmsgp = CMSG_NXTHDR(&msg, cmsgp);
450*00b67f09SDavid van Moolenbroek if (cmsgp != NULL)
451*00b67f09SDavid van Moolenbroek return ((char *)cmsgp - (char *)msg.msg_control);
452*00b67f09SDavid van Moolenbroek else
453*00b67f09SDavid van Moolenbroek return (0);
454*00b67f09SDavid van Moolenbroek #endif
455*00b67f09SDavid van Moolenbroek }
456*00b67f09SDavid van Moolenbroek
457*00b67f09SDavid van Moolenbroek #ifdef ISC_NET_BSD44MSGHDR
458*00b67f09SDavid van Moolenbroek /*
459*00b67f09SDavid van Moolenbroek * Make a fd non-blocking.
460*00b67f09SDavid van Moolenbroek */
461*00b67f09SDavid van Moolenbroek static isc_result_t
make_nonblock(int fd)462*00b67f09SDavid van Moolenbroek make_nonblock(int fd) {
463*00b67f09SDavid van Moolenbroek int ret;
464*00b67f09SDavid van Moolenbroek int flags;
465*00b67f09SDavid van Moolenbroek char strbuf[ISC_STRERRORSIZE];
466*00b67f09SDavid van Moolenbroek #ifdef USE_FIONBIO_IOCTL
467*00b67f09SDavid van Moolenbroek int on = 1;
468*00b67f09SDavid van Moolenbroek
469*00b67f09SDavid van Moolenbroek ret = ioctl(fd, FIONBIO, (char *)&on);
470*00b67f09SDavid van Moolenbroek #else
471*00b67f09SDavid van Moolenbroek flags = fcntl(fd, F_GETFL, 0);
472*00b67f09SDavid van Moolenbroek flags |= PORT_NONBLOCK;
473*00b67f09SDavid van Moolenbroek ret = fcntl(fd, F_SETFL, flags);
474*00b67f09SDavid van Moolenbroek #endif
475*00b67f09SDavid van Moolenbroek
476*00b67f09SDavid van Moolenbroek if (ret == -1) {
477*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
478*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__,
479*00b67f09SDavid van Moolenbroek #ifdef USE_FIONBIO_IOCTL
480*00b67f09SDavid van Moolenbroek "ioctl(%d, FIONBIO, &on): %s", fd,
481*00b67f09SDavid van Moolenbroek #else
482*00b67f09SDavid van Moolenbroek "fcntl(%d, F_SETFL, %d): %s", fd, flags,
483*00b67f09SDavid van Moolenbroek #endif
484*00b67f09SDavid van Moolenbroek strbuf);
485*00b67f09SDavid van Moolenbroek
486*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
487*00b67f09SDavid van Moolenbroek }
488*00b67f09SDavid van Moolenbroek
489*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
490*00b67f09SDavid van Moolenbroek }
491*00b67f09SDavid van Moolenbroek
492*00b67f09SDavid van Moolenbroek static isc_boolean_t
cmsgsend(int s,int level,int type,struct addrinfo * res)493*00b67f09SDavid van Moolenbroek cmsgsend(int s, int level, int type, struct addrinfo *res) {
494*00b67f09SDavid van Moolenbroek char strbuf[ISC_STRERRORSIZE];
495*00b67f09SDavid van Moolenbroek struct sockaddr_storage ss;
496*00b67f09SDavid van Moolenbroek ISC_SOCKADDR_LEN_T len = sizeof(ss);
497*00b67f09SDavid van Moolenbroek struct msghdr msg;
498*00b67f09SDavid van Moolenbroek union {
499*00b67f09SDavid van Moolenbroek struct cmsghdr h;
500*00b67f09SDavid van Moolenbroek unsigned char b[256];
501*00b67f09SDavid van Moolenbroek } control;
502*00b67f09SDavid van Moolenbroek struct cmsghdr *cmsgp;
503*00b67f09SDavid van Moolenbroek int dscp = 46;
504*00b67f09SDavid van Moolenbroek struct iovec iovec;
505*00b67f09SDavid van Moolenbroek char buf[1] = { 0 };
506*00b67f09SDavid van Moolenbroek isc_result_t result;
507*00b67f09SDavid van Moolenbroek
508*00b67f09SDavid van Moolenbroek if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
509*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
510*00b67f09SDavid van Moolenbroek isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
511*00b67f09SDavid van Moolenbroek ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
512*00b67f09SDavid van Moolenbroek "bind: %s", strbuf);
513*00b67f09SDavid van Moolenbroek return (ISC_FALSE);
514*00b67f09SDavid van Moolenbroek }
515*00b67f09SDavid van Moolenbroek
516*00b67f09SDavid van Moolenbroek if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
517*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
518*00b67f09SDavid van Moolenbroek isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
519*00b67f09SDavid van Moolenbroek ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
520*00b67f09SDavid van Moolenbroek "getsockname: %s", strbuf);
521*00b67f09SDavid van Moolenbroek return (ISC_FALSE);
522*00b67f09SDavid van Moolenbroek }
523*00b67f09SDavid van Moolenbroek
524*00b67f09SDavid van Moolenbroek memset(&control, 0, sizeof(control));
525*00b67f09SDavid van Moolenbroek
526*00b67f09SDavid van Moolenbroek iovec.iov_base = buf;
527*00b67f09SDavid van Moolenbroek iovec.iov_len = sizeof(buf);
528*00b67f09SDavid van Moolenbroek
529*00b67f09SDavid van Moolenbroek memset(&msg, 0, sizeof(msg));
530*00b67f09SDavid van Moolenbroek msg.msg_name = (struct sockaddr *)&ss;
531*00b67f09SDavid van Moolenbroek msg.msg_namelen = len;
532*00b67f09SDavid van Moolenbroek msg.msg_iov = &iovec;
533*00b67f09SDavid van Moolenbroek msg.msg_iovlen = 1;
534*00b67f09SDavid van Moolenbroek msg.msg_control = (void*)&control;
535*00b67f09SDavid van Moolenbroek msg.msg_controllen = cmsg_space(sizeof(int));
536*00b67f09SDavid van Moolenbroek msg.msg_flags = 0;
537*00b67f09SDavid van Moolenbroek
538*00b67f09SDavid van Moolenbroek cmsgp = msg.msg_control;
539*00b67f09SDavid van Moolenbroek cmsgp->cmsg_level = level;
540*00b67f09SDavid van Moolenbroek cmsgp->cmsg_type = type;
541*00b67f09SDavid van Moolenbroek
542*00b67f09SDavid van Moolenbroek switch (cmsgp->cmsg_type) {
543*00b67f09SDavid van Moolenbroek #ifdef IP_TOS
544*00b67f09SDavid van Moolenbroek case IP_TOS:
545*00b67f09SDavid van Moolenbroek cmsgp->cmsg_len = cmsg_len(sizeof(char));
546*00b67f09SDavid van Moolenbroek *(unsigned char*)CMSG_DATA(cmsgp) = dscp;
547*00b67f09SDavid van Moolenbroek break;
548*00b67f09SDavid van Moolenbroek #endif
549*00b67f09SDavid van Moolenbroek #ifdef IPV6_TCLASS
550*00b67f09SDavid van Moolenbroek case IPV6_TCLASS:
551*00b67f09SDavid van Moolenbroek cmsgp->cmsg_len = cmsg_len(sizeof(dscp));
552*00b67f09SDavid van Moolenbroek memmove(CMSG_DATA(cmsgp), &dscp, sizeof(dscp));
553*00b67f09SDavid van Moolenbroek break;
554*00b67f09SDavid van Moolenbroek #endif
555*00b67f09SDavid van Moolenbroek default:
556*00b67f09SDavid van Moolenbroek INSIST(0);
557*00b67f09SDavid van Moolenbroek }
558*00b67f09SDavid van Moolenbroek
559*00b67f09SDavid van Moolenbroek if (sendmsg(s, &msg, 0) < 0) {
560*00b67f09SDavid van Moolenbroek int debug = ISC_LOG_DEBUG(10);
561*00b67f09SDavid van Moolenbroek switch (errno) {
562*00b67f09SDavid van Moolenbroek #ifdef ENOPROTOOPT
563*00b67f09SDavid van Moolenbroek case ENOPROTOOPT:
564*00b67f09SDavid van Moolenbroek #endif
565*00b67f09SDavid van Moolenbroek #ifdef EOPNOTSUPP
566*00b67f09SDavid van Moolenbroek case EOPNOTSUPP:
567*00b67f09SDavid van Moolenbroek #endif
568*00b67f09SDavid van Moolenbroek case EINVAL:
569*00b67f09SDavid van Moolenbroek break;
570*00b67f09SDavid van Moolenbroek default:
571*00b67f09SDavid van Moolenbroek debug = ISC_LOG_NOTICE;
572*00b67f09SDavid van Moolenbroek }
573*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
574*00b67f09SDavid van Moolenbroek if (debug != ISC_LOG_NOTICE) {
575*00b67f09SDavid van Moolenbroek isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
576*00b67f09SDavid van Moolenbroek ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
577*00b67f09SDavid van Moolenbroek "sendmsg: %s", strbuf);
578*00b67f09SDavid van Moolenbroek } else {
579*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__,
580*00b67f09SDavid van Moolenbroek "sendmsg() %s: %s",
581*00b67f09SDavid van Moolenbroek isc_msgcat_get(isc_msgcat,
582*00b67f09SDavid van Moolenbroek ISC_MSGSET_GENERAL,
583*00b67f09SDavid van Moolenbroek ISC_MSG_FAILED,
584*00b67f09SDavid van Moolenbroek "failed"),
585*00b67f09SDavid van Moolenbroek strbuf);
586*00b67f09SDavid van Moolenbroek }
587*00b67f09SDavid van Moolenbroek return (ISC_FALSE);
588*00b67f09SDavid van Moolenbroek }
589*00b67f09SDavid van Moolenbroek
590*00b67f09SDavid van Moolenbroek /*
591*00b67f09SDavid van Moolenbroek * Make sure the message actually got sent.
592*00b67f09SDavid van Moolenbroek */
593*00b67f09SDavid van Moolenbroek result = make_nonblock(s);
594*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(result == ISC_R_SUCCESS);
595*00b67f09SDavid van Moolenbroek
596*00b67f09SDavid van Moolenbroek iovec.iov_base = buf;
597*00b67f09SDavid van Moolenbroek iovec.iov_len = sizeof(buf);
598*00b67f09SDavid van Moolenbroek
599*00b67f09SDavid van Moolenbroek memset(&msg, 0, sizeof(msg));
600*00b67f09SDavid van Moolenbroek msg.msg_name = (struct sockaddr *)&ss;
601*00b67f09SDavid van Moolenbroek msg.msg_namelen = sizeof(ss);
602*00b67f09SDavid van Moolenbroek msg.msg_iov = &iovec;
603*00b67f09SDavid van Moolenbroek msg.msg_iovlen = 1;
604*00b67f09SDavid van Moolenbroek msg.msg_control = NULL;
605*00b67f09SDavid van Moolenbroek msg.msg_controllen = 0;
606*00b67f09SDavid van Moolenbroek msg.msg_flags = 0;
607*00b67f09SDavid van Moolenbroek
608*00b67f09SDavid van Moolenbroek if (recvmsg(s, &msg, 0) < 0)
609*00b67f09SDavid van Moolenbroek return (ISC_FALSE);
610*00b67f09SDavid van Moolenbroek
611*00b67f09SDavid van Moolenbroek return (ISC_TRUE);
612*00b67f09SDavid van Moolenbroek }
613*00b67f09SDavid van Moolenbroek #endif
614*00b67f09SDavid van Moolenbroek
615*00b67f09SDavid van Moolenbroek static void
try_dscp_v4(void)616*00b67f09SDavid van Moolenbroek try_dscp_v4(void) {
617*00b67f09SDavid van Moolenbroek #ifdef IP_TOS
618*00b67f09SDavid van Moolenbroek char strbuf[ISC_STRERRORSIZE];
619*00b67f09SDavid van Moolenbroek struct addrinfo hints, *res0;
620*00b67f09SDavid van Moolenbroek int s, dscp = 0, n;
621*00b67f09SDavid van Moolenbroek #ifdef IP_RECVTOS
622*00b67f09SDavid van Moolenbroek int on = 1;
623*00b67f09SDavid van Moolenbroek #endif /* IP_RECVTOS */
624*00b67f09SDavid van Moolenbroek
625*00b67f09SDavid van Moolenbroek memset(&hints, 0, sizeof(hints));
626*00b67f09SDavid van Moolenbroek hints.ai_family = AF_INET;
627*00b67f09SDavid van Moolenbroek hints.ai_socktype = SOCK_DGRAM;
628*00b67f09SDavid van Moolenbroek hints.ai_protocol = IPPROTO_UDP;
629*00b67f09SDavid van Moolenbroek #ifdef AI_NUMERICHOST
630*00b67f09SDavid van Moolenbroek hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
631*00b67f09SDavid van Moolenbroek #else
632*00b67f09SDavid van Moolenbroek hints.ai_flags = AI_PASSIVE;
633*00b67f09SDavid van Moolenbroek #endif
634*00b67f09SDavid van Moolenbroek
635*00b67f09SDavid van Moolenbroek n = getaddrinfo("127.0.0.1", NULL, &hints, &res0);
636*00b67f09SDavid van Moolenbroek if (n != 0 || res0 == NULL) {
637*00b67f09SDavid van Moolenbroek isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
638*00b67f09SDavid van Moolenbroek ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
639*00b67f09SDavid van Moolenbroek "getaddrinfo(127.0.0.1): %s", gai_strerror(n));
640*00b67f09SDavid van Moolenbroek return;
641*00b67f09SDavid van Moolenbroek }
642*00b67f09SDavid van Moolenbroek
643*00b67f09SDavid van Moolenbroek s = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol);
644*00b67f09SDavid van Moolenbroek
645*00b67f09SDavid van Moolenbroek if (s == -1) {
646*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
647*00b67f09SDavid van Moolenbroek isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
648*00b67f09SDavid van Moolenbroek ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
649*00b67f09SDavid van Moolenbroek "socket: %s", strbuf);
650*00b67f09SDavid van Moolenbroek freeaddrinfo(res0);
651*00b67f09SDavid van Moolenbroek return;
652*00b67f09SDavid van Moolenbroek }
653*00b67f09SDavid van Moolenbroek
654*00b67f09SDavid van Moolenbroek if (setsockopt(s, IPPROTO_IP, IP_TOS, &dscp, sizeof(dscp)) == 0)
655*00b67f09SDavid van Moolenbroek dscp_result |= ISC_NET_DSCPSETV4;
656*00b67f09SDavid van Moolenbroek
657*00b67f09SDavid van Moolenbroek #ifdef IP_RECVTOS
658*00b67f09SDavid van Moolenbroek on = 1;
659*00b67f09SDavid van Moolenbroek if (setsockopt(s, IPPROTO_IP, IP_RECVTOS, &on, sizeof(on)) == 0)
660*00b67f09SDavid van Moolenbroek dscp_result |= ISC_NET_DSCPRECVV4;
661*00b67f09SDavid van Moolenbroek #endif /* IP_RECVTOS */
662*00b67f09SDavid van Moolenbroek
663*00b67f09SDavid van Moolenbroek #ifdef ISC_NET_BSD44MSGHDR
664*00b67f09SDavid van Moolenbroek
665*00b67f09SDavid van Moolenbroek #ifndef ISC_CMSG_IP_TOS
666*00b67f09SDavid van Moolenbroek #ifdef __APPLE__
667*00b67f09SDavid van Moolenbroek #define ISC_CMSG_IP_TOS 0 /* As of 10.8.2. */
668*00b67f09SDavid van Moolenbroek #else /* ! __APPLE__ */
669*00b67f09SDavid van Moolenbroek #define ISC_CMSG_IP_TOS 1
670*00b67f09SDavid van Moolenbroek #endif /* ! __APPLE__ */
671*00b67f09SDavid van Moolenbroek #endif /* ! ISC_CMSG_IP_TOS */
672*00b67f09SDavid van Moolenbroek
673*00b67f09SDavid van Moolenbroek #if ISC_CMSG_IP_TOS
674*00b67f09SDavid van Moolenbroek if (cmsgsend(s, IPPROTO_IP, IP_TOS, res0))
675*00b67f09SDavid van Moolenbroek dscp_result |= ISC_NET_DSCPPKTV4;
676*00b67f09SDavid van Moolenbroek #endif /* ISC_CMSG_IP_TOS */
677*00b67f09SDavid van Moolenbroek
678*00b67f09SDavid van Moolenbroek #endif /* ISC_NET_BSD44MSGHDR */
679*00b67f09SDavid van Moolenbroek
680*00b67f09SDavid van Moolenbroek freeaddrinfo(res0);
681*00b67f09SDavid van Moolenbroek close(s);
682*00b67f09SDavid van Moolenbroek
683*00b67f09SDavid van Moolenbroek #endif /* IP_TOS */
684*00b67f09SDavid van Moolenbroek }
685*00b67f09SDavid van Moolenbroek
686*00b67f09SDavid van Moolenbroek static void
try_dscp_v6(void)687*00b67f09SDavid van Moolenbroek try_dscp_v6(void) {
688*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVEIPV6
689*00b67f09SDavid van Moolenbroek #ifdef WANT_IPV6
690*00b67f09SDavid van Moolenbroek #ifdef IPV6_TCLASS
691*00b67f09SDavid van Moolenbroek char strbuf[ISC_STRERRORSIZE];
692*00b67f09SDavid van Moolenbroek struct addrinfo hints, *res0;
693*00b67f09SDavid van Moolenbroek int s, dscp = 0, n;
694*00b67f09SDavid van Moolenbroek #if defined(IPV6_RECVTCLASS)
695*00b67f09SDavid van Moolenbroek int on = 1;
696*00b67f09SDavid van Moolenbroek #endif /* IPV6_RECVTCLASS */
697*00b67f09SDavid van Moolenbroek
698*00b67f09SDavid van Moolenbroek memset(&hints, 0, sizeof(hints));
699*00b67f09SDavid van Moolenbroek hints.ai_family = AF_INET6;
700*00b67f09SDavid van Moolenbroek hints.ai_socktype = SOCK_DGRAM;
701*00b67f09SDavid van Moolenbroek hints.ai_protocol = IPPROTO_UDP;
702*00b67f09SDavid van Moolenbroek #ifdef AI_NUMERICHOST
703*00b67f09SDavid van Moolenbroek hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
704*00b67f09SDavid van Moolenbroek #else
705*00b67f09SDavid van Moolenbroek hints.ai_flags = AI_PASSIVE;
706*00b67f09SDavid van Moolenbroek #endif
707*00b67f09SDavid van Moolenbroek
708*00b67f09SDavid van Moolenbroek n = getaddrinfo("::1", NULL, &hints, &res0);
709*00b67f09SDavid van Moolenbroek if (n != 0 || res0 == NULL) {
710*00b67f09SDavid van Moolenbroek isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
711*00b67f09SDavid van Moolenbroek ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
712*00b67f09SDavid van Moolenbroek "getaddrinfo(::1): %s", gai_strerror(n));
713*00b67f09SDavid van Moolenbroek return;
714*00b67f09SDavid van Moolenbroek }
715*00b67f09SDavid van Moolenbroek
716*00b67f09SDavid van Moolenbroek s = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol);
717*00b67f09SDavid van Moolenbroek if (s == -1) {
718*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
719*00b67f09SDavid van Moolenbroek isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
720*00b67f09SDavid van Moolenbroek ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
721*00b67f09SDavid van Moolenbroek "socket: %s", strbuf);
722*00b67f09SDavid van Moolenbroek freeaddrinfo(res0);
723*00b67f09SDavid van Moolenbroek return;
724*00b67f09SDavid van Moolenbroek }
725*00b67f09SDavid van Moolenbroek if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &dscp, sizeof(dscp)) == 0)
726*00b67f09SDavid van Moolenbroek dscp_result |= ISC_NET_DSCPSETV6;
727*00b67f09SDavid van Moolenbroek
728*00b67f09SDavid van Moolenbroek #ifdef IPV6_RECVTCLASS
729*00b67f09SDavid van Moolenbroek on = 1;
730*00b67f09SDavid van Moolenbroek if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVTCLASS, &on, sizeof(on)) == 0)
731*00b67f09SDavid van Moolenbroek dscp_result |= ISC_NET_DSCPRECVV6;
732*00b67f09SDavid van Moolenbroek #endif /* IPV6_RECVTCLASS */
733*00b67f09SDavid van Moolenbroek
734*00b67f09SDavid van Moolenbroek #ifdef ISC_NET_BSD44MSGHDR
735*00b67f09SDavid van Moolenbroek if (cmsgsend(s, IPPROTO_IPV6, IPV6_TCLASS, res0))
736*00b67f09SDavid van Moolenbroek dscp_result |= ISC_NET_DSCPPKTV6;
737*00b67f09SDavid van Moolenbroek #endif /* ISC_NET_BSD44MSGHDR */
738*00b67f09SDavid van Moolenbroek
739*00b67f09SDavid van Moolenbroek freeaddrinfo(res0);
740*00b67f09SDavid van Moolenbroek close(s);
741*00b67f09SDavid van Moolenbroek
742*00b67f09SDavid van Moolenbroek #endif /* IPV6_TCLASS */
743*00b67f09SDavid van Moolenbroek #endif /* WANT_IPV6 */
744*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_HAVEIPV6 */
745*00b67f09SDavid van Moolenbroek }
746*00b67f09SDavid van Moolenbroek
747*00b67f09SDavid van Moolenbroek static void
try_dscp(void)748*00b67f09SDavid van Moolenbroek try_dscp(void) {
749*00b67f09SDavid van Moolenbroek try_dscp_v4();
750*00b67f09SDavid van Moolenbroek try_dscp_v6();
751*00b67f09SDavid van Moolenbroek }
752*00b67f09SDavid van Moolenbroek
753*00b67f09SDavid van Moolenbroek static void
initialize_dscp(void)754*00b67f09SDavid van Moolenbroek initialize_dscp(void) {
755*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(isc_once_do(&once_dscp, try_dscp) == ISC_R_SUCCESS);
756*00b67f09SDavid van Moolenbroek }
757*00b67f09SDavid van Moolenbroek
758*00b67f09SDavid van Moolenbroek unsigned int
isc_net_probedscp(void)759*00b67f09SDavid van Moolenbroek isc_net_probedscp(void) {
760*00b67f09SDavid van Moolenbroek initialize_dscp();
761*00b67f09SDavid van Moolenbroek return (dscp_result);
762*00b67f09SDavid van Moolenbroek }
763*00b67f09SDavid van Moolenbroek
764*00b67f09SDavid van Moolenbroek #if defined(USE_SYSCTL_PORTRANGE)
765*00b67f09SDavid van Moolenbroek #if defined(HAVE_SYSCTLBYNAME)
766*00b67f09SDavid van Moolenbroek static isc_result_t
getudpportrange_sysctl(int af,in_port_t * low,in_port_t * high)767*00b67f09SDavid van Moolenbroek getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
768*00b67f09SDavid van Moolenbroek int port_low, port_high;
769*00b67f09SDavid van Moolenbroek size_t portlen;
770*00b67f09SDavid van Moolenbroek const char *sysctlname_lowport, *sysctlname_hiport;
771*00b67f09SDavid van Moolenbroek
772*00b67f09SDavid van Moolenbroek if (af == AF_INET) {
773*00b67f09SDavid van Moolenbroek sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW;
774*00b67f09SDavid van Moolenbroek sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH;
775*00b67f09SDavid van Moolenbroek } else {
776*00b67f09SDavid van Moolenbroek sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
777*00b67f09SDavid van Moolenbroek sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
778*00b67f09SDavid van Moolenbroek }
779*00b67f09SDavid van Moolenbroek portlen = sizeof(portlen);
780*00b67f09SDavid van Moolenbroek if (sysctlbyname(sysctlname_lowport, &port_low, &portlen,
781*00b67f09SDavid van Moolenbroek NULL, 0) < 0) {
782*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
783*00b67f09SDavid van Moolenbroek }
784*00b67f09SDavid van Moolenbroek portlen = sizeof(portlen);
785*00b67f09SDavid van Moolenbroek if (sysctlbyname(sysctlname_hiport, &port_high, &portlen,
786*00b67f09SDavid van Moolenbroek NULL, 0) < 0) {
787*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
788*00b67f09SDavid van Moolenbroek }
789*00b67f09SDavid van Moolenbroek if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
790*00b67f09SDavid van Moolenbroek return (ISC_R_RANGE);
791*00b67f09SDavid van Moolenbroek
792*00b67f09SDavid van Moolenbroek *low = (in_port_t)port_low;
793*00b67f09SDavid van Moolenbroek *high = (in_port_t)port_high;
794*00b67f09SDavid van Moolenbroek
795*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
796*00b67f09SDavid van Moolenbroek }
797*00b67f09SDavid van Moolenbroek #else /* !HAVE_SYSCTLBYNAME */
798*00b67f09SDavid van Moolenbroek static isc_result_t
getudpportrange_sysctl(int af,in_port_t * low,in_port_t * high)799*00b67f09SDavid van Moolenbroek getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
800*00b67f09SDavid van Moolenbroek int mib_lo4[4] = SYSCTL_V4PORTRANGE_LOW;
801*00b67f09SDavid van Moolenbroek int mib_hi4[4] = SYSCTL_V4PORTRANGE_HIGH;
802*00b67f09SDavid van Moolenbroek int mib_lo6[4] = SYSCTL_V6PORTRANGE_LOW;
803*00b67f09SDavid van Moolenbroek int mib_hi6[4] = SYSCTL_V6PORTRANGE_HIGH;
804*00b67f09SDavid van Moolenbroek int *mib_lo, *mib_hi, miblen;
805*00b67f09SDavid van Moolenbroek int port_low, port_high;
806*00b67f09SDavid van Moolenbroek size_t portlen;
807*00b67f09SDavid van Moolenbroek
808*00b67f09SDavid van Moolenbroek if (af == AF_INET) {
809*00b67f09SDavid van Moolenbroek mib_lo = mib_lo4;
810*00b67f09SDavid van Moolenbroek mib_hi = mib_hi4;
811*00b67f09SDavid van Moolenbroek miblen = sizeof(mib_lo4) / sizeof(mib_lo4[0]);
812*00b67f09SDavid van Moolenbroek } else {
813*00b67f09SDavid van Moolenbroek mib_lo = mib_lo6;
814*00b67f09SDavid van Moolenbroek mib_hi = mib_hi6;
815*00b67f09SDavid van Moolenbroek miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]);
816*00b67f09SDavid van Moolenbroek }
817*00b67f09SDavid van Moolenbroek
818*00b67f09SDavid van Moolenbroek portlen = sizeof(portlen);
819*00b67f09SDavid van Moolenbroek if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) {
820*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
821*00b67f09SDavid van Moolenbroek }
822*00b67f09SDavid van Moolenbroek
823*00b67f09SDavid van Moolenbroek portlen = sizeof(portlen);
824*00b67f09SDavid van Moolenbroek if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) {
825*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
826*00b67f09SDavid van Moolenbroek }
827*00b67f09SDavid van Moolenbroek
828*00b67f09SDavid van Moolenbroek if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
829*00b67f09SDavid van Moolenbroek return (ISC_R_RANGE);
830*00b67f09SDavid van Moolenbroek
831*00b67f09SDavid van Moolenbroek *low = (in_port_t) port_low;
832*00b67f09SDavid van Moolenbroek *high = (in_port_t) port_high;
833*00b67f09SDavid van Moolenbroek
834*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
835*00b67f09SDavid van Moolenbroek }
836*00b67f09SDavid van Moolenbroek #endif /* HAVE_SYSCTLBYNAME */
837*00b67f09SDavid van Moolenbroek #endif /* USE_SYSCTL_PORTRANGE */
838*00b67f09SDavid van Moolenbroek
839*00b67f09SDavid van Moolenbroek isc_result_t
isc_net_getudpportrange(int af,in_port_t * low,in_port_t * high)840*00b67f09SDavid van Moolenbroek isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
841*00b67f09SDavid van Moolenbroek int result = ISC_R_FAILURE;
842*00b67f09SDavid van Moolenbroek
843*00b67f09SDavid van Moolenbroek REQUIRE(low != NULL && high != NULL);
844*00b67f09SDavid van Moolenbroek
845*00b67f09SDavid van Moolenbroek #if defined(USE_SYSCTL_PORTRANGE)
846*00b67f09SDavid van Moolenbroek result = getudpportrange_sysctl(af, low, high);
847*00b67f09SDavid van Moolenbroek #else
848*00b67f09SDavid van Moolenbroek UNUSED(af);
849*00b67f09SDavid van Moolenbroek #endif
850*00b67f09SDavid van Moolenbroek
851*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
852*00b67f09SDavid van Moolenbroek *low = ISC_NET_PORTRANGELOW;
853*00b67f09SDavid van Moolenbroek *high = ISC_NET_PORTRANGEHIGH;
854*00b67f09SDavid van Moolenbroek }
855*00b67f09SDavid van Moolenbroek
856*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS); /* we currently never fail in this function */
857*00b67f09SDavid van Moolenbroek }
858*00b67f09SDavid van Moolenbroek
859*00b67f09SDavid van Moolenbroek void
isc_net_disableipv4(void)860*00b67f09SDavid van Moolenbroek isc_net_disableipv4(void) {
861*00b67f09SDavid van Moolenbroek initialize();
862*00b67f09SDavid van Moolenbroek if (ipv4_result == ISC_R_SUCCESS)
863*00b67f09SDavid van Moolenbroek ipv4_result = ISC_R_DISABLED;
864*00b67f09SDavid van Moolenbroek }
865*00b67f09SDavid van Moolenbroek
866*00b67f09SDavid van Moolenbroek void
isc_net_disableipv6(void)867*00b67f09SDavid van Moolenbroek isc_net_disableipv6(void) {
868*00b67f09SDavid van Moolenbroek initialize();
869*00b67f09SDavid van Moolenbroek if (ipv6_result == ISC_R_SUCCESS)
870*00b67f09SDavid van Moolenbroek ipv6_result = ISC_R_DISABLED;
871*00b67f09SDavid van Moolenbroek }
872*00b67f09SDavid van Moolenbroek
873*00b67f09SDavid van Moolenbroek void
isc_net_enableipv4(void)874*00b67f09SDavid van Moolenbroek isc_net_enableipv4(void) {
875*00b67f09SDavid van Moolenbroek initialize();
876*00b67f09SDavid van Moolenbroek if (ipv4_result == ISC_R_DISABLED)
877*00b67f09SDavid van Moolenbroek ipv4_result = ISC_R_SUCCESS;
878*00b67f09SDavid van Moolenbroek }
879*00b67f09SDavid van Moolenbroek
880*00b67f09SDavid van Moolenbroek void
isc_net_enableipv6(void)881*00b67f09SDavid van Moolenbroek isc_net_enableipv6(void) {
882*00b67f09SDavid van Moolenbroek initialize();
883*00b67f09SDavid van Moolenbroek if (ipv6_result == ISC_R_DISABLED)
884*00b67f09SDavid van Moolenbroek ipv6_result = ISC_R_SUCCESS;
885*00b67f09SDavid van Moolenbroek }
886