]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
ntp_io.c:
authorFrank Kardel <kardel@ntp.org>
Sat, 14 Oct 2006 08:51:43 +0000 (08:51 +0000)
committerFrank Kardel <kardel@ntp.org>
Sat, 14 Oct 2006 08:51:43 +0000 (08:51 +0000)
  Bug #715 (& dupe 723):
  findlocalinterface() in update_interface can be replaced by
  a simple address to interface lookup. This avoids tripping
  over the Linux strategy to return the localhost address
  when attempting to send to an IPv6 address of a local interface.
  Additionally:
    synchronize debug output with reality
    avoid adding duplicate address entries to the address list
    declare more functions static to reduce name space pollution

bk: 4530a51fP3_h1Po4dNHAbynhQE-amQ

ntpd/ntp_io.c

index 4057b4df12c05651519f77dfdfec920d4b8459d6..c204020d869aeb6c1e67bf922c459cc91edac001 100644 (file)
@@ -253,15 +253,16 @@ ISC_LIST(struct interface)     inter_list;
 static struct interface *wildipv4 = NULL;
 static struct interface *wildipv6 = NULL;
 
-void   add_fd_to_list  P((SOCKET, enum desc_type));
-void   close_and_delete_fd_from_list   P((SOCKET));
-void   add_addr_to_list        P((struct sockaddr_storage *, struct interface *));
-void   delete_addr_from_list   P((struct sockaddr_storage *));
-struct interface *find_addr_in_list    P((struct sockaddr_storage *));
-struct interface *find_flagged_addr_in_list P((struct sockaddr_storage *, int));
-static void create_wildcards   P((u_short));
-isc_boolean_t address_okay     P((isc_interface_t *));
-void   convert_isc_if          P((isc_interface_t *, struct interface *, u_short));
+static void    add_fd_to_list  P((SOCKET, enum desc_type));
+static void    close_and_delete_fd_from_list   P((SOCKET));
+static void    add_addr_to_list        P((struct sockaddr_storage *, struct interface *));
+static void    delete_addr_from_list   P((struct sockaddr_storage *));
+static struct interface *find_addr_in_list     P((struct sockaddr_storage *));
+static struct interface *find_flagged_addr_in_list P((struct sockaddr_storage *, int));
+static void    create_wildcards        P((u_short));
+static isc_boolean_t   address_okay    P((isc_interface_t *));
+static void            convert_isc_if          P((isc_interface_t *, struct interface *, u_short));
+static struct interface *getinterface  P((struct sockaddr_storage *));
 static struct interface *findlocalinterface    P((struct sockaddr_storage *));
 static struct interface *findlocalcastinterface        P((struct sockaddr_storage *, int));
 
@@ -815,7 +816,7 @@ list_if_listening(struct interface *interface, u_short port)
                "Enabled": "Disabled");
 }
 
-void
+static void
 create_wildcards(u_short port) {
        isc_boolean_t okipv4 = ISC_TRUE;
        /*
@@ -852,6 +853,8 @@ create_wildcards(u_short port) {
                if (interface->fd != INVALID_SOCKET) {
                        wildipv4 = interface;
                        any_interface = interface;
+                       
+                       add_addr_to_list(&interface->sin, interface);
                        add_interface(interface);
                        list_if_listening(interface, port);
                } else {
@@ -887,6 +890,7 @@ create_wildcards(u_short port) {
                if (interface->fd != INVALID_SOCKET) {
                        wildipv6 = interface;
                        any6_interface = interface;
+                       add_addr_to_list(&interface->sin, interface);
                        add_interface(interface);
                        list_if_listening(interface, port);
                } else {
@@ -899,7 +903,7 @@ create_wildcards(u_short port) {
 }
 
 
-isc_boolean_t
+static isc_boolean_t
 address_okay(isc_interface_t *isc_if) {
 
        DPRINTF(4, ("address_okay: listen Virtual: %d, IF name: %s, Up Flag: %d\n", 
@@ -936,7 +940,7 @@ address_okay(isc_interface_t *isc_if) {
        return (ISC_TRUE);
 }
 
-void
+static void
 convert_isc_if(isc_interface_t *isc_if, struct interface *itf, u_short port) {
        itf->scopeid = 0;
        itf->family = (short) isc_if->af;
@@ -1236,7 +1240,7 @@ update_interfaces(
                 * with the appropriate socket (our name space is
                 * (ip-address) - NOT (interface name, ip-address))
                 */
-               iface = findlocalinterface(&interface.sin);
+               iface = getinterface(&interface.sin);
                
                if (iface && refresh_interface(iface)) 
                {
@@ -1457,6 +1461,7 @@ create_interface(
        /*
         * put into our interface list
         */
+       add_addr_to_list(&interface->sin, interface);
        add_interface(interface);
 
        DPRINT_INTERFACE(2, (interface, "created ", "\n"));
@@ -2001,6 +2006,7 @@ io_multicast_add(
                ((struct sockaddr_in*)&interface->mask)->sin_addr.s_addr =
                                                htonl(~(u_int32)0);
                DPRINT_INTERFACE(2, (interface, "multicast add ", "\n"));
+               add_addr_to_list(&interface->sin, interface);
                add_interface(interface);
                list_if_listening(interface, NTP_PORT);
        }
@@ -2407,8 +2413,6 @@ open_socket(
 
        add_fd_to_list(fd, FD_TYPE_SOCKET);
 
-       add_addr_to_list(addr, interf);
-
 #if !defined(SYS_WINNT) && !defined(VMS)
        DPRINTF(4, ("flags for fd %d: 0x%x\n", fd,
                    fcntl(fd, F_GETFL, 0)));
@@ -3135,14 +3139,13 @@ findinterface(
  * logic in ntpd which would be a silly and really unportable thing to do.
  *
  */
-struct interface *
+static struct interface *
 findlocalinterface(
        struct sockaddr_storage *addr
        )
 {
        SOCKET s;
        int rtn;
-       struct interface *interface;
        struct sockaddr_storage saddr;
        GETSOCKNAME_SOCKLEN_TYPE saddrlen = SOCKLEN(addr);
 
@@ -3191,29 +3194,25 @@ findlocalinterface(
 
        DPRINTF(4, ("findlocalinterface: kernel maps %s to %s\n", stoa(addr), stoa(&saddr)));
        
-       for (interface = ISC_LIST_HEAD(inter_list);
-            interface != NULL;
-            interface = ISC_LIST_NEXT(interface, link)) 
-       {
-               if (interface->flags & INT_WILDCARD)
-                       continue;
-         
+       return getinterface(&saddr);
+}
+
+/*
+ * fetch an interface structure the matches the
+ * address is not a wildcard/mcast or ignoring interface
+ */
+static struct interface *
+getinterface(struct sockaddr_storage *addr)
+{
+       struct interface *interface = find_addr_in_list(addr);
+
+       if (interface != NULL) {
+               if (interface->flags & (INT_WILDCARD|INT_MCASTIF))
+                       return NULL;
+               
                /* Don't both with ignore interfaces */
                if (interface->ignore_packets == ISC_TRUE)
-                       continue;
-
-               /*
-                * First look if is the the correct family
-                */
-               if(interface->sin.ss_family != saddr.ss_family)
-                       continue;
-               /*
-                * We match the unicast address only.
-                */
-               if (SOCKCMP(&interface->sin, &saddr))
-               {
-                       break;
-               }
+                       return NULL;
        }
 
        return interface;
@@ -3313,8 +3312,15 @@ findbcastinter(
        DPRINTF(4, ("Finding broadcast interface for addr %s in list of addresses\n",
                    stoa(addr)));
 
+#if 0 /* currently disabled - see comment inside */
        interface = find_flagged_addr_in_list(addr, INT_BCASTOPEN|INT_MCASTOPEN);
        
+       /*
+        * Do nothing right now
+        * Eventually we will find the interface this
+        * way, but until it works properly we just see
+        * which one we got
+        */
 #ifdef DEBUG
        if (interface) {
                DPRINTF(4, ("Found bcastinter index #%d %s\n", interface->ifnum, interface->name));
@@ -3322,29 +3328,23 @@ findbcastinter(
                DPRINTF(4, ("No bcast interface found for %s\n", stoa(addr)));
        }
 #endif
-       /*
-        * Do nothing right now
-        * Eventually we will find the interface this
-        * way, but until it works properly we just see
-        * which one we got
-        */
-/*     if (interface != NULL)
+       if (interface != NULL)
        {
-               return (interface);
+               return interface;
        }
-*/
+#endif
 
        for (interface = ISC_LIST_HEAD(inter_list);
             interface != NULL;
             interface = ISC_LIST_NEXT(interface, link)) 
-         {
+       {
                if (interface->flags & INT_WILDCARD)
                        continue;
-         
+               
                /* Don't bother with ignored interfaces */
                if (interface->ignore_packets == ISC_TRUE)
                        continue;
-
+               
                /*
                 * First look if this is the correct family
                 */
@@ -3355,13 +3355,15 @@ findbcastinter(
                if (interface->flags & INT_LOOPBACK)
                        continue;
 
+#if 0 /* XXX - disable null effect code - kd */
                /* for IPv6 multicast check the address for linklocal */
 #ifdef INCLUDE_IPV6_SUPPORT
                if (interface->sin.ss_family == AF_INET6 &&
-                  (IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6*)&interface->sin)->sin6_addr)))
+                   (IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6*)&interface->sin)->sin6_addr)))
                {
 /*                     continue; */
                }
+#endif
 #endif
                /*
                 * If we are looking to match a multicast address grab it.
@@ -3370,7 +3372,7 @@ findbcastinter(
                 */
                if (addr_ismulticast(addr) == ISC_TRUE && interface->flags & INT_MULTICAST)
                {
-                       return (interface);
+                       break;
                }
 
                /*
@@ -3380,24 +3382,33 @@ findbcastinter(
                 * Sloppy.
                 */
                if(addr->ss_family == AF_INET) {
-                       if (SOCKCMP(&interface->bcast, addr))
-                               return interface;
+                       if (SOCKCMP(&interface->bcast, addr)) {
+                               break;
+                       }
                        if ((NSRCADR(&interface->sin) &
-                               NSRCADR(&interface->mask)) == (NSRCADR(addr) &
-                               NSRCADR(&interface->mask)))
-                               return interface;
+                            NSRCADR(&interface->mask)) == (NSRCADR(addr) &
+                                                           NSRCADR(&interface->mask)))
+                               break;
                }
 #ifdef INCLUDE_IPV6_SUPPORT
                else if(addr->ss_family == AF_INET6) {
-                       if (SOCKCMP(&interface->bcast, addr))
-                               return interface;
-                       if (SOCKCMP(netof(&interface->sin), netof(addr)))
-                               return interface;
+                       if (SOCKCMP(&interface->bcast, addr)) {
+                               break;
+                       }
+                       if (SOCKCMP(netof(&interface->sin), netof(addr))) {
+                               break;
+                       }
                }
 #endif
        }
 #endif /* SIOCGIFCONF */
-       return ANY_INTERFACE_CHOOSE(addr);
+       if (interface == NULL) {
+               DPRINTF(4, ("No bcast interface found for %s\n", stoa(addr)));
+               return ANY_INTERFACE_CHOOSE(addr);
+       } else {
+               DPRINTF(4, ("Found bcastinter index #%d %s\n", interface->ifnum, interface->name));
+               return interface;
+       }
 }
 
 
@@ -3539,7 +3550,7 @@ kill_asyncio(int startfd)
 /*
  * Add and delete functions for the list of open sockets
  */
-void
+static void
 add_fd_to_list(SOCKET fd, enum desc_type type) {
        vsock_t *lsock = (vsock_t *)malloc(sizeof(vsock_t));
        lsock->fd = fd;
@@ -3559,7 +3570,7 @@ add_fd_to_list(SOCKET fd, enum desc_type type) {
 #endif
 }
 
-void
+static void
 close_and_delete_fd_from_list(SOCKET fd) {
 
        vsock_t *next;
@@ -3609,19 +3620,29 @@ close_and_delete_fd_from_list(SOCKET fd) {
        }
 }
 
-void
+static void
 add_addr_to_list(struct sockaddr_storage *addr, struct interface *interface){
-       remaddr_t *laddr = (remaddr_t *)emalloc(sizeof(remaddr_t));
-       memcpy(&laddr->addr, addr, sizeof(struct sockaddr_storage));
-       laddr->interface = interface;
-
-       ISC_LIST_APPEND(remoteaddr_list, laddr, link);
-
-       DPRINTF(4, ("Added addr %s to list of addresses\n",
-                   stoa(addr)));
+#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->interface = interface;
+               
+               ISC_LIST_APPEND(remoteaddr_list, laddr, link);
+               
+               DPRINTF(4, ("Added addr %s to list of addresses\n",
+                           stoa(addr)));
+#ifdef DEBUG
+       } else {
+               DPRINTF(4, ("WARNING: Attempt to add duplicate addr %s to address list\n",
+                           stoa(addr)));
+       }
+#endif
 }
 
-void
+static void
 delete_addr_from_list(struct sockaddr_storage *addr) {
 
        remaddr_t *next;
@@ -3633,38 +3654,39 @@ delete_addr_from_list(struct sockaddr_storage *addr) {
                        ISC_LIST_DEQUEUE_TYPE(remoteaddr_list, laddr, link, remaddr_t);
                        free(laddr);
                        break;
+                       DPRINTF(4, ("Deleted addr %s from list of addresses\n",
+                                   stoa(addr)));
                }
                else
                        laddr = next;
        }
-       DPRINTF(4, ("Deleted addr %s from list of addresses\n",
-                   stoa(addr)));
 }
 
-struct interface *
+static struct interface *
 find_addr_in_list(struct sockaddr_storage *addr) {
 
        remaddr_t *next;
        remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list);
-       DPRINTF(4, ("Finding addr %s in list of addresses\n",
+       DPRINTF(4, ("Searching for addr %s in list of addresses - ",
                    stoa(addr)));
 
        while(laddr != NULL) {
                next = ISC_LIST_NEXT(laddr, link);
                if(SOCKCMP(&laddr->addr, addr)) {
+                       DPRINTF(4, ("FOUND\n"));
                        return laddr->interface;
-                       break;
                }
                else
                        laddr = next;
        }
+       DPRINTF(4, ("NOT FOUND\n"));
        return NULL; /* Not found */
 }
 
 /*
  * Find the given address with the associated flag in the list
  */
-struct interface *
+static struct interface *
 find_flagged_addr_in_list(struct sockaddr_storage *addr, int flag) {
 
        remaddr_t *next;
@@ -3687,6 +3709,10 @@ find_flagged_addr_in_list(struct sockaddr_storage *addr, int flag) {
 #ifdef HAS_ROUTING_SOCKET
 #include <net/route.h>
 
+#ifndef UPDATE_GRACE
+#define UPDATE_GRACE   2       /* wait UPDATE_GRACE seconds before scanning */
+#endif
+
 static void
 process_routing_msgs(struct asyncio_reader *reader)
 {
@@ -3761,7 +3787,7 @@ process_routing_msgs(struct asyncio_reader *reader)
                         * we are keen on new and deleted addresses and if an interface goes up and down or routing changes
                         */
                        DPRINTF(3, ("routing message op = %d: scheduling interface update\n", rtm->rtm_type));
-                       timer_interfacetimeout(current_time);
+                       timer_interfacetimeout(current_time + UPDATE_GRACE);
                        break;
                default:
                        /*