"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/isc/unix/net.c" (7 Sep 2020, 21068 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


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