00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00051
00052
00053
00054
00055
00056
00057
00058
00059 #ifndef ISC_NET_PORTRANGELOW
00060 #define ISC_NET_PORTRANGELOW 1024
00061 #endif
00062 #ifndef ISC_NET_PORTRANGEHIGH
00063 #define ISC_NET_PORTRANGEHIGH 65535
00064 #endif
00065
00066 #ifdef HAVE_SYSCTLBYNAME
00067
00068
00069
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
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
00096 #define SYSCTL_V6PORTRANGE_LOW SYSCTL_V4PORTRANGE_LOW
00097 #define SYSCTL_V6PORTRANGE_HIGH SYSCTL_V4PORTRANGE_HIGH
00098 #endif
00099
00100 #endif
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
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
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
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
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
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
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
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
00382 #endif
00383 #endif
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
00420
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
00436
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
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
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
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
00664
00665 #ifdef ISC_NET_BSD44MSGHDR
00666
00667 #ifndef ISC_CMSG_IP_TOS
00668 #ifdef __APPLE__
00669 #define ISC_CMSG_IP_TOS 0
00670 #else
00671 #define ISC_CMSG_IP_TOS 1
00672 #endif
00673 #endif
00674
00675 #if ISC_CMSG_IP_TOS
00676 if (cmsgsend(s, IPPROTO_IP, IP_TOS, res0))
00677 dscp_result |= ISC_NET_DSCPPKTV4;
00678 #endif
00679
00680 #endif
00681
00682 freeaddrinfo(res0);
00683 close(s);
00684
00685 #endif
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
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
00735
00736 #ifdef ISC_NET_BSD44MSGHDR
00737 if (cmsgsend(s, IPPROTO_IPV6, IPV6_TCLASS, res0))
00738 dscp_result |= ISC_NET_DSCPPKTV6;
00739 #endif
00740
00741 freeaddrinfo(res0);
00742 close(s);
00743
00744 #endif
00745 #endif
00746 #endif
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
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
00839 #endif
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
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);
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 }