"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/lib/isc/unix/net.c" (4 Sep 2020, 20929 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "net.c" see the Fossies "Dox" file reference documentation.

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