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