]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 1184] ntpd is deaf when restricted to second IP on the same net
authorDave Hart <hart@ntp.org>
Mon, 11 May 2009 19:01:24 +0000 (19:01 +0000)
committerDave Hart <hart@ntp.org>
Mon, 11 May 2009 19:01:24 +0000 (19:01 +0000)
bk: 4a087604u85i8inR912rzAxqc-5CoQ

ChangeLog
include/ntp.h
ntpd/ntp_io.c

index 5f8e3948c8084af9e730f2e212679a2694ba1608..2ef770947c134307400d3ea6cbe835552cd336d8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,5 @@
 * [Bug 1180] ntpd won't start with more than ~1000 interfaces
+* [Bug 1184] ntpd is deaf when restricted to second IP on the same net
 * Stale leapsecond file fixes from Dave Mills.
 (4.2.5p173) 2009/05/08 Released by Harlan Stenn <stenn@ntp.org>
 * Include (4.2.4p7-RC6)
index 4b9691906e25e11e07ea890d0730565e255cb23e..333a1d2163762dc9f709b53b7aa6d0da76b0f8a6 100644 (file)
@@ -531,15 +531,16 @@ struct peer {
 
 #define SOCKCMP(sock1, sock2) \
        (((struct sockaddr_storage *)sock1)->ss_family \
-           == ((struct sockaddr_storage *)sock2)->ss_family ? \
-       ((struct sockaddr_storage *)sock1)->ss_family == AF_INET ? \
-       memcmp(&((struct sockaddr_in *)sock1)->sin_addr, \
-           &((struct sockaddr_in *)sock2)->sin_addr, \
-           sizeof(struct in_addr)) == 0 : \
-       memcmp(&((struct sockaddr_in6 *)sock1)->sin6_addr, \
-           &((struct sockaddr_in6 *)sock2)->sin6_addr, \
-              sizeof(struct in6_addr)) == 0 && SOCKSCOPE(sock1, sock2) : \
-       0)
+        == ((struct sockaddr_storage *)sock2)->ss_family \
+               ? (((struct sockaddr_storage *)sock1)->ss_family == AF_INET \
+                       ? (memcmp(&((struct sockaddr_in *)sock1)->sin_addr, \
+                                 &((struct sockaddr_in *)sock2)->sin_addr, \
+                                 sizeof(struct in_addr)) == 0) \
+                       : (memcmp(&((struct sockaddr_in6 *)sock1)->sin6_addr, \
+                                 &((struct sockaddr_in6 *)sock2)->sin6_addr, \
+                                 sizeof(struct in6_addr)) == 0) \
+                         && SOCKSCOPE(sock1, sock2)) \
+               : 0)
 
 #define SOCKNUL(sock1) \
        (((struct sockaddr_storage *)sock1)->ss_family == AF_INET ? \
index 133af61544f9cff2c6d54c3a371b0045d4125927..90d1ce48ef03e8d6c3c98ab03dabb0495e536573 100644 (file)
@@ -300,11 +300,13 @@ static void       add_addr_to_list        (struct sockaddr_storage *, struct interface *);
 static void    delete_addr_from_list   (struct sockaddr_storage *);
 static void    delete_interface_from_list      (struct interface *);
 static struct interface *find_addr_in_list     (struct sockaddr_storage *);
+static struct interface *find_samenet_addr_in_list (struct sockaddr_storage *);
 static struct interface *find_flagged_addr_in_list (struct sockaddr_storage *, int);
 static void    create_wildcards        (u_short);
 static isc_boolean_t   address_okay    (isc_interface_t *);
 static void            convert_isc_if          (isc_interface_t *, struct interface *, u_short);
 static struct interface *getinterface  (struct sockaddr_storage *, int);
+static struct interface *getsamenetinterface   (struct sockaddr_storage *, int);
 static struct interface *findlocalinterface    (struct sockaddr_storage *, int, int);
 static struct interface *findlocalcastinterface        (struct sockaddr_storage *, int);
 
@@ -3480,11 +3482,7 @@ findlocalinterface(
                          (char *)&on, sizeof(on));
 
        rtn = connect(s, (struct sockaddr *)&saddr, SOCKLEN(&saddr));
-#ifndef SYS_WINNT
-       if (rtn < 0)
-#else
        if (rtn == SOCKET_ERROR)
-#endif
        {
                closesocket(s);
                return NULL;
@@ -3492,31 +3490,25 @@ findlocalinterface(
 
        rtn = getsockname(s, (struct sockaddr *)&saddr, &saddrlen);
        closesocket(s);
-#ifndef SYS_WINNT
-       if (rtn < 0)
-#else
        if (rtn == SOCKET_ERROR)
-#endif
                return NULL;
 
        DPRINTF(4, ("findlocalinterface: kernel maps %s to %s\n", stoa(addr), stoa(&saddr)));
        
        iface = getinterface(&saddr, flags);
+       if (NULL == iface)
+               iface = getsamenetinterface(&saddr, flags);
 
-       /* Don't both with ignore interfaces */
-       if (iface != NULL && iface->ignore_packets == ISC_TRUE)
-       {
-               return NULL;
-       }
-       else
-       {
-               return iface;
-       }
+       /* Don't return an interface which will ignore replies */
+       if (NULL != iface && iface->ignore_packets)
+               iface = NULL;
+
+       return iface;
 }
 
 /*
  * fetch an interface structure the matches the
- * address is has the given flags not set
+ * address is has the given flags NOT set
  */
 static struct interface *
 getinterface(struct sockaddr_storage *addr, int flags)
@@ -3533,6 +3525,23 @@ getinterface(struct sockaddr_storage *addr, int flags)
        }
 }
 
+/*
+ * fetch an interface structure with a local address on the same subnet
+ * as addr which has the given flags NOT set
+ */
+static struct interface *
+getsamenetinterface(struct sockaddr_storage *addr, int flags)
+{
+       struct interface *iface;
+
+       iface = find_samenet_addr_in_list(addr);
+
+       if (NULL != iface && iface->flags & flags)
+               iface = NULL;
+
+       return iface;
+}
+
 /*
  * findlocalcastinterface - find local *cast interface index corresponding to address
  * depending on the flags passed
@@ -3864,8 +3873,12 @@ kill_asyncio(int startfd)
  * Add and delete functions for the list of open sockets
  */
 static void
-add_fd_to_list(SOCKET fd, enum desc_type type) {
-       vsock_t *lsock = (vsock_t *)emalloc(sizeof(vsock_t));
+add_fd_to_list(
+       SOCKET fd,
+       enum desc_type type
+       )
+{
+       vsock_t *lsock = emalloc(sizeof(*lsock));
 
        lsock->fd = fd;
        lsock->type = type;
@@ -3890,8 +3903,10 @@ add_fd_to_list(SOCKET fd, enum desc_type type) {
 }
 
 static void
-close_and_delete_fd_from_list(SOCKET fd) {
-
+close_and_delete_fd_from_list(
+       SOCKET fd
+       ) 
+{
        vsock_t *next;
        vsock_t *lsock = ISC_LIST_HEAD(fd_list);
 
@@ -3939,13 +3954,19 @@ close_and_delete_fd_from_list(SOCKET fd) {
 }
 
 static void
-add_addr_to_list(struct sockaddr_storage *addr, struct interface *interface){
+add_addr_to_list(
+       struct sockaddr_storage *addr,
+       struct interface *interface
+       )
+{
+       remaddr_t *laddr;
+
 #ifdef DEBUG
        if (find_addr_in_list(addr) == NULL) {
 #endif
                /* not there yet - add to list */
-               remaddr_t *laddr = (remaddr_t *)emalloc(sizeof(remaddr_t));
-               memcpy(&laddr->addr, addr, sizeof(struct sockaddr_storage));
+               laddr = emalloc(sizeof(*laddr));
+               memcpy(&laddr->addr, addr, sizeof(laddr->addr));
                laddr->interface = interface;
                
                ISC_LIST_APPEND(remoteaddr_list, laddr, link);
@@ -3954,15 +3975,18 @@ add_addr_to_list(struct sockaddr_storage *addr, struct interface *interface){
                            stoa(addr)));
 #ifdef DEBUG
        } else {
-               DPRINTF(4, ("WARNING: Attempt to add duplicate addr %s to address list\n",
+               DPRINTF(4, ("WARNING: Attempt to add duplicate addr "
+                           "%s to address list\n",
                            stoa(addr)));
        }
 #endif
 }
 
 static void
-delete_addr_from_list(struct sockaddr_storage *addr) {
-
+delete_addr_from_list(
+       struct sockaddr_storage *addr
+       ) 
+{
        remaddr_t *next;
        remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list);
 
@@ -3980,7 +4004,10 @@ delete_addr_from_list(struct sockaddr_storage *addr) {
 }
 
 static void
-delete_interface_from_list(struct interface *iface) {
+delete_interface_from_list(
+       struct interface *iface
+       )
+{
        remaddr_t *next;
        remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list);
 
@@ -3997,8 +4024,10 @@ delete_interface_from_list(struct interface *iface) {
 }
 
 static struct interface *
-find_addr_in_list(struct sockaddr_storage *addr) {
-
+find_addr_in_list(
+       struct sockaddr_storage *addr
+       ) 
+{
        remaddr_t *next;
        remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list);
        DPRINTF(4, ("Searching for addr %s in list of addresses - ",
@@ -4006,15 +4035,115 @@ find_addr_in_list(struct sockaddr_storage *addr) {
 
        while(laddr != NULL) {
                next = ISC_LIST_NEXT(laddr, link);
+
                if(SOCKCMP(&laddr->addr, addr)) {
                        DPRINTF(4, ("FOUND\n"));
                        return laddr->interface;
                }
-               else
-                       laddr = next;
+               
+               laddr = next;
        }
+
        DPRINTF(4, ("NOT FOUND\n"));
-       return NULL; /* Not found */
+       return NULL;
+}
+
+static inline isc_boolean_t
+same_network_v4(
+       struct sockaddr_in *addr1,
+       struct sockaddr_in *mask,
+       struct sockaddr_in *addr2
+       )
+{
+       return (addr1->sin_addr.s_addr & mask->sin_addr.s_addr)
+              == (addr2->sin_addr.s_addr & mask->sin_addr.s_addr);
+}
+
+#ifdef INCLUDE_IPV6_SUPPORT
+static inline isc_boolean_t
+same_network_v6(
+       struct sockaddr_in6 *addr1,
+       struct sockaddr_in6 *mask,
+       struct sockaddr_in6 *addr2
+       )
+{
+       int i;
+
+       for (i = 0; 
+            i < sizeof(addr1->sin6_addr.s6_addr) / 
+                sizeof(addr1->sin6_addr.s6_addr[0]);
+            i++)
+
+               if ((addr1->sin6_addr.s6_addr[i] &
+                    mask->sin6_addr.s6_addr[i]) 
+                   !=
+                   (addr2->sin6_addr.s6_addr[i] &
+                    mask->sin6_addr.s6_addr[i]))
+
+                       return ISC_FALSE;
+
+       return ISC_TRUE;
+}
+#endif /* INCLUDE_IPV6_SUPPORT */
+
+static isc_boolean_t
+same_network(
+       struct sockaddr_storage *addr1,
+       struct sockaddr_storage *mask,
+       struct sockaddr_storage *addr2
+       )
+{
+       if (addr1->ss_family != addr2->ss_family)
+               return ISC_FALSE;
+
+       if (AF_INET == addr1->ss_family) {
+               return same_network_v4(
+                               (struct sockaddr_in *)addr1,
+                               (struct sockaddr_in *)mask,
+                               (struct sockaddr_in *)addr2);
+       }
+#ifdef INCLUDE_IPV6_SUPPORT
+       else if (AF_INET6 == addr1->ss_family) {
+               return same_network_v6(
+                               (struct sockaddr_in6 *)addr1,
+                               (struct sockaddr_in6 *)mask,
+                               (struct sockaddr_in6 *)addr2);
+       }
+#endif
+       else
+               return ISC_FALSE;
+}
+
+/*
+ * Find an address in the list on the same network as addr
+ */
+static struct interface *
+find_samenet_addr_in_list(
+       struct sockaddr_storage *addr
+       ) 
+{
+       remaddr_t *next;
+       remaddr_t *laddr;
+
+       DPRINTF(4, ("Searching for addr with same subnet as %s in "
+                   "list of addresses - ",
+                   stoa(addr)));
+
+       for (laddr = ISC_LIST_HEAD(remoteaddr_list);
+            NULL != laddr;
+            laddr = next)
+       {
+               next = ISC_LIST_NEXT(laddr, link);
+
+               if (same_network(&laddr->addr, &laddr->interface->mask,
+                                addr)) {
+                       DPRINTF(4, ("FOUND\n"));
+                       return laddr->interface;
+               }
+       }
+
+       DPRINTF(4, ("NOT FOUND\n"));
+       return NULL;
 }
 
 /*