net.c revision 293423
1178825Sdfr/* 2233294Sstas * Copyright (C) 2004, 2005, 2007-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 3233294Sstas * Copyright (C) 1999-2003 Internet Software Consortium. 4233294Sstas * 5178825Sdfr * Permission to use, copy, modify, and/or distribute this software for any 6233294Sstas * purpose with or without fee is hereby granted, provided that the above 7233294Sstas * copyright notice and this permission notice appear in all copies. 8233294Sstas * 9178825Sdfr * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10233294Sstas * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11233294Sstas * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12178825Sdfr * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13233294Sstas * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14233294Sstas * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15233294Sstas * PERFORMANCE OF THIS SOFTWARE. 16178825Sdfr */ 17233294Sstas 18233294Sstas/* $Id$ */ 19233294Sstas 20178825Sdfr#include <config.h> 21233294Sstas 22233294Sstas#include <errno.h> 23233294Sstas#include <unistd.h> 24233294Sstas 25233294Sstas#include <isc/log.h> 26233294Sstas#include <isc/msgs.h> 27233294Sstas#include <isc/net.h> 28233294Sstas#include <isc/once.h> 29233294Sstas#include <isc/strerror.h> 30233294Sstas#include <isc/string.h> 31233294Sstas#include <isc/util.h> 32178825Sdfr 33178825Sdfr/*% 34233294Sstas * Definitions about UDP port range specification. This is a total mess of 35178825Sdfr * portability variants: some use sysctl (but the sysctl names vary), some use 36178825Sdfr * system-specific interfaces, some have the same interface for IPv4 and IPv6, 37178825Sdfr * some separate them, etc... 38178825Sdfr */ 39178825Sdfr 40178825Sdfr/*% 41178825Sdfr * The last resort defaults: use all non well known port space 42178825Sdfr */ 43178825Sdfr#ifndef ISC_NET_PORTRANGELOW 44178825Sdfr#define ISC_NET_PORTRANGELOW 1024 45178825Sdfr#endif /* ISC_NET_PORTRANGELOW */ 46178825Sdfr#ifndef ISC_NET_PORTRANGEHIGH 47178825Sdfr#define ISC_NET_PORTRANGEHIGH 65535 48178825Sdfr#endif /* ISC_NET_PORTRANGEHIGH */ 49233294Sstas 50178825Sdfr#if defined(ISC_PLATFORM_NEEDIN6ADDRANY) 51233294Sstasconst struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT; 52233294Sstas#endif 53178825Sdfr 54178825Sdfr#if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK) 55233294Sstasconst struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT; 56233294Sstas#endif 57178825Sdfr 58233294Sstas 59178825Sdfrstatic isc_once_t once = ISC_ONCE_INIT; 60233294Sstasstatic isc_once_t once_ipv6only = ISC_ONCE_INIT; 61233294Sstasstatic isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT; 62233294Sstasstatic isc_result_t ipv4_result = ISC_R_NOTFOUND; 63233294Sstasstatic isc_result_t ipv6_result = ISC_R_NOTFOUND; 64178825Sdfrstatic isc_result_t ipv6only_result = ISC_R_NOTFOUND; 65233294Sstasstatic isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND; 66233294Sstas 67233294Sstasvoid InitSockets(void); 68178825Sdfr 69178825Sdfrstatic isc_result_t 70178825Sdfrtry_proto(int domain) { 71178825Sdfr SOCKET s; 72233294Sstas char strbuf[ISC_STRERRORSIZE]; 73233294Sstas int errval; 74233294Sstas 75233294Sstas s = socket(domain, SOCK_STREAM, IPPROTO_TCP); 76233294Sstas if (s == INVALID_SOCKET) { 77233294Sstas errval = WSAGetLastError(); 78233294Sstas switch (errval) { 79233294Sstas case WSAEAFNOSUPPORT: 80233294Sstas case WSAEPROTONOSUPPORT: 81233294Sstas case WSAEINVAL: 82233294Sstas return (ISC_R_NOTFOUND); 83233294Sstas default: 84233294Sstas isc__strerror(errval, strbuf, sizeof(strbuf)); 85233294Sstas UNEXPECTED_ERROR(__FILE__, __LINE__, 86233294Sstas "socket() %s: %s", 87233294Sstas isc_msgcat_get(isc_msgcat, 88178825Sdfr ISC_MSGSET_GENERAL, 89178825Sdfr ISC_MSG_FAILED, 90233294Sstas "failed"), 91178825Sdfr strbuf); 92178825Sdfr return (ISC_R_UNEXPECTED); 93178825Sdfr } 94178825Sdfr } 95178825Sdfr 96178825Sdfr closesocket(s); 97233294Sstas 98233294Sstas return (ISC_R_SUCCESS); 99233294Sstas} 100178825Sdfr 101178825Sdfrstatic void 102178825Sdfrinitialize_action(void) { 103178825Sdfr InitSockets(); 104178825Sdfr ipv4_result = try_proto(PF_INET); 105233294Sstas#ifdef ISC_PLATFORM_HAVEIPV6 106233294Sstas#ifdef WANT_IPV6 107178825Sdfr#ifdef ISC_PLATFORM_HAVEIN6PKTINFO 108178825Sdfr ipv6_result = try_proto(PF_INET6); 109178825Sdfr#endif 110178825Sdfr#endif 111178825Sdfr#endif 112178825Sdfr} 113178825Sdfr 114178825Sdfrstatic void 115178825Sdfrinitialize(void) { 116178825Sdfr RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 117178825Sdfr} 118178825Sdfr 119178825Sdfrisc_result_t 120178825Sdfrisc_net_probeipv4(void) { 121178825Sdfr initialize(); 122178825Sdfr return (ipv4_result); 123178825Sdfr} 124178825Sdfr 125178825Sdfrisc_result_t 126178825Sdfrisc_net_probeipv6(void) { 127178825Sdfr initialize(); 128178825Sdfr return (ipv6_result); 129178825Sdfr} 130178825Sdfr 131178825Sdfrisc_result_t 132233294Sstasisc_net_probeunix(void) { 133178825Sdfr return (ISC_R_NOTFOUND); 134178825Sdfr} 135178825Sdfr 136178825Sdfr#ifdef ISC_PLATFORM_HAVEIPV6 137178825Sdfr#ifdef WANT_IPV6 138178825Sdfrstatic void 139178825Sdfrtry_ipv6only(void) { 140178825Sdfr#ifdef IPV6_V6ONLY 141178825Sdfr SOCKET s; 142178825Sdfr int on; 143178825Sdfr char strbuf[ISC_STRERRORSIZE]; 144178825Sdfr#endif 145178825Sdfr isc_result_t result; 146178825Sdfr 147178825Sdfr result = isc_net_probeipv6(); 148178825Sdfr if (result != ISC_R_SUCCESS) { 149178825Sdfr ipv6only_result = result; 150178825Sdfr return; 151178825Sdfr } 152178825Sdfr 153178825Sdfr#ifndef IPV6_V6ONLY 154233294Sstas ipv6only_result = ISC_R_NOTFOUND; 155178825Sdfr return; 156178825Sdfr#else 157178825Sdfr /* check for TCP sockets */ 158 s = socket(PF_INET6, SOCK_STREAM, 0); 159 if (s == INVALID_SOCKET) { 160 isc__strerror(errno, strbuf, sizeof(strbuf)); 161 UNEXPECTED_ERROR(__FILE__, __LINE__, 162 "socket() %s: %s", 163 isc_msgcat_get(isc_msgcat, 164 ISC_MSGSET_GENERAL, 165 ISC_MSG_FAILED, 166 "failed"), 167 strbuf); 168 ipv6only_result = ISC_R_UNEXPECTED; 169 return; 170 } 171 172 on = 1; 173 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&on, 174 sizeof(on)) < 0) { 175 ipv6only_result = ISC_R_NOTFOUND; 176 goto close; 177 } 178 179 closesocket(s); 180 181 /* check for UDP sockets */ 182 s = socket(PF_INET6, SOCK_DGRAM, 0); 183 if (s == INVALID_SOCKET) { 184 isc__strerror(errno, strbuf, sizeof(strbuf)); 185 UNEXPECTED_ERROR(__FILE__, __LINE__, 186 "socket() %s: %s", 187 isc_msgcat_get(isc_msgcat, 188 ISC_MSGSET_GENERAL, 189 ISC_MSG_FAILED, 190 "failed"), 191 strbuf); 192 ipv6only_result = ISC_R_UNEXPECTED; 193 return; 194 } 195 196 on = 1; 197 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&on, 198 sizeof(on)) < 0) { 199 ipv6only_result = ISC_R_NOTFOUND; 200 goto close; 201 } 202 203 ipv6only_result = ISC_R_SUCCESS; 204 205close: 206 closesocket(s); 207 return; 208#endif /* IPV6_V6ONLY */ 209} 210 211static void 212initialize_ipv6only(void) { 213 RUNTIME_CHECK(isc_once_do(&once_ipv6only, 214 try_ipv6only) == ISC_R_SUCCESS); 215} 216 217static void 218try_ipv6pktinfo(void) { 219 SOCKET s; 220 int on; 221 char strbuf[ISC_STRERRORSIZE]; 222 isc_result_t result; 223 int optname; 224 225 result = isc_net_probeipv6(); 226 if (result != ISC_R_SUCCESS) { 227 ipv6pktinfo_result = result; 228 return; 229 } 230 231 /* we only use this for UDP sockets */ 232 s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); 233 if (s == INVALID_SOCKET) { 234 isc__strerror(errno, strbuf, sizeof(strbuf)); 235 UNEXPECTED_ERROR(__FILE__, __LINE__, 236 "socket() %s: %s", 237 isc_msgcat_get(isc_msgcat, 238 ISC_MSGSET_GENERAL, 239 ISC_MSG_FAILED, 240 "failed"), 241 strbuf); 242 ipv6pktinfo_result = ISC_R_UNEXPECTED; 243 return; 244 } 245 246#ifdef IPV6_RECVPKTINFO 247 optname = IPV6_RECVPKTINFO; 248#else 249 optname = IPV6_PKTINFO; 250#endif 251 on = 1; 252 if (setsockopt(s, IPPROTO_IPV6, optname, (const char *) &on, 253 sizeof(on)) < 0) { 254 ipv6pktinfo_result = ISC_R_NOTFOUND; 255 goto close; 256 } 257 258 ipv6pktinfo_result = ISC_R_SUCCESS; 259 260close: 261 closesocket(s); 262 return; 263} 264 265static void 266initialize_ipv6pktinfo(void) { 267 RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo, 268 try_ipv6pktinfo) == ISC_R_SUCCESS); 269} 270#endif /* WANT_IPV6 */ 271#endif /* ISC_PLATFORM_HAVEIPV6 */ 272 273isc_result_t 274isc_net_probe_ipv6only(void) { 275#ifdef ISC_PLATFORM_HAVEIPV6 276#ifdef WANT_IPV6 277 initialize_ipv6only(); 278#else 279 ipv6only_result = ISC_R_NOTFOUND; 280#endif 281#endif 282 return (ipv6only_result); 283} 284 285isc_result_t 286isc_net_probe_ipv6pktinfo(void) { 287#ifdef ISC_PLATFORM_HAVEIPV6 288#ifdef WANT_IPV6 289 initialize_ipv6pktinfo(); 290#else 291 ipv6pktinfo_result = ISC_R_NOTFOUND; 292#endif 293#endif 294 return (ipv6pktinfo_result); 295} 296 297isc_result_t 298isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) { 299 int result = ISC_R_FAILURE; 300 301 REQUIRE(low != NULL && high != NULL); 302 303 UNUSED(af); 304 305 if (result != ISC_R_SUCCESS) { 306 *low = ISC_NET_PORTRANGELOW; 307 *high = ISC_NET_PORTRANGEHIGH; 308 } 309 310 return (ISC_R_SUCCESS); /* we currently never fail in this function */ 311} 312 313void 314isc_net_disableipv4(void) { 315 initialize(); 316 if (ipv4_result == ISC_R_SUCCESS) 317 ipv4_result = ISC_R_DISABLED; 318} 319 320void 321isc_net_disableipv6(void) { 322 initialize(); 323 if (ipv6_result == ISC_R_SUCCESS) 324 ipv6_result = ISC_R_DISABLED; 325} 326 327void 328isc_net_enableipv4(void) { 329 initialize(); 330 if (ipv4_result == ISC_R_DISABLED) 331 ipv4_result = ISC_R_SUCCESS; 332} 333 334void 335isc_net_enableipv6(void) { 336 initialize(); 337 if (ipv6_result == ISC_R_DISABLED) 338 ipv6_result = ISC_R_SUCCESS; 339} 340