1*eabc0478Schristos /* $NetBSD: net.c,v 1.2 2024/08/18 20:47:16 christos Exp $ */ 2897be3a4Schristos 3897be3a4Schristos /* 4897be3a4Schristos * Copyright (C) 2004, 2005, 2007-2009, 2011, 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 <errno.h> 25897be3a4Schristos #include <unistd.h> 26897be3a4Schristos 27897be3a4Schristos #include <isc/log.h> 28897be3a4Schristos #include <isc/msgs.h> 29897be3a4Schristos #include <isc/net.h> 30897be3a4Schristos #include <isc/once.h> 31897be3a4Schristos #include <isc/strerror.h> 32897be3a4Schristos #include <isc/string.h> 33897be3a4Schristos #include <isc/util.h> 34897be3a4Schristos 35897be3a4Schristos /*% 36897be3a4Schristos * Definitions about UDP port range specification. This is a total mess of 37897be3a4Schristos * portability variants: some use sysctl (but the sysctl names vary), some use 38897be3a4Schristos * system-specific interfaces, some have the same interface for IPv4 and IPv6, 39897be3a4Schristos * some separate them, etc... 40897be3a4Schristos */ 41897be3a4Schristos 42897be3a4Schristos /*% 43897be3a4Schristos * The last resort defaults: use all non well known port space 44897be3a4Schristos */ 45897be3a4Schristos #ifndef ISC_NET_PORTRANGELOW 46897be3a4Schristos #define ISC_NET_PORTRANGELOW 1024 47897be3a4Schristos #endif /* ISC_NET_PORTRANGELOW */ 48897be3a4Schristos #ifndef ISC_NET_PORTRANGEHIGH 49897be3a4Schristos #define ISC_NET_PORTRANGEHIGH 65535 50897be3a4Schristos #endif /* ISC_NET_PORTRANGEHIGH */ 51897be3a4Schristos 52897be3a4Schristos #if defined(ISC_PLATFORM_NEEDIN6ADDRANY) 53897be3a4Schristos const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT; 54897be3a4Schristos #endif 55897be3a4Schristos 56897be3a4Schristos #if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK) 57897be3a4Schristos const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT; 58897be3a4Schristos #endif 59897be3a4Schristos 60897be3a4Schristos 61897be3a4Schristos static isc_once_t once = ISC_ONCE_INIT; 62897be3a4Schristos static isc_once_t once_ipv6only = ISC_ONCE_INIT; 63897be3a4Schristos static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT; 64897be3a4Schristos static isc_result_t ipv4_result = ISC_R_NOTFOUND; 65897be3a4Schristos static isc_result_t ipv6_result = ISC_R_NOTFOUND; 66897be3a4Schristos static isc_result_t ipv6only_result = ISC_R_NOTFOUND; 67897be3a4Schristos static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND; 68897be3a4Schristos 69897be3a4Schristos void InitSockets(void); 70897be3a4Schristos 71897be3a4Schristos static isc_result_t 72897be3a4Schristos try_proto(int domain) { 73897be3a4Schristos SOCKET s; 74897be3a4Schristos char strbuf[ISC_STRERRORSIZE]; 75897be3a4Schristos int errval; 76897be3a4Schristos 77897be3a4Schristos s = socket(domain, SOCK_STREAM, IPPROTO_TCP); 78897be3a4Schristos if (s == INVALID_SOCKET) { 79897be3a4Schristos errval = WSAGetLastError(); 80897be3a4Schristos switch (errval) { 81897be3a4Schristos case WSAEAFNOSUPPORT: 82897be3a4Schristos case WSAEPROTONOSUPPORT: 83897be3a4Schristos case WSAEINVAL: 84897be3a4Schristos return (ISC_R_NOTFOUND); 85897be3a4Schristos default: 86897be3a4Schristos isc__strerror(errval, strbuf, sizeof(strbuf)); 87897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, 88897be3a4Schristos "socket() %s: %s", 89897be3a4Schristos isc_msgcat_get(isc_msgcat, 90897be3a4Schristos ISC_MSGSET_GENERAL, 91897be3a4Schristos ISC_MSG_FAILED, 92897be3a4Schristos "failed"), 93897be3a4Schristos strbuf); 94897be3a4Schristos return (ISC_R_UNEXPECTED); 95897be3a4Schristos } 96897be3a4Schristos } 97897be3a4Schristos 98897be3a4Schristos closesocket(s); 99897be3a4Schristos 100897be3a4Schristos return (ISC_R_SUCCESS); 101897be3a4Schristos } 102897be3a4Schristos 103897be3a4Schristos static void 104897be3a4Schristos initialize_action(void) { 105897be3a4Schristos InitSockets(); 106897be3a4Schristos ipv4_result = try_proto(PF_INET); 107897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIPV6 108897be3a4Schristos #ifdef WANT_IPV6 109897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIN6PKTINFO 110897be3a4Schristos ipv6_result = try_proto(PF_INET6); 111897be3a4Schristos #endif 112897be3a4Schristos #endif 113897be3a4Schristos #endif 114897be3a4Schristos } 115897be3a4Schristos 116897be3a4Schristos static void 117897be3a4Schristos initialize(void) { 118897be3a4Schristos RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 119897be3a4Schristos } 120897be3a4Schristos 121897be3a4Schristos isc_result_t 122897be3a4Schristos isc_net_probeipv4(void) { 123897be3a4Schristos initialize(); 124897be3a4Schristos return (ipv4_result); 125897be3a4Schristos } 126897be3a4Schristos 127897be3a4Schristos isc_result_t 128897be3a4Schristos isc_net_probeipv6(void) { 129897be3a4Schristos initialize(); 130897be3a4Schristos return (ipv6_result); 131897be3a4Schristos } 132897be3a4Schristos 133897be3a4Schristos isc_result_t 134897be3a4Schristos isc_net_probeunix(void) { 135897be3a4Schristos return (ISC_R_NOTFOUND); 136897be3a4Schristos } 137897be3a4Schristos 138897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIPV6 139897be3a4Schristos #ifdef WANT_IPV6 140897be3a4Schristos static void 141897be3a4Schristos try_ipv6only(void) { 142897be3a4Schristos #ifdef IPV6_V6ONLY 143897be3a4Schristos SOCKET s; 144897be3a4Schristos int on; 145897be3a4Schristos char strbuf[ISC_STRERRORSIZE]; 146897be3a4Schristos #endif 147897be3a4Schristos isc_result_t result; 148897be3a4Schristos 149897be3a4Schristos result = isc_net_probeipv6(); 150897be3a4Schristos if (result != ISC_R_SUCCESS) { 151897be3a4Schristos ipv6only_result = result; 152897be3a4Schristos return; 153897be3a4Schristos } 154897be3a4Schristos 155897be3a4Schristos #ifndef IPV6_V6ONLY 156897be3a4Schristos ipv6only_result = ISC_R_NOTFOUND; 157897be3a4Schristos return; 158897be3a4Schristos #else 159897be3a4Schristos /* check for TCP sockets */ 160897be3a4Schristos s = socket(PF_INET6, SOCK_STREAM, 0); 161897be3a4Schristos if (s == INVALID_SOCKET) { 162897be3a4Schristos isc__strerror(errno, strbuf, sizeof(strbuf)); 163897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, 164897be3a4Schristos "socket() %s: %s", 165897be3a4Schristos isc_msgcat_get(isc_msgcat, 166897be3a4Schristos ISC_MSGSET_GENERAL, 167897be3a4Schristos ISC_MSG_FAILED, 168897be3a4Schristos "failed"), 169897be3a4Schristos strbuf); 170897be3a4Schristos ipv6only_result = ISC_R_UNEXPECTED; 171897be3a4Schristos return; 172897be3a4Schristos } 173897be3a4Schristos 174897be3a4Schristos on = 1; 175897be3a4Schristos if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&on, 176897be3a4Schristos sizeof(on)) < 0) { 177897be3a4Schristos ipv6only_result = ISC_R_NOTFOUND; 178897be3a4Schristos goto close; 179897be3a4Schristos } 180897be3a4Schristos 181897be3a4Schristos closesocket(s); 182897be3a4Schristos 183897be3a4Schristos /* check for UDP sockets */ 184897be3a4Schristos s = socket(PF_INET6, SOCK_DGRAM, 0); 185897be3a4Schristos if (s == INVALID_SOCKET) { 186897be3a4Schristos isc__strerror(errno, strbuf, sizeof(strbuf)); 187897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, 188897be3a4Schristos "socket() %s: %s", 189897be3a4Schristos isc_msgcat_get(isc_msgcat, 190897be3a4Schristos ISC_MSGSET_GENERAL, 191897be3a4Schristos ISC_MSG_FAILED, 192897be3a4Schristos "failed"), 193897be3a4Schristos strbuf); 194897be3a4Schristos ipv6only_result = ISC_R_UNEXPECTED; 195897be3a4Schristos return; 196897be3a4Schristos } 197897be3a4Schristos 198897be3a4Schristos on = 1; 199897be3a4Schristos if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&on, 200897be3a4Schristos sizeof(on)) < 0) { 201897be3a4Schristos ipv6only_result = ISC_R_NOTFOUND; 202897be3a4Schristos goto close; 203897be3a4Schristos } 204897be3a4Schristos 205897be3a4Schristos ipv6only_result = ISC_R_SUCCESS; 206897be3a4Schristos 207897be3a4Schristos close: 208897be3a4Schristos closesocket(s); 209897be3a4Schristos return; 210897be3a4Schristos #endif /* IPV6_V6ONLY */ 211897be3a4Schristos } 212897be3a4Schristos 213897be3a4Schristos static void 214897be3a4Schristos initialize_ipv6only(void) { 215897be3a4Schristos RUNTIME_CHECK(isc_once_do(&once_ipv6only, 216897be3a4Schristos try_ipv6only) == ISC_R_SUCCESS); 217897be3a4Schristos } 218897be3a4Schristos 219897be3a4Schristos static void 220897be3a4Schristos try_ipv6pktinfo(void) { 221897be3a4Schristos SOCKET s; 222897be3a4Schristos int on; 223897be3a4Schristos char strbuf[ISC_STRERRORSIZE]; 224897be3a4Schristos isc_result_t result; 225897be3a4Schristos int optname; 226897be3a4Schristos 227897be3a4Schristos result = isc_net_probeipv6(); 228897be3a4Schristos if (result != ISC_R_SUCCESS) { 229897be3a4Schristos ipv6pktinfo_result = result; 230897be3a4Schristos return; 231897be3a4Schristos } 232897be3a4Schristos 233897be3a4Schristos /* we only use this for UDP sockets */ 234897be3a4Schristos s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); 235897be3a4Schristos if (s == INVALID_SOCKET) { 236897be3a4Schristos isc__strerror(errno, strbuf, sizeof(strbuf)); 237897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, 238897be3a4Schristos "socket() %s: %s", 239897be3a4Schristos isc_msgcat_get(isc_msgcat, 240897be3a4Schristos ISC_MSGSET_GENERAL, 241897be3a4Schristos ISC_MSG_FAILED, 242897be3a4Schristos "failed"), 243897be3a4Schristos strbuf); 244897be3a4Schristos ipv6pktinfo_result = ISC_R_UNEXPECTED; 245897be3a4Schristos return; 246897be3a4Schristos } 247897be3a4Schristos 248897be3a4Schristos #ifdef IPV6_RECVPKTINFO 249897be3a4Schristos optname = IPV6_RECVPKTINFO; 250897be3a4Schristos #else 251897be3a4Schristos optname = IPV6_PKTINFO; 252897be3a4Schristos #endif 253897be3a4Schristos on = 1; 254897be3a4Schristos if (setsockopt(s, IPPROTO_IPV6, optname, (const char *) &on, 255897be3a4Schristos sizeof(on)) < 0) { 256897be3a4Schristos ipv6pktinfo_result = ISC_R_NOTFOUND; 257897be3a4Schristos goto close; 258897be3a4Schristos } 259897be3a4Schristos 260897be3a4Schristos ipv6pktinfo_result = ISC_R_SUCCESS; 261897be3a4Schristos 262897be3a4Schristos close: 263897be3a4Schristos closesocket(s); 264897be3a4Schristos return; 265897be3a4Schristos } 266897be3a4Schristos 267897be3a4Schristos static void 268897be3a4Schristos initialize_ipv6pktinfo(void) { 269897be3a4Schristos RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo, 270897be3a4Schristos try_ipv6pktinfo) == ISC_R_SUCCESS); 271897be3a4Schristos } 272897be3a4Schristos #endif /* WANT_IPV6 */ 273897be3a4Schristos #endif /* ISC_PLATFORM_HAVEIPV6 */ 274897be3a4Schristos 275897be3a4Schristos isc_result_t 276897be3a4Schristos isc_net_probe_ipv6only(void) { 277897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIPV6 278897be3a4Schristos #ifdef WANT_IPV6 279897be3a4Schristos initialize_ipv6only(); 280897be3a4Schristos #else 281897be3a4Schristos ipv6only_result = ISC_R_NOTFOUND; 282897be3a4Schristos #endif 283897be3a4Schristos #endif 284897be3a4Schristos return (ipv6only_result); 285897be3a4Schristos } 286897be3a4Schristos 287897be3a4Schristos isc_result_t 288897be3a4Schristos isc_net_probe_ipv6pktinfo(void) { 289897be3a4Schristos #ifdef ISC_PLATFORM_HAVEIPV6 290897be3a4Schristos #ifdef WANT_IPV6 291897be3a4Schristos initialize_ipv6pktinfo(); 292897be3a4Schristos #else 293897be3a4Schristos ipv6pktinfo_result = ISC_R_NOTFOUND; 294897be3a4Schristos #endif 295897be3a4Schristos #endif 296897be3a4Schristos return (ipv6pktinfo_result); 297897be3a4Schristos } 298897be3a4Schristos 299897be3a4Schristos isc_result_t 300897be3a4Schristos isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) { 301897be3a4Schristos int result = ISC_R_FAILURE; 302897be3a4Schristos 303897be3a4Schristos REQUIRE(low != NULL && high != NULL); 304897be3a4Schristos 305897be3a4Schristos UNUSED(af); 306897be3a4Schristos 307897be3a4Schristos if (result != ISC_R_SUCCESS) { 308897be3a4Schristos *low = ISC_NET_PORTRANGELOW; 309897be3a4Schristos *high = ISC_NET_PORTRANGEHIGH; 310897be3a4Schristos } 311897be3a4Schristos 312897be3a4Schristos return (ISC_R_SUCCESS); /* we currently never fail in this function */ 313897be3a4Schristos } 314897be3a4Schristos 315897be3a4Schristos void 316897be3a4Schristos isc_net_disableipv4(void) { 317897be3a4Schristos initialize(); 318897be3a4Schristos if (ipv4_result == ISC_R_SUCCESS) 319897be3a4Schristos ipv4_result = ISC_R_DISABLED; 320897be3a4Schristos } 321897be3a4Schristos 322897be3a4Schristos void 323897be3a4Schristos isc_net_disableipv6(void) { 324897be3a4Schristos initialize(); 325897be3a4Schristos if (ipv6_result == ISC_R_SUCCESS) 326897be3a4Schristos ipv6_result = ISC_R_DISABLED; 327897be3a4Schristos } 328897be3a4Schristos 329897be3a4Schristos void 330897be3a4Schristos isc_net_enableipv4(void) { 331897be3a4Schristos initialize(); 332897be3a4Schristos if (ipv4_result == ISC_R_DISABLED) 333897be3a4Schristos ipv4_result = ISC_R_SUCCESS; 334897be3a4Schristos } 335897be3a4Schristos 336897be3a4Schristos void 337897be3a4Schristos isc_net_enableipv6(void) { 338897be3a4Schristos initialize(); 339897be3a4Schristos if (ipv6_result == ISC_R_DISABLED) 340897be3a4Schristos ipv6_result = ISC_R_SUCCESS; 341897be3a4Schristos } 342