]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
ntp_io.c:
authorFrank Kardel <kardel@ntp.org>
Fri, 22 Sep 2006 22:58:27 +0000 (22:58 +0000)
committerFrank Kardel <kardel@ntp.org>
Fri, 22 Sep 2006 22:58:27 +0000 (22:58 +0000)
  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

configure.ac
ntpd/ntp_io.c

index 6c4f912b10f62e007176ca00482ba0d6fcf214c1..6a6496a8840e8a1ac02b1c05c188cf088b6060d0 100644 (file)
@@ -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
index eb7a2158e844e82bf77c8ee1c9b1bd52edde6a1e..8027dd9b950f9a4a9693e8c86b828d4dff5a0958 100644 (file)
@@ -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)));