net.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2008, 2012-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 #include <config.h>
00021 
00022 #include <sys/types.h>
00023 
00024 #if defined(HAVE_SYS_SYSCTL_H)
00025 #if defined(HAVE_SYS_PARAM_H)
00026 #include <sys/param.h>
00027 #endif
00028 #include <sys/sysctl.h>
00029 #endif
00030 #include <sys/uio.h>
00031 
00032 #include <errno.h>
00033 #include <unistd.h>
00034 #include <fcntl.h>
00035 
00036 #include <isc/log.h>
00037 #include <isc/msgs.h>
00038 #include <isc/net.h>
00039 #include <isc/netdb.h>
00040 #include <isc/once.h>
00041 #include <isc/strerror.h>
00042 #include <isc/string.h>
00043 #include <isc/util.h>
00044 
00045 #ifndef ISC_SOCKADDR_LEN_T
00046 #define ISC_SOCKADDR_LEN_T unsigned int
00047 #endif
00048 
00049 /*%
00050  * Definitions about UDP port range specification.  This is a total mess of
00051  * portability variants: some use sysctl (but the sysctl names vary), some use
00052  * system-specific interfaces, some have the same interface for IPv4 and IPv6,
00053  * some separate them, etc...
00054  */
00055 
00056 /*%
00057  * The last resort defaults: use all non well known port space
00058  */
00059 #ifndef ISC_NET_PORTRANGELOW
00060 #define ISC_NET_PORTRANGELOW 1024
00061 #endif  /* ISC_NET_PORTRANGELOW */
00062 #ifndef ISC_NET_PORTRANGEHIGH
00063 #define ISC_NET_PORTRANGEHIGH 65535
00064 #endif  /* ISC_NET_PORTRANGEHIGH */
00065 
00066 #ifdef HAVE_SYSCTLBYNAME
00067 
00068 /*%
00069  * sysctl variants
00070  */
00071 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
00072 #define USE_SYSCTL_PORTRANGE
00073 #define SYSCTL_V4PORTRANGE_LOW  "net.inet.ip.portrange.hifirst"
00074 #define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
00075 #define SYSCTL_V6PORTRANGE_LOW  "net.inet.ip.portrange.hifirst"
00076 #define SYSCTL_V6PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
00077 #endif
00078 
00079 #ifdef __NetBSD__
00080 #define USE_SYSCTL_PORTRANGE
00081 #define SYSCTL_V4PORTRANGE_LOW  "net.inet.ip.anonportmin"
00082 #define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.anonportmax"
00083 #define SYSCTL_V6PORTRANGE_LOW  "net.inet6.ip6.anonportmin"
00084 #define SYSCTL_V6PORTRANGE_HIGH "net.inet6.ip6.anonportmax"
00085 #endif
00086 
00087 #else /* !HAVE_SYSCTLBYNAME */
00088 
00089 #ifdef __OpenBSD__
00090 #define USE_SYSCTL_PORTRANGE
00091 #define SYSCTL_V4PORTRANGE_LOW  { CTL_NET, PF_INET, IPPROTO_IP, \
00092                                   IPCTL_IPPORT_HIFIRSTAUTO }
00093 #define SYSCTL_V4PORTRANGE_HIGH { CTL_NET, PF_INET, IPPROTO_IP, \
00094                                   IPCTL_IPPORT_HILASTAUTO }
00095 /* Same for IPv6 */
00096 #define SYSCTL_V6PORTRANGE_LOW  SYSCTL_V4PORTRANGE_LOW
00097 #define SYSCTL_V6PORTRANGE_HIGH SYSCTL_V4PORTRANGE_HIGH
00098 #endif
00099 
00100 #endif /* HAVE_SYSCTLBYNAME */
00101 
00102 #if defined(ISC_PLATFORM_HAVEIPV6)
00103 # if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
00104 const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
00105 # endif
00106 
00107 # if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
00108 const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
00109 # endif
00110 
00111 # if defined(WANT_IPV6)
00112 static isc_once_t       once_ipv6only = ISC_ONCE_INIT;
00113 # endif
00114 
00115 # if defined(ISC_PLATFORM_HAVEIN6PKTINFO)
00116 static isc_once_t       once_ipv6pktinfo = ISC_ONCE_INIT;
00117 # endif
00118 #endif /* ISC_PLATFORM_HAVEIPV6 */
00119 
00120 static isc_once_t       once = ISC_ONCE_INIT;
00121 static isc_once_t       once_dscp = ISC_ONCE_INIT;
00122 
00123 static isc_result_t     ipv4_result = ISC_R_NOTFOUND;
00124 static isc_result_t     ipv6_result = ISC_R_NOTFOUND;
00125 static isc_result_t     unix_result = ISC_R_NOTFOUND;
00126 static isc_result_t     ipv6only_result = ISC_R_NOTFOUND;
00127 static isc_result_t     ipv6pktinfo_result = ISC_R_NOTFOUND;
00128 static unsigned int     dscp_result = 0;
00129 
00130 static isc_result_t
00131 try_proto(int domain) {
00132         int s;
00133         isc_result_t result = ISC_R_SUCCESS;
00134         char strbuf[ISC_STRERRORSIZE];
00135 
00136         s = socket(domain, SOCK_STREAM, 0);
00137         if (s == -1) {
00138                 switch (errno) {
00139 #ifdef EAFNOSUPPORT
00140                 case EAFNOSUPPORT:
00141 #endif
00142 #ifdef EPROTONOSUPPORT
00143                 case EPROTONOSUPPORT:
00144 #endif
00145 #ifdef EINVAL
00146                 case EINVAL:
00147 #endif
00148                         return (ISC_R_NOTFOUND);
00149                 default:
00150                         isc__strerror(errno, strbuf, sizeof(strbuf));
00151                         UNEXPECTED_ERROR(__FILE__, __LINE__,
00152                                          "socket() %s: %s",
00153                                          isc_msgcat_get(isc_msgcat,
00154                                                         ISC_MSGSET_GENERAL,
00155                                                         ISC_MSG_FAILED,
00156                                                         "failed"),
00157                                          strbuf);
00158                         return (ISC_R_UNEXPECTED);
00159                 }
00160         }
00161 
00162 #ifdef ISC_PLATFORM_HAVEIPV6
00163 #ifdef WANT_IPV6
00164 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
00165         if (domain == PF_INET6) {
00166                 struct sockaddr_in6 sin6;
00167                 unsigned int len;
00168 
00169                 /*
00170                  * Check to see if IPv6 is broken, as is common on Linux.
00171                  */
00172                 len = sizeof(sin6);
00173                 if (getsockname(s, (struct sockaddr *)&sin6, (void *)&len) < 0)
00174                 {
00175                         isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00176                                       ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
00177                                       "retrieving the address of an IPv6 "
00178                                       "socket from the kernel failed.");
00179                         isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00180                                       ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
00181                                       "IPv6 is not supported.");
00182                         result = ISC_R_NOTFOUND;
00183                 } else {
00184                         if (len == sizeof(struct sockaddr_in6))
00185                                 result = ISC_R_SUCCESS;
00186                         else {
00187                                 isc_log_write(isc_lctx,
00188                                               ISC_LOGCATEGORY_GENERAL,
00189                                               ISC_LOGMODULE_SOCKET,
00190                                               ISC_LOG_ERROR,
00191                                               "IPv6 structures in kernel and "
00192                                               "user space do not match.");
00193                                 isc_log_write(isc_lctx,
00194                                               ISC_LOGCATEGORY_GENERAL,
00195                                               ISC_LOGMODULE_SOCKET,
00196                                               ISC_LOG_ERROR,
00197                                               "IPv6 is not supported.");
00198                                 result = ISC_R_NOTFOUND;
00199                         }
00200                 }
00201         }
00202 #endif
00203 #endif
00204 #endif
00205 
00206         (void)close(s);
00207 
00208         return (result);
00209 }
00210 
00211 static void
00212 initialize_action(void) {
00213         ipv4_result = try_proto(PF_INET);
00214 #ifdef ISC_PLATFORM_HAVEIPV6
00215 #ifdef WANT_IPV6
00216 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
00217         ipv6_result = try_proto(PF_INET6);
00218 #endif
00219 #endif
00220 #endif
00221 #ifdef ISC_PLATFORM_HAVESYSUNH
00222         unix_result = try_proto(PF_UNIX);
00223 #endif
00224 }
00225 
00226 static void
00227 initialize(void) {
00228         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
00229 }
00230 
00231 isc_result_t
00232 isc_net_probeipv4(void) {
00233         initialize();
00234         return (ipv4_result);
00235 }
00236 
00237 isc_result_t
00238 isc_net_probeipv6(void) {
00239         initialize();
00240         return (ipv6_result);
00241 }
00242 
00243 isc_result_t
00244 isc_net_probeunix(void) {
00245         initialize();
00246         return (unix_result);
00247 }
00248 
00249 #ifdef ISC_PLATFORM_HAVEIPV6
00250 #ifdef WANT_IPV6
00251 static void
00252 try_ipv6only(void) {
00253 #ifdef IPV6_V6ONLY
00254         int s, on;
00255         char strbuf[ISC_STRERRORSIZE];
00256 #endif
00257         isc_result_t result;
00258 
00259         result = isc_net_probeipv6();
00260         if (result != ISC_R_SUCCESS) {
00261                 ipv6only_result = result;
00262                 return;
00263         }
00264 
00265 #ifndef IPV6_V6ONLY
00266         ipv6only_result = ISC_R_NOTFOUND;
00267         return;
00268 #else
00269         /* check for TCP sockets */
00270         s = socket(PF_INET6, SOCK_STREAM, 0);
00271         if (s == -1) {
00272                 isc__strerror(errno, strbuf, sizeof(strbuf));
00273                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00274                                  "socket() %s: %s",
00275                                  isc_msgcat_get(isc_msgcat,
00276                                                 ISC_MSGSET_GENERAL,
00277                                                 ISC_MSG_FAILED,
00278                                                 "failed"),
00279                                  strbuf);
00280                 ipv6only_result = ISC_R_UNEXPECTED;
00281                 return;
00282         }
00283 
00284         on = 1;
00285         if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
00286                 ipv6only_result = ISC_R_NOTFOUND;
00287                 goto close;
00288         }
00289 
00290         close(s);
00291 
00292         /* check for UDP sockets */
00293         s = socket(PF_INET6, SOCK_DGRAM, 0);
00294         if (s == -1) {
00295                 isc__strerror(errno, strbuf, sizeof(strbuf));
00296                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00297                                  "socket() %s: %s",
00298                                  isc_msgcat_get(isc_msgcat,
00299                                                 ISC_MSGSET_GENERAL,
00300                                                 ISC_MSG_FAILED,
00301                                                 "failed"),
00302                                  strbuf);
00303                 ipv6only_result = ISC_R_UNEXPECTED;
00304                 return;
00305         }
00306 
00307         on = 1;
00308         if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
00309                 ipv6only_result = ISC_R_NOTFOUND;
00310                 goto close;
00311         }
00312 
00313         ipv6only_result = ISC_R_SUCCESS;
00314 
00315 close:
00316         close(s);
00317         return;
00318 #endif /* IPV6_V6ONLY */
00319 }
00320 
00321 static void
00322 initialize_ipv6only(void) {
00323         RUNTIME_CHECK(isc_once_do(&once_ipv6only,
00324                                   try_ipv6only) == ISC_R_SUCCESS);
00325 }
00326 #endif /* WANT_IPV6 */
00327 
00328 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
00329 #ifdef WANT_IPV6
00330 static void
00331 try_ipv6pktinfo(void) {
00332         int s, on;
00333         char strbuf[ISC_STRERRORSIZE];
00334         isc_result_t result;
00335         int optname;
00336 
00337         result = isc_net_probeipv6();
00338         if (result != ISC_R_SUCCESS) {
00339                 ipv6pktinfo_result = result;
00340                 return;
00341         }
00342 
00343         /* we only use this for UDP sockets */
00344         s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
00345         if (s == -1) {
00346                 isc__strerror(errno, strbuf, sizeof(strbuf));
00347                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00348                                  "socket() %s: %s",
00349                                  isc_msgcat_get(isc_msgcat,
00350                                                 ISC_MSGSET_GENERAL,
00351                                                 ISC_MSG_FAILED,
00352                                                 "failed"),
00353                                  strbuf);
00354                 ipv6pktinfo_result = ISC_R_UNEXPECTED;
00355                 return;
00356         }
00357 
00358 #ifdef IPV6_RECVPKTINFO
00359         optname = IPV6_RECVPKTINFO;
00360 #else
00361         optname = IPV6_PKTINFO;
00362 #endif
00363         on = 1;
00364         if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
00365                 ipv6pktinfo_result = ISC_R_NOTFOUND;
00366                 goto close;
00367         }
00368 
00369         ipv6pktinfo_result = ISC_R_SUCCESS;
00370 
00371 close:
00372         close(s);
00373         return;
00374 }
00375 
00376 static void
00377 initialize_ipv6pktinfo(void) {
00378         RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
00379                                   try_ipv6pktinfo) == ISC_R_SUCCESS);
00380 }
00381 #endif /* WANT_IPV6 */
00382 #endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
00383 #endif /* ISC_PLATFORM_HAVEIPV6 */
00384 
00385 isc_result_t
00386 isc_net_probe_ipv6only(void) {
00387 #ifdef ISC_PLATFORM_HAVEIPV6
00388 #ifdef WANT_IPV6
00389         initialize_ipv6only();
00390 #else
00391         ipv6only_result = ISC_R_NOTFOUND;
00392 #endif
00393 #endif
00394         return (ipv6only_result);
00395 }
00396 
00397 isc_result_t
00398 isc_net_probe_ipv6pktinfo(void) {
00399 #ifdef ISC_PLATFORM_HAVEIPV6
00400 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
00401 #ifdef WANT_IPV6
00402         initialize_ipv6pktinfo();
00403 #else
00404         ipv6pktinfo_result = ISC_R_NOTFOUND;
00405 #endif
00406 #endif
00407 #endif
00408         return (ipv6pktinfo_result);
00409 }
00410 
00411 static inline ISC_SOCKADDR_LEN_T
00412 cmsg_len(ISC_SOCKADDR_LEN_T len) {
00413 #ifdef CMSG_LEN
00414         return (CMSG_LEN(len));
00415 #else
00416         ISC_SOCKADDR_LEN_T hdrlen;
00417 
00418         /*
00419          * Cast NULL so that any pointer arithmetic performed by CMSG_DATA
00420          * is correct.
00421          */
00422         hdrlen = (ISC_SOCKADDR_LEN_T)CMSG_DATA(((struct cmsghdr *)NULL));
00423         return (hdrlen + len);
00424 #endif
00425 }
00426 
00427 static inline ISC_SOCKADDR_LEN_T
00428 cmsg_space(ISC_SOCKADDR_LEN_T len) {
00429 #ifdef CMSG_SPACE
00430         return (CMSG_SPACE(len));
00431 #else
00432         struct msghdr msg;
00433         struct cmsghdr *cmsgp;
00434         /*
00435          * XXX: The buffer length is an ad-hoc value, but should be enough
00436          * in a practical sense.
00437          */
00438         char dummybuf[sizeof(struct cmsghdr) + 1024];
00439 
00440         memset(&msg, 0, sizeof(msg));
00441         msg.msg_control = dummybuf;
00442         msg.msg_controllen = sizeof(dummybuf);
00443 
00444         cmsgp = (struct cmsghdr *)dummybuf;
00445         cmsgp->cmsg_len = cmsg_len(len);
00446 
00447         cmsgp = CMSG_NXTHDR(&msg, cmsgp);
00448         if (cmsgp != NULL)
00449                 return ((char *)cmsgp - (char *)msg.msg_control);
00450         else
00451                 return (0);
00452 #endif
00453 }
00454 
00455 #ifdef ISC_NET_BSD44MSGHDR
00456 /*
00457  * Make a fd non-blocking.
00458  */
00459 static isc_result_t
00460 make_nonblock(int fd) {
00461         int ret;
00462         int flags;
00463         char strbuf[ISC_STRERRORSIZE];
00464 #ifdef USE_FIONBIO_IOCTL
00465         int on = 1;
00466 
00467         ret = ioctl(fd, FIONBIO, (char *)&on);
00468 #else
00469         flags = fcntl(fd, F_GETFL, 0);
00470         flags |= PORT_NONBLOCK;
00471         ret = fcntl(fd, F_SETFL, flags);
00472 #endif
00473 
00474         if (ret == -1) {
00475                 isc__strerror(errno, strbuf, sizeof(strbuf));
00476                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00477 #ifdef USE_FIONBIO_IOCTL
00478                                  "ioctl(%d, FIONBIO, &on): %s", fd,
00479 #else
00480                                  "fcntl(%d, F_SETFL, %d): %s", fd, flags,
00481 #endif
00482                                  strbuf);
00483 
00484                 return (ISC_R_UNEXPECTED);
00485         }
00486 
00487         return (ISC_R_SUCCESS);
00488 }
00489 
00490 static isc_boolean_t
00491 cmsgsend(int s, int level, int type, struct addrinfo *res) {
00492         char strbuf[ISC_STRERRORSIZE];
00493         struct sockaddr_storage ss;
00494         ISC_SOCKADDR_LEN_T len = sizeof(ss);
00495         struct msghdr msg;
00496         union {
00497                 struct cmsghdr h;
00498                 unsigned char b[256];
00499         } control;
00500         struct cmsghdr *cmsgp;
00501         int dscp = 46;
00502         struct iovec iovec;
00503         char buf[1] = { 0 };
00504         isc_result_t result;
00505 
00506         if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
00507                 isc__strerror(errno, strbuf, sizeof(strbuf));
00508                 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00509                               ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
00510                               "bind: %s", strbuf);
00511                 return (ISC_FALSE);
00512         }
00513 
00514         if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
00515                 isc__strerror(errno, strbuf, sizeof(strbuf));
00516                 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00517                               ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
00518                               "getsockname: %s", strbuf);
00519                 return (ISC_FALSE);
00520         }
00521 
00522         iovec.iov_base = buf;
00523         iovec.iov_len = sizeof(buf);
00524 
00525         memset(&msg, 0, sizeof(msg));
00526         msg.msg_name = (struct sockaddr *)&ss;
00527         msg.msg_namelen = len;
00528         msg.msg_iov = &iovec;
00529         msg.msg_iovlen = 1;
00530         msg.msg_control = (void*)&control;
00531         msg.msg_controllen = 0;
00532         msg.msg_flags = 0;
00533 
00534         cmsgp = msg.msg_control;
00535 
00536         switch (type) {
00537 #ifdef IP_TOS
00538         case IP_TOS:
00539                 memset(cmsgp, 0, cmsg_space(sizeof(char)));
00540                 cmsgp->cmsg_level = level;
00541                 cmsgp->cmsg_type = type;
00542                 cmsgp->cmsg_len = cmsg_len(sizeof(char));
00543                 *(unsigned char*)CMSG_DATA(cmsgp) = dscp;
00544                 msg.msg_controllen += cmsg_space(sizeof(char));
00545                 break;
00546 #endif
00547 #ifdef IPV6_TCLASS
00548         case IPV6_TCLASS:
00549                 memset(cmsgp, 0, cmsg_space(sizeof(dscp)));
00550                 cmsgp->cmsg_level = level;
00551                 cmsgp->cmsg_type = type;
00552                 cmsgp->cmsg_len = cmsg_len(sizeof(dscp));
00553                 memmove(CMSG_DATA(cmsgp), &dscp, sizeof(dscp));
00554                 msg.msg_controllen += cmsg_space(sizeof(dscp));
00555                 break;
00556 #endif
00557         default:
00558                 INSIST(0);
00559         }
00560 
00561         if (sendmsg(s, &msg, 0) < 0) {
00562                 int debug = ISC_LOG_DEBUG(10);
00563                 switch (errno) {
00564 #ifdef ENOPROTOOPT
00565                 case ENOPROTOOPT:
00566 #endif
00567 #ifdef EOPNOTSUPP
00568                 case EOPNOTSUPP:
00569 #endif
00570                 case EINVAL:
00571                         break;
00572                 default:
00573                         debug = ISC_LOG_NOTICE;
00574                 }
00575                 isc__strerror(errno, strbuf, sizeof(strbuf));
00576                 if (debug != ISC_LOG_NOTICE) {
00577                         isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00578                                       ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
00579                                       "sendmsg: %s", strbuf);
00580                 } else {
00581                         UNEXPECTED_ERROR(__FILE__, __LINE__,
00582                                          "sendmsg() %s: %s",
00583                                          isc_msgcat_get(isc_msgcat,
00584                                                         ISC_MSGSET_GENERAL,
00585                                                         ISC_MSG_FAILED,
00586                                                         "failed"),
00587                                          strbuf);
00588                 }
00589                 return (ISC_FALSE);
00590         }
00591 
00592         /*
00593          * Make sure the message actually got sent.
00594          */
00595         result = make_nonblock(s);
00596         RUNTIME_CHECK(result == ISC_R_SUCCESS);
00597 
00598         iovec.iov_base = buf;
00599         iovec.iov_len = sizeof(buf);
00600 
00601         memset(&msg, 0, sizeof(msg));
00602         msg.msg_name = (struct sockaddr *)&ss;
00603         msg.msg_namelen = sizeof(ss);
00604         msg.msg_iov = &iovec;
00605         msg.msg_iovlen = 1;
00606         msg.msg_control = NULL;
00607         msg.msg_controllen = 0;
00608         msg.msg_flags = 0;
00609 
00610         if (recvmsg(s, &msg, 0) < 0)
00611                 return (ISC_FALSE);
00612 
00613         return (ISC_TRUE);
00614 }
00615 #endif
00616 
00617 static void
00618 try_dscp_v4(void) {
00619 #ifdef IP_TOS
00620         char strbuf[ISC_STRERRORSIZE];
00621         struct addrinfo hints, *res0;
00622         int s, dscp = 0, n;
00623 #ifdef IP_RECVTOS
00624         int on = 1;
00625 #endif /* IP_RECVTOS */
00626 
00627         memset(&hints, 0, sizeof(hints));
00628         hints.ai_family = AF_INET;
00629         hints.ai_socktype = SOCK_DGRAM;
00630         hints.ai_protocol = IPPROTO_UDP;
00631 #ifdef AI_NUMERICHOST
00632         hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
00633 #else
00634         hints.ai_flags = AI_PASSIVE;
00635 #endif
00636 
00637         n = getaddrinfo("127.0.0.1", NULL, &hints, &res0);
00638         if (n != 0 || res0 == NULL) {
00639                 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00640                               ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
00641                               "getaddrinfo(127.0.0.1): %s", gai_strerror(n));
00642                 return;
00643         }
00644 
00645         s = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol);
00646 
00647         if (s == -1) {
00648                 isc__strerror(errno, strbuf, sizeof(strbuf));
00649                 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00650                               ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
00651                               "socket: %s", strbuf);
00652                 freeaddrinfo(res0);
00653                 return;
00654         }
00655 
00656         if (setsockopt(s, IPPROTO_IP, IP_TOS, &dscp, sizeof(dscp)) == 0)
00657                 dscp_result |= ISC_NET_DSCPSETV4;
00658 
00659 #ifdef IP_RECVTOS
00660         on = 1;
00661         if (setsockopt(s, IPPROTO_IP, IP_RECVTOS, &on, sizeof(on)) == 0)
00662                 dscp_result |= ISC_NET_DSCPRECVV4;
00663 #endif /* IP_RECVTOS */
00664 
00665 #ifdef ISC_NET_BSD44MSGHDR
00666 
00667 #ifndef ISC_CMSG_IP_TOS
00668 #ifdef __APPLE__
00669 #define ISC_CMSG_IP_TOS 0       /* As of 10.8.2. */
00670 #else /* ! __APPLE__ */
00671 #define ISC_CMSG_IP_TOS 1
00672 #endif /* ! __APPLE__ */
00673 #endif /* ! ISC_CMSG_IP_TOS */
00674 
00675 #if ISC_CMSG_IP_TOS
00676         if (cmsgsend(s, IPPROTO_IP, IP_TOS, res0))
00677                 dscp_result |= ISC_NET_DSCPPKTV4;
00678 #endif /* ISC_CMSG_IP_TOS */
00679 
00680 #endif /* ISC_NET_BSD44MSGHDR */
00681 
00682         freeaddrinfo(res0);
00683         close(s);
00684 
00685 #endif /* IP_TOS */
00686 }
00687 
00688 static void
00689 try_dscp_v6(void) {
00690 #ifdef ISC_PLATFORM_HAVEIPV6
00691 #ifdef WANT_IPV6
00692 #ifdef IPV6_TCLASS
00693         char strbuf[ISC_STRERRORSIZE];
00694         struct addrinfo hints, *res0;
00695         int s, dscp = 0, n;
00696 #if defined(IPV6_RECVTCLASS)
00697         int on = 1;
00698 #endif /* IPV6_RECVTCLASS */
00699 
00700         memset(&hints, 0, sizeof(hints));
00701         hints.ai_family = AF_INET6;
00702         hints.ai_socktype = SOCK_DGRAM;
00703         hints.ai_protocol = IPPROTO_UDP;
00704 #ifdef AI_NUMERICHOST
00705         hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
00706 #else
00707         hints.ai_flags = AI_PASSIVE;
00708 #endif
00709 
00710         n = getaddrinfo("::1", NULL, &hints, &res0);
00711         if (n != 0 || res0 == NULL) {
00712                 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00713                               ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
00714                               "getaddrinfo(::1): %s", gai_strerror(n));
00715                 return;
00716         }
00717 
00718         s = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol);
00719         if (s == -1) {
00720                 isc__strerror(errno, strbuf, sizeof(strbuf));
00721                 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00722                               ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
00723                               "socket: %s", strbuf);
00724                 freeaddrinfo(res0);
00725                 return;
00726         }
00727         if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &dscp, sizeof(dscp)) == 0)
00728                 dscp_result |= ISC_NET_DSCPSETV6;
00729 
00730 #ifdef IPV6_RECVTCLASS
00731         on = 1;
00732         if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVTCLASS, &on, sizeof(on)) == 0)
00733                 dscp_result |= ISC_NET_DSCPRECVV6;
00734 #endif /* IPV6_RECVTCLASS */
00735 
00736 #ifdef ISC_NET_BSD44MSGHDR
00737         if (cmsgsend(s, IPPROTO_IPV6, IPV6_TCLASS, res0))
00738                 dscp_result |= ISC_NET_DSCPPKTV6;
00739 #endif /* ISC_NET_BSD44MSGHDR */
00740 
00741         freeaddrinfo(res0);
00742         close(s);
00743 
00744 #endif /* IPV6_TCLASS */
00745 #endif /* WANT_IPV6 */
00746 #endif /* ISC_PLATFORM_HAVEIPV6 */
00747 }
00748 
00749 static void
00750 try_dscp(void) {
00751         try_dscp_v4();
00752         try_dscp_v6();
00753 }
00754 
00755 static void
00756 initialize_dscp(void) {
00757         RUNTIME_CHECK(isc_once_do(&once_dscp, try_dscp) == ISC_R_SUCCESS);
00758 }
00759 
00760 unsigned int
00761 isc_net_probedscp(void) {
00762         initialize_dscp();
00763         return (dscp_result);
00764 }
00765 
00766 #if defined(USE_SYSCTL_PORTRANGE)
00767 #if defined(HAVE_SYSCTLBYNAME)
00768 static isc_result_t
00769 getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
00770         int port_low, port_high;
00771         size_t portlen;
00772         const char *sysctlname_lowport, *sysctlname_hiport;
00773 
00774         if (af == AF_INET) {
00775                 sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW;
00776                 sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH;
00777         } else {
00778                 sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
00779                 sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
00780         }
00781         portlen = sizeof(port_low);
00782         if (sysctlbyname(sysctlname_lowport, &port_low, &portlen,
00783                          NULL, 0) < 0) {
00784                 return (ISC_R_FAILURE);
00785         }
00786         portlen = sizeof(port_high);
00787         if (sysctlbyname(sysctlname_hiport, &port_high, &portlen,
00788                          NULL, 0) < 0) {
00789                 return (ISC_R_FAILURE);
00790         }
00791         if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
00792                 return (ISC_R_RANGE);
00793 
00794         *low = (in_port_t)port_low;
00795         *high = (in_port_t)port_high;
00796 
00797         return (ISC_R_SUCCESS);
00798 }
00799 #else /* !HAVE_SYSCTLBYNAME */
00800 static isc_result_t
00801 getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
00802         int mib_lo4[4] = SYSCTL_V4PORTRANGE_LOW;
00803         int mib_hi4[4] = SYSCTL_V4PORTRANGE_HIGH;
00804         int mib_lo6[4] = SYSCTL_V6PORTRANGE_LOW;
00805         int mib_hi6[4] = SYSCTL_V6PORTRANGE_HIGH;
00806         int *mib_lo, *mib_hi, miblen;
00807         int port_low, port_high;
00808         size_t portlen;
00809 
00810         if (af == AF_INET) {
00811                 mib_lo = mib_lo4;
00812                 mib_hi = mib_hi4;
00813                 miblen = sizeof(mib_lo4) / sizeof(mib_lo4[0]);
00814         } else {
00815                 mib_lo = mib_lo6;
00816                 mib_hi = mib_hi6;
00817                 miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]);
00818         }
00819 
00820         portlen = sizeof(port_low);
00821         if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) {
00822                 return (ISC_R_FAILURE);
00823         }
00824 
00825         portlen = sizeof(port_high);
00826         if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) {
00827                 return (ISC_R_FAILURE);
00828         }
00829 
00830         if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
00831                 return (ISC_R_RANGE);
00832 
00833         *low = (in_port_t) port_low;
00834         *high = (in_port_t) port_high;
00835 
00836         return (ISC_R_SUCCESS);
00837 }
00838 #endif /* HAVE_SYSCTLBYNAME */
00839 #endif /* USE_SYSCTL_PORTRANGE */
00840 
00841 isc_result_t
00842 isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
00843         int result = ISC_R_FAILURE;
00844 #if !defined(USE_SYSCTL_PORTRANGE) && defined(__linux)
00845         FILE *fp;
00846 #endif
00847 
00848         REQUIRE(low != NULL && high != NULL);
00849 
00850 #if defined(USE_SYSCTL_PORTRANGE)
00851         result = getudpportrange_sysctl(af, low, high);
00852 #elif defined(__linux)
00853 
00854         UNUSED(af);
00855 
00856         /*
00857          * Linux local ports are address family agnostic.
00858          */
00859         fp = fopen("/proc/sys/net/ipv4/ip_local_port_range", "r");
00860         if (fp != NULL) {
00861                 int n;
00862                 unsigned int l, h;
00863 
00864                 n = fscanf(fp, "%u %u", &l, &h);
00865                 if (n == 2 && (l & ~0xffff) == 0 && (h & ~0xffff) == 0) {
00866                         *low = l;
00867                         *high = h;
00868                         result = ISC_R_SUCCESS;
00869                 }
00870                 fclose(fp);
00871         }
00872 #else
00873         UNUSED(af);
00874 #endif
00875 
00876         if (result != ISC_R_SUCCESS) {
00877                 *low = ISC_NET_PORTRANGELOW;
00878                 *high = ISC_NET_PORTRANGEHIGH;
00879         }
00880 
00881         return (ISC_R_SUCCESS); /* we currently never fail in this function */
00882 }
00883 
00884 void
00885 isc_net_disableipv4(void) {
00886         initialize();
00887         if (ipv4_result == ISC_R_SUCCESS)
00888                 ipv4_result = ISC_R_DISABLED;
00889 }
00890 
00891 void
00892 isc_net_disableipv6(void) {
00893         initialize();
00894         if (ipv6_result == ISC_R_SUCCESS)
00895                 ipv6_result = ISC_R_DISABLED;
00896 }
00897 
00898 void
00899 isc_net_enableipv4(void) {
00900         initialize();
00901         if (ipv4_result == ISC_R_DISABLED)
00902                 ipv4_result = ISC_R_SUCCESS;
00903 }
00904 
00905 void
00906 isc_net_enableipv6(void) {
00907         initialize();
00908         if (ipv6_result == ISC_R_DISABLED)
00909                 ipv6_result = ISC_R_SUCCESS;
00910 }

Generated on Tue Apr 28 17:41:05 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha