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