From: Frank Kardel Date: Fri, 22 Sep 2006 22:58:27 +0000 (+0000) Subject: ntp_io.c: X-Git-Tag: NTP_4_2_3P50~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d624959ba3b12834d8941b189fa11fca47928a94;p=thirdparty%2Fntp.git ntp_io.c: add autoconfig enabled code to temporarily set SO_REUSEADDR on wildcard sockets when binding interface addresses. So OSes need this configure.ac: add configtest for REUSEADDR enable on wildcard sockets to allow binding to interface addresses bk: 45146a93QzfDVyUkM_jz91Pu2h3Jsw --- diff --git a/configure.ac b/configure.ac index 6c4f912b1..6a6496a88 100644 --- a/configure.ac +++ b/configure.ac @@ -1458,6 +1458,19 @@ case "$ac_cv_os_routeupdates" in yes) AC_DEFINE(OS_MISSES_SPECIFIC_ROUTE_UPDATES, 1, [need to recreate sockets on changed routing?]) ;; esac +AC_CACHE_CHECK(if the OS needs the wildcard socket set to REUSEADDR for binding interface addresses, ac_cv_os_wildcardreuse, +[[case "$host" in + *-*-linux*) + ans=yes + ;; + *) ans=no + ;; +esac +ac_cv_os_wildcardreuse=$ans]]) +case "$ac_cv_os_wildcardreuse" in + yes) AC_DEFINE(OS_NEEDS_REUSEADDR_FOR_IFADDRBIND, 1, [wildcard socket needs to set REUSEADDR when binding to interface addresses]) ;; +esac + ntp_warning='GRONK' AC_MSG_CHECKING(if we'll use clock_settime or settimeofday or stime) case "$ac_cv_func_clock_settime$ac_cv_func_settimeofday$ac_cv_func_stime" in diff --git a/ntpd/ntp_io.c b/ntpd/ntp_io.c index eb7a2158e..8027dd9b9 100644 --- a/ntpd/ntp_io.c +++ b/ntpd/ntp_io.c @@ -1044,15 +1044,15 @@ interface_update(interface_receiver_t receiver, void *data) * a wildcard address */ static int -is_wildcard_ifaddr(struct interface *itf) +is_wildcard_addr(struct sockaddr_storage *sas) { - if (itf->family == AF_INET && - ((struct sockaddr_in*)&itf->sin)->sin_addr.s_addr == htonl(INADDR_ANY)) + if (sas->ss_family == AF_INET && + ((struct sockaddr_in*)sas)->sin_addr.s_addr == htonl(INADDR_ANY)) return 1; #ifdef INCLUDE_IPV6_SUPPORT - if (itf->family == AF_INET6 && - memcmp(&((struct sockaddr_in6*)&itf->sin)->sin6_addr, &in6addr_any, + if (sas->ss_family == AF_INET6 && + memcmp(&((struct sockaddr_in6*)sas)->sin6_addr, &in6addr_any, sizeof(in6addr_any) == 0)) return 1; #endif @@ -1060,6 +1060,47 @@ is_wildcard_ifaddr(struct interface *itf) return 0; } +/* + * enable/disable re-use of wildcard address socket + */ +static void +set_wildcard_reuse(int family, int on) +{ + int onvalue = 1; + int offvalue = 0; + int *onoff; + SOCKET fd = INVALID_SOCKET; + + onoff = on ? &onvalue : &offvalue; + + switch (family) { + case AF_INET: + if (any_interface) { + fd = any_interface->fd; + } + break; + +#ifdef INCLUDE_IPV6_SUPPORT + case AF_INET6: + if (any6_interface) { + fd = any6_interface->fd; + } + break; +#endif /* !INCLUDE_IPV6_SUPPORT */ + } + + if (fd != INVALID_SOCKET) { + if (setsockopt(fd, SOL_SOCKET, + SO_REUSEADDR, (char *)onoff, + sizeof(*onoff))) { + netsyslog(LOG_ERR, "set_wildcard_reuse: setsockopt(SO_REUSEADDR, %s) failed: %m", *onoff ? "on" : "off"); + } + DPRINTF(4, ("set SO_REUSEADDR to %s on %s\n", *onoff ? "ON" : "OFF", + stoa((family == AF_INET) ? + &any_interface->sin : &any6_interface->sin))); + } +} + /* * update_interface strategy * @@ -1180,7 +1221,7 @@ update_interfaces( * address - some dhcp clients produce that in the * wild */ - if (is_wildcard_ifaddr(&interface)) + if (is_wildcard_addr(&interface.sin)) continue; /* @@ -1941,12 +1982,13 @@ io_multicast_add( set_reuseaddr(1); interface->bfd = INVALID_SOCKET; interface->fd = open_socket(&interface->sin, - INT_MULTICAST, 1, interface); + INT_MULTICAST, 0, interface); if (interface->fd != INVALID_SOCKET) { interface->bfd = INVALID_SOCKET; interface->ignore_packets = ISC_FALSE; + interface->flags |= INT_MCASTIF; (void) strncpy(interface->name, "multicast", sizeof(interface->name)); @@ -2194,6 +2236,7 @@ open_socket( errval == WSAEPFNOSUPPORT) #endif return (INVALID_SOCKET); + msyslog(LOG_ERR, "unexpected error code %d (not PROTONOSUPPORT|AFNOSUPPORT|FPNOSUPPORT) - exiting", errval); exit(1); /*NOTREACHED*/ } @@ -2212,7 +2255,7 @@ open_socket( /* * set SO_REUSEADDR since we will be binding the same port - * number on each interface + * number on each interface according to flag */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, turn_off_reuse ? (char *)&off : (char *)&on, sizeof(on))) @@ -2263,34 +2306,34 @@ open_socket( #endif /* IPV6_BINDV6ONLY */ } +#ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND + /* + * some OSes don't allow bindinf to more specific + * addresses if a wildcard address already bound + * to the port and SO_REUSEADDR is not set + */ + if (!is_wildcard_addr(addr)) { + set_wildcard_reuse(addr->ss_family, 1); + } +#endif + /* * bind the local address. */ - if (bind(fd, (struct sockaddr *)addr, SOCKLEN(addr)) < 0) { - char buff[160]; + errval = bind(fd, (struct sockaddr *)addr, SOCKLEN(addr)); - if(addr->ss_family == AF_INET) - sprintf(buff, - "bind() fd %d, family %d, port %d, addr %s, in_classd=%d flags=0x%x fails: %%m", - fd, addr->ss_family, (int)ntohs(((struct sockaddr_in*)addr)->sin_port), - stoa(addr), - IN_CLASSD(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr)), flags); -#ifdef INCLUDE_IPV6_SUPPORT - else if(addr->ss_family == AF_INET6) - sprintf(buff, - "bind() fd %d, family %d, port %d, scope %d, addr %s, in6_is_addr_multicast=%d flags=%d fails: %%m", - fd, addr->ss_family, (int)ntohs(((struct sockaddr_in6*)addr)->sin6_port), -# ifdef ISC_PLATFORM_HAVESCOPEID - ((struct sockaddr_in6*)addr)->sin6_scope_id -# else - -1 -# endif - , stoa(addr), - IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr), flags); +#ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND + /* + * some OSes don't allow binding to more specific + * addresses if a wildcard address already bound + * to the port and REUSE_ADDR is not set + */ + if (!is_wildcard_addr(addr)) { + set_wildcard_reuse(addr->ss_family, 0); + } #endif - else - return INVALID_SOCKET; + if (errval < 0) { /* * Don't log this under all conditions */ @@ -2298,12 +2341,31 @@ open_socket( #ifdef DEBUG || debug > 1 #endif - ) - netsyslog(LOG_ERR, buff); + ) { + if (addr->ss_family == AF_INET) + netsyslog(LOG_ERR, + "bind() fd %d, family %d, port %d, addr %s, in_classd=%d flags=0x%x fails: %m", + fd, addr->ss_family, (int)ntohs(((struct sockaddr_in*)addr)->sin_port), + stoa(addr), + IN_CLASSD(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr)), flags); +#ifdef INCLUDE_IPV6_SUPPORT + else if (addr->ss_family == AF_INET6) + netsyslog(LOG_ERR, + "bind() fd %d, family %d, port %d, scope %d, addr %s, in6_is_addr_multicast=%d flags=%d fails: %m", + fd, addr->ss_family, (int)ntohs(((struct sockaddr_in6*)addr)->sin6_port), +# ifdef ISC_PLATFORM_HAVESCOPEID + ((struct sockaddr_in6*)addr)->sin6_scope_id +# else + -1 +# endif + , stoa(addr), + IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr), flags); +#endif + } closesocket(fd); - - return (INVALID_SOCKET); + + return INVALID_SOCKET; } #ifdef HAVE_TIMESTAMP @@ -2340,20 +2402,6 @@ open_socket( add_addr_to_list(addr, interf); - /* - * Turn off the SO_REUSEADDR socket option. It apparently - * causes heartburn on systems with multicast IP installed. - * On normal systems it only gets looked at when the address - * is being bound anyway.. - */ - if (turn_off_reuse) - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - (char *)&off, sizeof(off))) - { - netsyslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails on address %s: %m", - stoa(addr)); - } - #if !defined(SYS_WINNT) && !defined(VMS) DPRINTF(4, ("flags for fd %d: 0x%x\n", fd, fcntl(fd, F_GETFL, 0)));