]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 1741] Enable multicast reception on each address (Windows).
authorDave Hart <hart@ntp.org>
Sun, 12 Dec 2010 07:11:37 +0000 (07:11 +0000)
committerDave Hart <hart@ntp.org>
Sun, 12 Dec 2010 07:11:37 +0000 (07:11 +0000)
Minimize local address flip-flopping by avoiding peer_refresh_allinterfaces()
  if nothing has changed in the interface list since the last scan.
Separate handling of scope ID embedded in many in6_addr from ifindex used
  for IPv6 multicasting ioctls.
Add INT_PRIVACY endpt bit flag for IPv6 RFC 4941 privacy addresses.
Enable outbound multicast from only one address per interface in the same
  subnet, and in that case prefer embedded MAC address modified EUI-64 IPv6
  addresses first, then static, and last RFC 4941 privacy addresses.
Use setsockopt(IP[V6]_MULTICAST_IF) before each send to multicast to select
  the local source address, using the correct socket isn't enough.

bk: 4d0475a9Ar3OmzQDf-G6MvbiNEAhbA

21 files changed:
ChangeLog
include/isc/mem.h
include/ntp.h
include/ntp_control.h
include/ntp_io.h
include/ntp_net.h
include/ntp_stdlib.h
include/ntpd.h
lib/isc/include/isc/interfaceiter.h
lib/isc/unix/ifiter_ioctl.c
lib/isc/unix/ifiter_sysctl.c
lib/isc/unix/interfaceiter.c
lib/isc/win32/include/isc/ipv6.h
lib/isc/win32/interfaceiter.c
libntp/socktoa.c
libntp/socktohost.c
ntpd/ntp_control.c
ntpd/ntp_io.c
ntpd/ntp_peer.c
ntpd/ntp_request.c
ntpd/ntpd.c

index ae8d367f7bd0511a12b5989b8b7bd16a84c39724..d52bfca4bae33a797bf5dabad491122827d261da 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,11 +1,23 @@
 ---
 
+* [Bug 1741] Enable multicast reception on each address (Windows).
 * [Bug 1742] Fix a typo in an error message in the "build" script.
 * [Bug 1743] Display timezone offset when showing time for sntp in the
   local timezone.
 * Clean up m4 quoting in configure.ac, *.m4 files, resolving
   intermittent AC_LANG_PROGRAM possibly undefined errors.
 * Clean up the SNTP documentation.
+* Other manycastclient repairs:
+  Separate handling of scope ID embedded in many in6_addr from ifindex
+  used for IPv6 multicasting ioctls.
+  Add INT_PRIVACY endpt bit flag for IPv6 RFC 4941 privacy addresses.
+  Enable outbound multicast from only one address per interface in the
+  same subnet, and in that case prefer embedded MAC address modified
+  EUI-64 IPv6 addresses first, then static, and last RFC 4941 privacy
+  addresses.
+  Use setsockopt(IP[V6]_MULTICAST_IF) before each send to multicast to
+  select the local source address, using the correct socket is not
+  enough.
 
 ---
 (4.2.6p3-RC11) 2010/11/28 Released by Harlan Stenn <stenn@ntp.org>
index e6b0e2236abce609c1d5d89538ca5cf3e4741263..f5cf9ec57fff58f9ff44de7f80e9632965623894 100644 (file)
 #include <ntp_stdlib.h>
 
 
-#define ISC_MEM_UNUSED_ARG(ctx)                ((void)(ctx))
+#define ISC_MEM_UNUSED_ARG(a)          ((void)(a))
 
-#define isc_mem_get(c, cnt)            \
-       (ISC_MEM_UNUSED_ARG(c),         emalloc((cnt)))
 #define isc_mem_allocate(c, cnt)       isc_mem_get(c, cnt)
+#define isc_mem_get(c, cnt)            \
+       ( ISC_MEM_UNUSED_ARG(c),        emalloc(cnt) )
 
 #define isc_mem_reallocate(c, mem, cnt)        \
-       (ISC_MEM_UNUSED_ARG(c),         erealloc((mem), (cnt)))
+       ( ISC_MEM_UNUSED_ARG(c),        erealloc((mem), cnt) )
 
 #define isc_mem_put(c, mem, cnt)       \
-       (ISC_MEM_UNUSED_ARG(cnt),       isc_mem_free(c, (mem)))
+       ( ISC_MEM_UNUSED_ARG(cnt),      isc_mem_free(c, (mem)) )
+
 #define isc_mem_free(c, mem)           \
-       (ISC_MEM_UNUSED_ARG(c),         free((mem)))
+       ( ISC_MEM_UNUSED_ARG(c),        free(mem) )
 
 #define isc_mem_strdup(c, str)         \
-       (ISC_MEM_UNUSED_ARG(c),         estrdup((str)))
+       ( ISC_MEM_UNUSED_ARG(c),        estrdup(str) )
 
 #define isc_mem_attach(src, ptgt)      do { *(ptgt) = (src); } while (0)
-#define isc_mem_detach(c)              ((void)(c))
+#define isc_mem_detach(c)              ISC_MEM_UNUSED_ARG(c)
 #define isc_mem_printallactive(s)      fprintf((s), \
                                        "isc_mem_printallactive() stubbed.\n")
 
index d10a01fffc52b80f07d41a8f23f369c941253e00..2a764147d7bfdd23ecf209242f9392343a0f6ed8 100644 (file)
@@ -200,7 +200,7 @@ struct interface {
        volatile long   received;       /* number of incoming packets */
        long            sent;           /* number of outgoing packets */
        long            notsent;        /* number of send failures */
-       u_int           scopeid;        /* scope for multicasting */
+       u_int           ifindex;        /* for IPV6_MULTICAST_IF */
        isc_boolean_t   ignore_packets; /* listen-read-drop this? */
        struct peer *   peers;          /* list of peers using endpt */
        u_int           peercnt;        /* count of same */
@@ -216,8 +216,9 @@ struct interface {
 #define INT_MULTICAST  0x010   /* can multicast out this interface */
 #define        INT_BCASTOPEN   0x020   /* broadcast socket is open */
 #define INT_MCASTOPEN  0x040   /* multicasting enabled */
-#define INT_WILDCARD   0x080   /* wildcard interface - usually skipped */
+#define INT_WILDCARD   0x080   /* wildcard interface - usually skipped */
 #define INT_MCASTIF    0x100   /* bound directly to MCAST address */
+#define INT_PRIVACY    0x200   /* RFC 4941 IPv6 privacy address */
 
 /*
  * Define flasher bits (tests 1 through 11 in packet procedure)
index f056fdddadbf7f9f5a63ba034bed47f867915cc3..3bca32b6e5b1c00acfbc44862e5bc72ec1a50470 100644 (file)
@@ -18,7 +18,7 @@ struct ntp_control {
 /*
  * Length of the control header, in octets
  */
-#define        CTL_HEADER_LEN          12
+#define        CTL_HEADER_LEN          (offsetof(struct ntp_control, data))
 #define        CTL_MAX_DATA_LEN        468
 
 
index 7d88314ea86dc6b4e5a1b8787fa28b4cc359550d..920fd0d36f7087162584e4e5fb1fda4c24716f69 100644 (file)
 #include <isc/boolean.h>
 #include <isc/netaddr.h>
 
-#if HAVE_NETINET_IN_H && HAVE_NETINET_IP_H
-#include <netinet/in.h>
-# if HAVE_NETINET_IN_SYSTM_H
+#if defined(HAVE_NETINET_IN_H) && defined(HAVE_NETINET_IP_H)
+# include <netinet/in.h>
+# ifdef HAVE_NETINET_IN_SYSTM_H
 #  include <netinet/in_systm.h>
 # endif
-#include <netinet/ip.h>
+# include <netinet/ip.h>
 #endif
 
 /*
index 97e7805ea94d854377a6d90219fab3e6fb895405..d417cea4d3d7ab5887c558cb89164ead027ff006 100644 (file)
@@ -103,6 +103,10 @@ typedef union {
            ? IN_CLASSD(SRCADR(psau))                           \
            : IN6_IS_ADDR_MULTICAST(PSOCK_ADDR6(psau)))
 
+/* v6 is interface ID scope universal, as with MAC-derived addresses */
+#define IS_IID_UNIV(psau)                                      \
+       (!!(0x02 & NSRCADR6(psau)[8]))
+
 #define SIZEOF_INADDR(fam)                                     \
        ((AF_INET == (fam))                                     \
            ? sizeof(struct in_addr)                            \
index 0abc490722f88c7bc9aa86cf3f313d3df2247e6e..1f8e404803c699e2a553693a29774dd60311afa7 100644 (file)
@@ -102,8 +102,8 @@ extern  const char * clockstatstr (int);
 extern sockaddr_u * netof      (sockaddr_u *);
 extern char *  numtoa          (u_int32);
 extern char *  numtohost       (u_int32);
-extern char *  socktoa         (sockaddr_u *);
-extern char *  socktohost      (sockaddr_u *);
+extern char *  socktoa         (const sockaddr_u *);
+extern char *  socktohost      (const sockaddr_u *);
 extern int     octtoint        (const char *, u_long *);
 extern u_long  ranp2           (int);
 extern char *  refnumtoa       (sockaddr_u *);
index 7342889992a36912021a775f1866e426f86c8bb7..9bc541054323c341cbb76076f3ca7592969665ef 100644 (file)
@@ -122,7 +122,7 @@ extern      u_int   sys_tai;
 extern void    init_mon        (void);
 extern void    mon_start       (int);
 extern void    mon_stop        (int);
-extern int     ntp_monitor     (struct recvbuf *, int);
+extern int     ntp_monitor     (struct recvbuf *, int);
 extern  void    ntp_monclearinterface (struct interface *interface);
 
 /* ntp_peer.c */
index 8d04d04f569d7f407b03cd4b4c4decf0047d6de5..544f54b12ad409852f3269a1097e9ccbc441366d 100644 (file)
@@ -56,6 +56,7 @@ struct isc_interface {
        isc_netaddr_t broadcast;        /*&< Broadcast address. */
        isc_netaddr_t dstaddress;       /*%< Destination address (point-to-point only). */
        isc_uint32_t flags;             /*%< Flags; see INTERFACE flags. */
+       unsigned int ifindex;           /*%< Interface index for IP(V6)_MULTICAST_IF. */
 };
 
 /*@{*/
@@ -66,6 +67,7 @@ struct isc_interface {
 #define INTERFACE_F_LOOPBACK           0x00000004U
 #define INTERFACE_F_BROADCAST          0x00000008U
 #define INTERFACE_F_MULTICAST          0x00000010U
+#define INTERFACE_F_PRIVACY            0x00000020U     /* RFC 4941 */
 /*@}*/
 
 /***
index 36ce4c0dd53660f5dcd060e23d2b32b7fa576f26..a69979326883dc1e20f8aa349235fd62896c72fa 100644 (file)
@@ -689,12 +689,8 @@ internal_current6(isc_interfaceiter_t *iter) {
        get_addr(family, &iter->current.address,
                 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
 
-       /*
-        * NTP local change
-        * enable_multicast_if() requires scopeid for setsockopt,
-        * so associate address with their corresponding ifindex.
-        */
-       if (family == AF_INET6)
+       iter->current.ifindex = lifreq.lifr_index;
+       if (isc_netaddr_islinklocal(&iter->current.address))
                isc_netaddr_setzone(&iter->current.address, 
                                    (isc_uint32_t)lifreq.lifr_index);
 
index 7215d9844bcaa2e7f678d6c9147827238bbc69b8..072e3494f756a35b1bd708184abdcd8951c34bf3 100644 (file)
@@ -166,6 +166,7 @@ internal_current(isc_interfaceiter_t *iter) {
 
                memset(&iter->current, 0, sizeof(iter->current));
 
+               iter->current.ifindex = sdl->sdl_index;
                namelen = sdl->sdl_nlen;
                if (namelen > sizeof(iter->current.name) - 1)
                        namelen = sizeof(iter->current.name) - 1;
index 87af69e99f48b0dccec14989a8b8803935980102..3524a02c640ef3a715055e3b9f5c47a0bf7322b5 100644 (file)
@@ -187,7 +187,8 @@ linux_if_inet6_current(isc_interfaceiter_t *iter) {
        char name[IF_NAMESIZE+1];
        char strbuf[ISC_STRERRORSIZE];
        struct in6_addr addr6;
-       int ifindex, prefix, scope, flags;
+       unsigned int ifindex;
+       int prefix, scope, flags;
        struct ifreq ifreq;
        int res;
        unsigned int i;
@@ -253,6 +254,7 @@ linux_if_inet6_current(isc_interfaceiter_t *iter) {
 #endif
 
        isc_netaddr_fromin6(&iter->current.address, &addr6);
+       iter->current.ifindex = ifindex;
        if (isc_netaddr_islinklocal(&iter->current.address)) {
                isc_netaddr_setzone(&iter->current.address,
                                    (isc_uint32_t)ifindex);
index a212a504bda446d4d743f13c2737d203868dcecb..51a6090715bb7cb6e8771aa4957d388e58ce5c75 100644 (file)
@@ -111,14 +111,14 @@ LIBISC_EXTERNAL_DATA extern const struct in6_addr isc_net_in6addrloop;
  */
 #ifndef IN6_IS_ADDR_LINKLOCAL
 #define IN6_IS_ADDR_LINKLOCAL(a)       (\
-(*((u_long *)((a)->s6_addr)    ) == 0xfe) && \
-((*((u_long *)((a)->s6_addr) + 1) & 0xc0) == 0x80))
+       ((a)->s6_addr[0] == 0xfe) && \
+       (((a)->s6_addr[1] & 0xc0) == 0x80))
 #endif
 
 #ifndef IN6_IS_ADDR_SITELOCAL
 #define IN6_IS_ADDR_SITELOCAL(a)       (\
-(*((u_long *)((a)->s6_addr)    ) == 0xfe) && \
-((*((u_long *)((a)->s6_addr) + 1) & 0xc0) == 0xc0))
+       ((a)->s6_addr[0] == 0xfe) && \
+       (((a)->s6_addr[1] & 0xc0) == 0xc0))
 #endif
 
 #endif /* ISC_IPV6_H */
index fe8979b92b1f676e23d595684931f7d76c236c5e..34c9428bcb5ff7b633e75910798ab58944a20b97 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <isc/interfaceiter.h>
 #include <isc/mem.h>
-//#include <isc/netaddr.h>
 #include <isc/result.h>
 #include <isc/string.h>
 #include <isc/strerror.h>
@@ -47,8 +46,6 @@ struct isc_interfaceiter {
        unsigned int            magic;          /* Magic number. */
        /* common fields */
        isc_mem_t               *mctx;
-       struct in6_addr         loop__1;        /* ::1 node-scope localhost */
-       struct in6_addr         loopfe80__1;    /* fe80::1 link-scope localhost */
        isc_interface_t         current;        /* Current interface data. */
        isc_result_t            result;         /* Last result code. */
        /* fields used if GetAdaptersAddresses is available at runtime */
@@ -67,6 +64,8 @@ struct isc_interfaceiter {
        SOCKET_ADDRESS_LIST     *buf6;
        unsigned int            buf6size;       /* Bytes allocated. */
        unsigned int            pos6;           /* buf6 index, counts down */
+       struct in6_addr         loop__1;        /* ::1 node-scope localhost */
+       struct in6_addr         loopfe80__1;    /* fe80::1 link-scope localhost */
 };
 
 typedef ULONG (WINAPI *PGETADAPTERSADDRESSES)(
@@ -77,7 +76,7 @@ typedef ULONG (WINAPI *PGETADAPTERSADDRESSES)(
     PULONG SizePointer
 );
 
-/* static */   isc_boolean_t           use_GAA;
+static isc_boolean_t           use_GAA;
 static isc_boolean_t           use_GAA_determined;
 static HMODULE                 hmod_iphlpapi;
 static PGETADAPTERSADDRESSES   pGAA;
@@ -451,32 +450,44 @@ GAA_find_prefix(isc_interfaceiter_t *iter) {
 
 static isc_result_t
 internal_current_GAA(isc_interfaceiter_t *iter) {
+       IP_ADAPTER_ADDRESSES *adap;
+       IP_ADAPTER_UNICAST_ADDRESS *addr;
        unsigned char prefix_len;
 
+       REQUIRE(iter->ipaaCur != NULL);
        REQUIRE(iter->ipuaCur != NULL);
+       adap = iter->ipaaCur;
+       addr = iter->ipuaCur;
+       if (IpDadStatePreferred != addr->DadState)
+               return (ISC_R_IGNORE);
        memset(&iter->current, 0, sizeof(iter->current));
-       iter->current.af = iter->ipuaCur->Address.lpSockaddr->sa_family;
+       iter->current.af = addr->Address.lpSockaddr->sa_family;
        isc_netaddr_fromsockaddr(&iter->current.address,
-           (isc_sockaddr_t *)iter->ipuaCur->Address.lpSockaddr);
+           (isc_sockaddr_t *)addr->Address.lpSockaddr);
+       if (AF_INET6 == iter->current.af)
+               iter->current.ifindex = adap->Ipv6IfIndex;
        iter->current.name[0] = '\0';
        WideCharToMultiByte(
                CP_ACP, 
                0, 
-               iter->ipaaCur->FriendlyName,
+               adap->FriendlyName,
                -1,
                iter->current.name,
                sizeof(iter->current.name),
                NULL,
                NULL);
        iter->current.name[sizeof(iter->current.name) - 1] = '\0';
-       if (IfOperStatusUp == iter->ipaaCur->OperStatus)
+       if (IfOperStatusUp == adap->OperStatus)
                iter->current.flags |= INTERFACE_F_UP;
-       if ((IP_ADAPTER_NO_MULTICAST & iter->ipaaCur->Flags) == 0)
-               iter->current.flags |= INTERFACE_F_MULTICAST;
-       if (IF_TYPE_PPP == iter->ipaaCur->IfType)
+       if (IF_TYPE_PPP == adap->IfType)
                iter->current.flags |= INTERFACE_F_POINTTOPOINT;
-       else if (IF_TYPE_SOFTWARE_LOOPBACK == iter->ipaaCur->IfType)
+       else if (IF_TYPE_SOFTWARE_LOOPBACK == adap->IfType)
                iter->current.flags |= INTERFACE_F_LOOPBACK;
+       if ((IP_ADAPTER_NO_MULTICAST & adap->Flags) == 0)
+               iter->current.flags |= INTERFACE_F_MULTICAST;
+       if (IpSuffixOriginRandom == addr->SuffixOrigin)
+               iter->current.flags |= INTERFACE_F_PRIVACY;
+
        prefix_len = GAA_find_prefix(iter);
        /* I'm failing to see a broadcast flag via GAA */
        if (AF_INET == iter->current.af && prefix_len < 32 &&
@@ -739,10 +750,12 @@ isc_interfaceiter_next(isc_interfaceiter_t *iter) {
        REQUIRE(use_GAA_determined);
 
        if (use_GAA) {
-               result = internal_next_GAA(iter);
-               if (ISC_R_NOMORE == result)
-                       goto set_result;
-               result = internal_current_GAA(iter);
+               do {
+                       result = internal_next_GAA(iter);
+                       if (ISC_R_NOMORE == result)
+                               goto set_result;
+                       result = internal_current_GAA(iter);
+               } while (ISC_R_IGNORE == result);
                goto set_result;
        }
 
index bd97e6806adf7d4879bdcedf8a03f0dfb0361ba8..62e4537266f0f5577f3e6ca83c627fa7af1ce4dc 100644 (file)
@@ -29,7 +29,7 @@
 
 char *
 socktoa(
-       sockaddr_u *sock
+       const sockaddr_u *sock
        )
 {
        register char *buffer;
index 325eea40da4a33e9c4e0ee79e0b200d9b427c469..05bbdd64344cd57d7f04eb1ae08f482f8e28d12a 100644 (file)
@@ -21,7 +21,7 @@
 
 char *
 socktohost(
-       sockaddr_u *sock
+       const sockaddr_u *sock
        )
 {
        register char *buffer;
index 7ffeacb5a30dec529bc177a40cca1c2d0a6d1a9b..a4d4afefc23059a7e8e2a140613743f124ba8995 100644 (file)
@@ -535,8 +535,6 @@ ctl_error(
        if (res_authenticate && sys_authenticate) {
                int maclen;
 
-               *(u_int32 *)((u_char *)&rpkt + CTL_HEADER_LEN) =
-                   htonl(res_keyid);
                maclen = authencrypt(res_keyid, (u_int32 *)&rpkt,
                                     CTL_HEADER_LEN);
                sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt,
index 5b7b7d86a90eb4413e9b49edae9449f9359ac798..cf253ca9572b069ba42abd452f550450fdb65ed9 100644 (file)
@@ -200,15 +200,14 @@ static    isc_boolean_t   is_anycast              (sockaddr_u *,
  * Not all platforms support multicast
  */
 #ifdef MCAST
-static isc_boolean_t   socket_multicast_enable (endpt *, int,
-                                                sockaddr_u *);
+static isc_boolean_t   socket_multicast_enable (endpt *, sockaddr_u *);
 static isc_boolean_t   socket_multicast_disable(endpt *, sockaddr_u *);
 #endif
 
 #ifdef DEBUG
-static void interface_dump     (struct interface *);
-static void sockaddr_dump      (sockaddr_u *psau);
-static void print_interface    (struct interface *, char *, char *);
+static void interface_dump     (const endpt *);
+static void sockaddr_dump      (const sockaddr_u *);
+static void print_interface    (const endpt *, char *, char *);
 #define DPRINT_INTERFACE(level, args) do { if (debug >= (level)) { print_interface args; } } while (0)
 #else
 #define DPRINT_INTERFACE(level, args) do {} while (0)
@@ -253,8 +252,10 @@ static void init_async_notifications (void);
 
 static int     addr_eqprefix   (const sockaddr_u *, const sockaddr_u *,
                                 int);
+static int     addr_samesubnet (const sockaddr_u *, const sockaddr_u *,
+                                const sockaddr_u *, const sockaddr_u *);
 static int     create_sockets  (u_short);
-static SOCKET  open_socket     (sockaddr_u *, int, int, struct interface *);
+static SOCKET  open_socket     (sockaddr_u *, int, int, endpt *);
 static char *  fdbits          (int, fd_set *);
 static void    set_reuseaddr   (int);
 static isc_boolean_t   socket_broadcast_enable  (struct interface *, SOCKET, sockaddr_u *);
@@ -287,9 +288,6 @@ static void create_wildcards        (u_short);
 static endpt * getinterface            (sockaddr_u *, u_int32);
 static endpt * findlocalinterface      (sockaddr_u *, int, int);
 static endpt * findclosestinterface    (sockaddr_u *, int);
-#ifdef MULTICAST_NONEWSOCKET
-static endpt * findlocalcastinterface  (sockaddr_u *);
-#endif
 #ifdef DEBUG
 static const char *    action_text     (nic_rule_action);
 #endif
@@ -574,7 +572,7 @@ io_open_sockets(void)
  * for debugging use only.
  */
 void
-interface_dump(struct interface *itf)
+interface_dump(const endpt *itf)
 {
        printf("Dumping interface: %p\n", itf);
        printf("fd = %d\n", itf->fd);
@@ -593,7 +591,7 @@ interface_dump(struct interface *itf)
        printf("received = %ld\n", itf->received);
        printf("sent = %ld\n", itf->sent);
        printf("notsent = %ld\n", itf->notsent);
-       printf("scopeid = %u\n", itf->scopeid);
+       printf("ifindex = %u\n", itf->ifindex);
        printf("peercnt = %u\n", itf->peercnt);
        printf("phase = %u\n", itf->phase);
 }
@@ -602,17 +600,16 @@ interface_dump(struct interface *itf)
  * sockaddr_dump - hex dump the start of a sockaddr_u
  */
 static void
-sockaddr_dump(sockaddr_u *psau)
+sockaddr_dump(const sockaddr_u *psau)
 {
        /* Limit the size of the sockaddr_storage hex dump */
        const int maxsize = min(32, sizeof(psau->sa6));
-       u_char *        cp;
+       const u_char *  cp;
        int             i;
 
-       cp = (u_char *)&psau->sa;
+       cp = (const void *)&psau->sa;
 
-       for(i = 0; i < maxsize; i++)
-       {
+       for(i = 0; i < maxsize; i++) {
                printf("%02x", *cp++);
                if (!((i + 1) % 4))
                        printf(" ");
@@ -624,16 +621,16 @@ sockaddr_dump(sockaddr_u *psau)
  * print_interface - helper to output debug information
  */
 static void
-print_interface(struct interface *iface, char *pfx, char *sfx)
+print_interface(const endpt *iface, char *pfx, char *sfx)
 {
-       printf("%sinterface #%d: fd=%d, bfd=%d, name=%s, flags=0x%x, scope=%d, sin=%s",
+       printf("%sinterface #%d: fd=%d, bfd=%d, name=%s, flags=0x%x, ifindex=%u, sin=%s",
               pfx,
               iface->ifnum,
               iface->fd,
               iface->bfd,
               iface->name,
               iface->flags,
-              iface->scopeid,
+              iface->ifindex,
               stoa(&iface->sin));
        if (AF_INET == iface->family) {
                if (iface->flags & INT_BROADCAST)
@@ -737,6 +734,48 @@ addr_eqprefix(
 }
 
 
+static int
+addr_samesubnet(
+       const sockaddr_u *      a,
+       const sockaddr_u *      a_mask,
+       const sockaddr_u *      b,
+       const sockaddr_u *      b_mask
+       )
+{
+       const u_int32 * pa;
+       const u_int32 * pa_limit;
+       const u_int32 * pb;
+       const u_int32 * pm;
+       size_t          loops;
+
+       NTP_REQUIRE(AF(a) == AF(a_mask));
+       NTP_REQUIRE(AF(b) == AF(b_mask));
+       /*
+        * With address and mask families verified to match, comparing
+        * the masks also validates the address's families match.
+        */
+       if (!SOCK_EQ(a_mask, b_mask))
+               return FALSE;
+
+       if (IS_IPV6(a)) {
+               loops = sizeof(NSRCADR6(a)) / sizeof(*pa);
+               pa = (const void *)&NSRCADR6(a);
+               pb = (const void *)&NSRCADR6(b);
+               pm = (const void *)&NSRCADR6(a_mask);
+       } else {
+               loops = sizeof(NSRCADR(a)) / sizeof(*pa);
+               pa = (const void *)&NSRCADR(a);
+               pb = (const void *)&NSRCADR(b);
+               pm = (const void *)&NSRCADR(a_mask);
+       }
+       for (pa_limit = pa + loops; pa < pa_limit; pa++, pb++, pm++)
+               if ((*pa & *pm) != (*pb & *pm))
+                       return FALSE;
+
+       return TRUE;
+}
+
+
 /*
  * Code to tell if we have an IP address
  * If we have then return the sockaddr structure
@@ -885,6 +924,11 @@ add_interface(
        sockaddr_u *    addr;
        int             ep_local;
        int             scan_local;
+       int             same_subnet;
+       int             ep_univ_iid;    /* iface ID from MAC address */
+       int             scan_univ_iid;  /* see RFC 4291 */
+       int             ep_privacy;     /* random local iface ID */
+       int             scan_privacy;   /* see RFC 4941 */
 
        /*
         * Calculate the address hash
@@ -894,20 +938,33 @@ add_interface(
        LINK_SLIST(ep_list, ep, elink);
        ninterfaces++;
        /* the rest is for enabled multicast-capable addresses only */
-       if (ep->ignore_packets || !(INT_MULTICAST & ep->flags))
+       if (ep->ignore_packets || !(INT_MULTICAST & ep->flags) ||
+           INT_LOOPBACK & ep->flags)
                return;
+#ifndef INCLUDE_IPV6_MULTICAST_SUPPORT
+       if (AF_INET6 == ep->family)
+               return;
+#endif
        pmclisthead = (AF_INET == ep->family)
                         ? &mc4_list
                         : &mc6_list;
 
-#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
-       addr = &ep->sin;
-       ep_local = (AF_INET6 == ep->family &&
-                   (IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(addr)) ||
-                    IN6_IS_ADDR_SITELOCAL(PSOCK_ADDR6(addr))));
-#else
-       ep_local = FALSE;
-#endif
+       if (AF_INET6 == ep->family) {
+               ep_local =
+                   IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(&ep->sin)) ||
+                   IN6_IS_ADDR_SITELOCAL(PSOCK_ADDR6(&ep->sin));
+               ep_univ_iid = IS_IID_UNIV(&ep->sin);
+               ep_privacy = !!(INT_PRIVACY & ep->flags);
+       } else {
+               ep_local = FALSE;
+               ep_univ_iid = FALSE;
+               ep_privacy = FALSE;
+       }
+       DPRINTF(4, ("add_interface mcast-capable %s%s%s%s\n",
+                   stoa(&ep->sin),
+                   (ep_local) ? " link/scope-local" : "",
+                   (ep_univ_iid) ? " univ-IID" : "",
+                   (ep_privacy) ? " privacy" : ""));
        /*
         * If we have multiple local addresses on the same network
         * interface, and some are link- or site-local, do not multicast
@@ -915,19 +972,39 @@ add_interface(
         * duplicate manycastclient associations between v6 peers using
         * link-local and global addresses.  link-local can still be
         * chosen using "nic ignore myv6globalprefix::/64".
+        * Similarly, if we have multiple global addresses from the same
+        * prefix on the same network interface, multicast from one,
+        * preferring EUI-64, then static, then least RFC 4941 privacy
+        * addresses.
         */
-       for (scan = *pmclisthead;
-            scan != NULL && (AF_INET6 == ep->family);
-            scan = scan_next) {
-
+       for (scan = *pmclisthead; scan != NULL; scan = scan_next) {
                scan_next = scan->mclink;
+               if (ep->family != scan->family)
+                       continue;
                if (strcmp(ep->name, scan->name))
                        continue;
-               addr = &scan->sin;
-               scan_local =
-                       (IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(addr)) ||
-                        IN6_IS_ADDR_SITELOCAL(PSOCK_ADDR6(addr)));
-               if (ep_local && !scan_local) {
+               same_subnet = addr_samesubnet(&ep->sin, &ep->mask,
+                                             &scan->sin, &scan->mask);
+               if (AF_INET6 == ep->family) {
+                       addr = &scan->sin;
+                       scan_local =
+                           IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(addr)) ||
+                           IN6_IS_ADDR_SITELOCAL(PSOCK_ADDR6(addr));
+                       scan_univ_iid = IS_IID_UNIV(addr);
+                       scan_privacy = !!(INT_PRIVACY & scan->flags);
+               } else {
+                       scan_local = FALSE;
+                       scan_univ_iid = FALSE;
+                       scan_privacy = FALSE;
+               }
+               DPRINTF(4, ("add_interface mcast-capable scan %s%s%s%s\n",
+                           stoa(&scan->sin),
+                           (scan_local) ? " link/scope-local" : "",
+                           (scan_univ_iid) ? " univ-IID" : "",
+                           (scan_privacy) ? " privacy" : ""));
+               if ((ep_local && !scan_local) || (same_subnet && 
+                   ((ep_privacy && !scan_privacy) ||
+                    (!ep_univ_iid && scan_univ_iid)))) {
                        DPRINTF(4, ("did not add %s to %s of IPv6 multicast-capable list which already has %s\n",
                                stoa(&ep->sin),
                                (ep_local)
@@ -936,7 +1013,9 @@ add_interface(
                                stoa(&scan->sin)));
                        return;
                }
-               if (scan_local && !ep_local) {
+               if ((scan_local && !ep_local) || (same_subnet &&
+                   ((scan_privacy && !ep_privacy) ||
+                    (!scan_univ_iid && ep_univ_iid)))) {
                        UNLINK_SLIST(unlinked, *pmclisthead,
                                     scan, mclink, endpt);
                        DPRINTF(4, ("%s %s from IPv6 multicast-capable list to add %s\n",
@@ -1388,7 +1467,7 @@ interface_action(
 static void
 convert_isc_if(
        isc_interface_t *isc_if,
-       struct interface *itf,
+       endpt *itf,
        u_short port
        )
 {
@@ -1397,6 +1476,7 @@ convert_isc_if(
 
        strncpy(itf->name, isc_if->name, sizeof(itf->name));
        itf->name[sizeof(itf->name) - 1] = 0; /* strncpy may not */
+       itf->ifindex = isc_if->ifindex;
        itf->family = (u_short)isc_if->af;
        AF(&itf->sin) = itf->family;
        AF(&itf->mask) = itf->family;
@@ -1420,8 +1500,7 @@ convert_isc_if(
                SET_ADDR6N(&itf->sin, isc_if->address.type.in6);
                SET_ADDR6N(&itf->mask, isc_if->netmask.type.in6);
 
-               itf->scopeid = isc_netaddr_getzone(&isc_if->address);
-               SET_SCOPE(&itf->sin, itf->scopeid);
+               SET_SCOPE(&itf->sin, isc_if->address.zone);
        }
 #endif /* INCLUDE_IPV6_SUPPORT */
 
@@ -1430,13 +1509,15 @@ convert_isc_if(
 
        itf->flags |=
                  ((INTERFACE_F_UP & isc_if->flags)
-                        ? INT_UP : 0)
+                       ? INT_UP : 0)
                | ((INTERFACE_F_LOOPBACK & isc_if->flags) 
-                        ? INT_LOOPBACK : 0)
+                       ? INT_LOOPBACK : 0)
                | ((INTERFACE_F_POINTTOPOINT & isc_if->flags) 
-                        ? INT_PPP : 0)
+                       ? INT_PPP : 0)
                | ((INTERFACE_F_MULTICAST & isc_if->flags) 
-                        ? INT_MULTICAST : 0)
+                       ? INT_MULTICAST : 0)
+               | ((INTERFACE_F_PRIVACY & isc_if->flags)
+                       ? INT_PRIVACY : 0)
                ;
 
        /*
@@ -1668,10 +1749,11 @@ update_interfaces(
        isc_result_t            result;
        isc_interface_t         isc_if;
        int                     new_interface_found;
+       int                     refresh_peers;
        unsigned int            family;
-       struct interface        interface;
-       struct interface *      iface;
-       struct interface *      next;
+       endpt                   enumep;
+       endpt *                 ep;
+       endpt *                 next_ep;
 
        DPRINTF(3, ("update_interfaces(%d)\n", port));
 
@@ -1681,7 +1763,8 @@ update_interfaces(
         * - update those that are found
         */
 
-       new_interface_found = 0;
+       new_interface_found = FALSE;
+       refresh_peers = FALSE;
        iter = NULL;
        result = isc_interfaceiter_create(mctx, &iter);
 
@@ -1713,34 +1796,34 @@ update_interfaces(
                        continue;
 
                /* create prototype */
-               init_interface(&interface);
+               init_interface(&enumep);
 
-               convert_isc_if(&isc_if, &interface, port);
+               convert_isc_if(&isc_if, &enumep, port);
 
                /* 
                 * Check if and how we are going to use the interface.
                 */
-               switch (interface_action(interface.name, &interface.sin,
-                                        interface.flags)) {
+               switch (interface_action(enumep.name, &enumep.sin,
+                                        enumep.flags)) {
 
                case ACTION_IGNORE:
                        continue;
 
                case ACTION_LISTEN:
-                       interface.ignore_packets = ISC_FALSE;
+                       enumep.ignore_packets = ISC_FALSE;
                        break;
 
                case ACTION_DROP:
-                       interface.ignore_packets = ISC_TRUE;
+                       enumep.ignore_packets = ISC_TRUE;
                        break;
                }
 
-               DPRINT_INTERFACE(4, (&interface, "examining ", "\n"));
+               DPRINT_INTERFACE(4, (&enumep, "examining ", "\n"));
 
                 /* interfaces must be UP to be usable */
-               if (!(interface.flags & INT_UP)) {
+               if (!(enumep.flags & INT_UP)) {
                        DPRINTF(4, ("skipping interface %s (%s) - DOWN\n",
-                                   interface.name, stoa(&interface.sin)));
+                                   enumep.name, stoa(&enumep.sin)));
                        continue;
                }
 
@@ -1749,47 +1832,56 @@ update_interfaces(
                 * address - some dhcp clients produce that in the
                 * wild
                 */
-               if (is_wildcard_addr(&interface.sin))
+               if (is_wildcard_addr(&enumep.sin))
                        continue;
 
-               if (is_anycast(&interface.sin, isc_if.name))
+               if (is_anycast(&enumep.sin, isc_if.name))
                        continue;
 
                /*
                 * map to local *address* in order to map all duplicate
-                * interfaces to an interface structure with the
-                * appropriate socket.  Our name space is (ip-address), 
-                * NOT (interface name, ip-address).
+                * interfaces to an endpt structure with the appropriate
+                * socket.  Our name space is (ip-address), NOT
+                * (interface name, ip-address).
                 */
-               iface = getinterface(&interface.sin, INT_WILDCARD);
+               ep = getinterface(&enumep.sin, INT_WILDCARD);
                
-               if (iface != NULL && refresh_interface(iface)) {
+               if (ep != NULL && refresh_interface(ep)) {
                        /*
                         * found existing and up to date interface -
                         * mark present.
                         */
-                       if (iface->phase != sys_interphase) {
+                       if (ep->phase != sys_interphase) {
                                /*
                                 * On a new round we reset the name so
                                 * the interface name shows up again if
                                 * this address is no longer shared.
-                                * The same reasoning goes for the
-                                * ignore_packets flag.
+                                * We reset ignore_packets from the
+                                * new prototype to respect any runtime
+                                * changes to the nic rules.
                                 */
-                               strncpy(iface->name, interface.name,
-                                       sizeof(iface->name));
-                               iface->ignore_packets = 
-                                       interface.ignore_packets;
-                       } else
+                               strncpy(ep->name, enumep.name,
+                                       sizeof(ep->name));
+                               if (ep->ignore_packets !=
+                                   enumep.ignore_packets) {
+                                       ep->ignore_packets = 
+                                           enumep.ignore_packets;
+                                       refresh_peers = TRUE;
+                                       DPRINTF(4, ("refreshing peers due to %s ignore_packets change to %d\n",
+                                           stoa(&ep->sin),
+                                           ep->ignore_packets));
+                               }
+                       } else {
                                /* name collision - rename interface */
-                               strncpy(iface->name, "*multiple*",
-                                       sizeof(iface->name));
+                               strncpy(ep->name, "*multiple*",
+                                       sizeof(ep->name));
+                       }
 
-                       DPRINT_INTERFACE(4, (iface, "updating ", 
+                       DPRINT_INTERFACE(4, (ep, "updating ", 
                                             " present\n"));
 
-                       if (iface->ignore_packets != 
-                           interface.ignore_packets) {
+                       if (ep->ignore_packets !=
+                           enumep.ignore_packets) {
                                /*
                                 * We have conflicting configurations
                                 * for the interface address. This is
@@ -1813,16 +1905,16 @@ update_interfaces(
                                 */
                                msyslog(LOG_ERR,
                                        "WARNING: conflicting enable configuration for interfaces %s and %s for address %s - unsupported configuration - address DISABLED",
-                                       interface.name, iface->name,
-                                       stoa(&interface.sin));
+                                       enumep.name, ep->name,
+                                       stoa(&enumep.sin));
 
-                               iface->ignore_packets = ISC_TRUE;                               
+                               ep->ignore_packets = ISC_TRUE;                          
                        }
 
-                       iface->phase = sys_interphase;
+                       ep->phase = sys_interphase;
 
                        ifi.action = IFS_EXISTS;
-                       ifi.ep = iface;
+                       ifi.ep = ep;
                        if (receiver != NULL)
                                (*receiver)(data, &ifi);
                } else {
@@ -1834,27 +1926,29 @@ update_interfaces(
                         * We can bind to the address as the refresh
                         * code already closed the offending socket
                         */
-                       iface = create_interface(port, &interface);
+                       ep = create_interface(port, &enumep);
 
-                       if (iface != NULL) {
+                       if (ep != NULL) {
                                ifi.action = IFS_CREATED;
-                               ifi.ep = iface;
+                               ifi.ep = ep;
                                if (receiver != NULL)
                                        (*receiver)(data, &ifi);
 
-                               new_interface_found = 1;
-
+                               new_interface_found = TRUE;
+                               refresh_peers = TRUE;
+                               DPRINTF(4, ("refreshing peers due to new addr %s\n",
+                                       stoa(&ep->sin)));
                                DPRINT_INTERFACE(3,
-                                       (iface, "updating ",
+                                       (ep, "updating ",
                                         " new - created\n"));
                        } else {
                                DPRINT_INTERFACE(3, 
-                                       (&interface, "updating ",
+                                       (&enumep, "updating ",
                                         " new - creation FAILED"));
                        
                                msyslog(LOG_INFO,
                                        "failed to init interface for address %s", 
-                                       stoa(&interface.sin));
+                                       stoa(&enumep.sin));
                                continue;
                        }
                }
@@ -1866,54 +1960,54 @@ update_interfaces(
         * phase 2 - delete gone interfaces - reassigning peers to
         * other interfaces
         */
-       iface = ep_list;
-
-       while (iface != NULL) {
-               next = iface->elink;
+       for (ep = ep_list; ep != NULL; ep = next_ep) {
+               next_ep = ep->elink;
                  
-               if (!(iface->flags & (INT_WILDCARD | INT_MCASTIF))) {
-                       /*
-                        * if phase does not match sys_phase this
-                        * interface was not enumerated during the last
-                        * interface scan - so it is gone and will be
-                        * deleted here unless it is solely an MCAST or
-                        * WILDCARD interface.
-                        */
-                       if (iface->phase != sys_interphase) {
-                               DPRINT_INTERFACE(3, 
-                                       (iface, "updating ",
-                                        "GONE - deleting\n"));
-                               remove_interface(iface);
+               /*
+                * if phase does not match sys_phase this interface was
+                * not enumerated during the last interface scan - so it
+                * is gone and will be deleted here unless it did not
+                * originate from interface enumeration (INT_WILDCARD,
+                * INT_MCASTIF).
+                */
+               if (((INT_WILDCARD | INT_MCASTIF) & ep->flags) ||
+                   ep->phase == sys_interphase)
+                       continue;
 
-                               ifi.action = IFS_DELETED;
-                               ifi.ep = iface;
-                               if (receiver != NULL)
-                                       (*receiver)(data, &ifi);
+               DPRINT_INTERFACE(3, (ep, "updating ",
+                                    "GONE - deleting\n"));
+               remove_interface(ep);
+               refresh_peers = TRUE;
+               DPRINTF(4, ("refreshing peers due to deleted addr %s",
+                           stoa(&ep->sin)));
 
-                               /*
-                                * disconnect peers from deleted
-                                * interface
-                                */
-                               while (iface->peers != NULL)
-                                       set_peerdstadr(iface->peers, NULL);
+               ifi.action = IFS_DELETED;
+               ifi.ep = ep;
+               if (receiver != NULL)
+                       (*receiver)(data, &ifi);
 
-                               /*
-                                * update globals in case we lose 
-                                * a loopback interface
-                                */
-                               if (iface == loopback_interface)
-                                       loopback_interface = NULL;
+               /* disconnect peers from deleted endpt. */
+               while (ep->peers != NULL)
+                       set_peerdstadr(ep->peers, NULL);
 
-                               delete_interface(iface);
-                       }
-               }
-               iface = next;
+               /*
+                * update globals in case we lose 
+                * a loopback interface
+                */
+               if (ep == loopback_interface)
+                       loopback_interface = NULL;
+
+               delete_interface(ep);
        }
 
        /*
         * phase 3 - re-configure as the world has changed if necessary
         */
-       refresh_all_peerinterfaces();
+       if (refresh_peers) {
+               refresh_all_peerinterfaces();
+               msyslog(LOG_INFO, "peers refreshed");
+       }
+
        return new_interface_found;
 }
 
@@ -1962,9 +2056,12 @@ create_interface(
        struct interface *      protot
        )
 {
-       sockaddr_u resmask;
-       struct interface *iface;
-
+       sockaddr_u      resmask;
+       endpt *         iface;
+#if defined(MCAST) && defined(MULTICAST_NONEWSOCKET)
+       remaddr_t *     entry;
+       remaddr_t *     next_entry;
+#endif
        DPRINTF(2, ("create_interface(%s#%d)\n", stoa(&protot->sin),
                    port));
 
@@ -2016,6 +2113,35 @@ create_interface(
        add_addr_to_list(&iface->sin, iface);
        add_interface(iface);
 
+#if defined(MCAST) && defined(MULTICAST_NONEWSOCKET)
+       /*
+        * Join any previously-configured compatible multicast groups.
+        */
+       if (INT_MULTICAST & iface->flags &&
+           !((INT_LOOPBACK | INT_WILDCARD) & iface->flags) &&
+           !iface->ignore_packets) {
+               for (entry = remoteaddr_list;
+                    entry != NULL;
+                    entry = next_entry) {
+                       next_entry = entry->link;
+                       if (AF(&iface->sin) != AF(&entry->addr) ||
+                           !IS_MCAST(&entry->addr))
+                               continue;
+                       if (socket_multicast_enable(iface,
+                                                   &entry->addr))
+                               msyslog(LOG_INFO, 
+                                       "Added Multicast Listener %s on %s",
+                                       stoa(&entry->addr),
+                                       stoa(&iface->sin));
+                       else
+                               msyslog(LOG_ERR,
+                                       "Failed to add Multicast Listener %s on %s",
+                                       stoa(&entry->addr),
+                                       stoa(&iface->sin));
+               }
+       }
+#endif /* MCAST && MCAST_NONEWSOCKET */
+
        DPRINT_INTERFACE(2, (iface, "created ", "\n"));
        return iface;
 }
@@ -2265,13 +2391,13 @@ enable_multicast_if(
 #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
                if (setsockopt(iface->fd, IPPROTO_IPV6,
                               IPV6_MULTICAST_IF,
-                              (char *)&iface->scopeid,
-                              sizeof(iface->scopeid))) {
+                              (char *)&iface->ifindex,
+                              sizeof(iface->ifindex))) {
 
                        msyslog(LOG_ERR,
-                               "setsockopt IPV6_MULTICAST_IF failed: %m on socket %d, addr %s, scope %d for multicast address %s",
+                               "setsockopt IPV6_MULTICAST_IF failed: %m on socket %d, addr %s, ifindex %u for multicast address %s",
                                iface->fd, stoa(&iface->sin),
-                               iface->scopeid, stoa(maddr));
+                               iface->ifindex, stoa(maddr));
                        return;
                }
 #ifdef IPV6_MULTICAST_LOOP
@@ -2288,9 +2414,9 @@ enable_multicast_if(
                                stoa(maddr));
                }
 #endif
-               DPRINTF(4, ("Added IPv6 multicast interface on socket %d, addr %s, scope %d for multicast address %s\n",
+               DPRINTF(4, ("Added IPv6 multicast interface on socket %d, addr %s, for multicast address %s\n",
                            iface->fd,  stoa(&iface->sin),
-                           iface->scopeid, stoa(maddr)));
+                           stoa(maddr)));
                break;
 #else
                return;
@@ -2305,11 +2431,10 @@ enable_multicast_if(
  * The socket is in the inter_list all we need to do is enable
  * multicasting. It is not this function's job to select the socket
  */
-#ifdef MCAST
+#if defined(MCAST)
 static isc_boolean_t
 socket_multicast_enable(
        endpt *         iface,
-       int             lscope,
        sockaddr_u *    maddr
        )
 {
@@ -2317,13 +2442,6 @@ socket_multicast_enable(
 #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
        struct ipv6_mreq        mreq6;
 #endif
-
-       if (find_addr_in_list(maddr) != NULL) {
-               DPRINTF(4, ("socket_multicast_enable(%s): already enabled\n",
-                           stoa(maddr)));
-               return ISC_TRUE;
-       }
-
        switch (AF(maddr)) {
 
        case AF_INET:
@@ -2360,18 +2478,18 @@ socket_multicast_enable(
                 */
                memset(&mreq6, 0, sizeof(mreq6));
                mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr);
-               mreq6.ipv6mr_interface = lscope;
+               mreq6.ipv6mr_interface = iface->ifindex;
 
                if (setsockopt(iface->fd, IPPROTO_IPV6,
                               IPV6_JOIN_GROUP, (char *)&mreq6, 
                               sizeof(mreq6))) {
                        msyslog(LOG_ERR,
-                               "setsockopt IPV6_JOIN_GROUP failed: %m on socket %d, addr %s for interface %d (%s)",
+                               "setsockopt IPV6_JOIN_GROUP failed: %m on socket %d, addr %s for interface %u (%s)",
                                iface->fd, stoa(&iface->sin),
                                mreq6.ipv6mr_interface, stoa(maddr));
                        return ISC_FALSE;
                }
-               DPRINTF(4, ("Added IPv6 multicast group on socket %d, addr %s for interface %d(%s)\n",
+               DPRINTF(4, ("Added IPv6 multicast group on socket %d, addr %s for interface %(%s)\n",
                            iface->fd, stoa(&iface->sin),
                            mreq6.ipv6mr_interface, stoa(maddr)));
 #else
@@ -2380,15 +2498,18 @@ socket_multicast_enable(
        }
        iface->flags |= INT_MCASTOPEN;
        iface->num_mcast++;
-       add_addr_to_list(maddr, iface);
+
        return ISC_TRUE;
 }
+#endif /* MCAST */
+
 
 /*
  * Remove a multicast address from a given socket
  * The socket is in the inter_list all we need to do is disable
  * multicasting. It is not this function's job to select the socket
  */
+#ifdef MCAST
 static isc_boolean_t
 socket_multicast_disable(
        struct interface *      iface,
@@ -2435,7 +2556,7 @@ socket_multicast_disable(
                 * the kernel figure it out.
                 */
                mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr);
-               mreq6.ipv6mr_interface = iface->scopeid;
+               mreq6.ipv6mr_interface = iface->ifindex;
 
                if (setsockopt(iface->fd, IPPROTO_IPV6,
                               IPV6_LEAVE_GROUP, (char *)&mreq6,
@@ -2444,7 +2565,7 @@ socket_multicast_disable(
                        msyslog(LOG_ERR,
                                "setsockopt IPV6_LEAVE_GROUP failure: %m on socket %d, addr %s for %d (%s)",
                                iface->fd, stoa(&iface->sin),
-                               iface->scopeid, stoa(maddr));
+                               iface->ifindex, stoa(maddr));
                        return ISC_FALSE;
                }
                break;
@@ -2551,19 +2672,14 @@ io_setbclient(void)
 void
 io_unsetbclient(void)
 {
-       struct interface *interf;
+       endpt *ep;
 
-       for (interf = ep_list;
-            NULL != interf;
-            interf = interf->elink)
-       {
-               if (interf->flags & INT_WILDCARD)
+       for (ep = ep_list; ep != NULL; ep = ep->elink) {
+               if (INT_WILDCARD & ep->flags)
                        continue;
-         
-               if (!(interf->flags & INT_BCASTOPEN))
+               if (!(INT_BCASTOPEN & ep->flags))
                        continue;
-
-               socket_broadcast_disable(interf, &interf->sin);
+               socket_broadcast_disable(ep, &ep->sin);
        }
 }
 
@@ -2577,7 +2693,7 @@ io_multicast_add(
 {
 #ifdef MCAST
        endpt * ep;
-       int     lscope;
+       endpt * one_ep;
 
        /*
         * Check to see if this is a multicast address
@@ -2593,48 +2709,27 @@ io_multicast_add(
                return;
        }
 
-       lscope = 0;
-
 #ifndef MULTICAST_NONEWSOCKET
        ep = new_interface(NULL);
        
        /*
         * Open a new socket for the multicast address
         */
-       ep->family = AF(addr);
-       AF(&ep->sin) = ep->family;
-       AF(&ep->mask) = ep->family;
+       ep->sin = *addr;
        SET_PORT(&ep->sin, NTP_PORT);
+       ep->family = AF(&ep->sin);
+       AF(&ep->mask) = ep->family;
        SET_ONESMASK(&ep->mask);
 
-       switch (AF(addr)) {
-
-       case AF_INET:
-               NSRCADR(&ep->sin) = NSRCADR(addr);
-               break;
-
-       case AF_INET6:
-#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
-               SET_ADDR6N(&ep->sin, SOCK_ADDR6(addr));
-               lscope = SCOPE(addr);
-               SET_SCOPE(&ep->sin, lscope); 
-#endif
-               break;
-       }
-               
        set_reuseaddr(1);
        ep->bfd = INVALID_SOCKET;
-       ep->fd = open_socket(&ep->sin, INT_MULTICAST, 0, ep);
+       ep->fd = open_socket(&ep->sin, 0, 0, ep);
        if (ep->fd != INVALID_SOCKET) {
                ep->ignore_packets = ISC_FALSE;
                ep->flags |= INT_MCASTIF;
                
                strncpy(ep->name, "multicast", sizeof(ep->name));
                DPRINT_INTERFACE(2, (ep, "multicast add ", "\n"));
-               /*
-                * socket_multicast_enable() will add this address to
-                * the addresslist
-                */
                add_interface(ep);
                log_listen_address(ep);
        } else {
@@ -2662,34 +2757,40 @@ io_multicast_add(
                        return;
                }
        }
-#else
+       {       /* in place of the { following for in #else clause */
+               one_ep = ep;
+#else  /* MULTICAST_NONEWSOCKET follows */
        /*
-        * For the case where we can't use a separate socket
+        * For the case where we can't use a separate socket (Windows)
+        * join each applicable endpoint socket to the group address.
         */
-       ep = findlocalcastinterface(addr);
-       /*
-        * If we don't have a valid socket, just return
-        */
-       if (NULL == ep) {
-               msyslog(LOG_ERR,
-                       "Can not add multicast address %s: no multicast interface found",
-                       stoa(addr));
-               return;
+       if (IS_IPV4(addr))
+               one_ep = wildipv4;
+       else if (IS_IPV6(addr))
+               one_ep = wildipv6;
+       for (ep = ep_list; ep != NULL; ep = ep->elink) {
+               if (ep->ignore_packets || AF(&ep->sin) != AF(addr) ||
+                   !(INT_MULTICAST & ep->flags) ||
+                   (INT_LOOPBACK | INT_WILDCARD) & ep->flags)
+                       continue;
+               one_ep = ep;
+#endif /* MULTICAST_NONEWSOCKET */
+               if (socket_multicast_enable(ep, addr))
+                       msyslog(LOG_INFO, 
+                               "Added Multicast Listener %s on %s",
+                               stoa(addr), stoa(&ep->sin));
+               else
+                       msyslog(LOG_ERR,
+                               "Failed to add Multicast Listener %s on %s",
+                               stoa(addr), stoa(&ep->sin));
        }
 
-#endif
-       if (socket_multicast_enable(ep, lscope, addr))
-               msyslog(LOG_INFO, 
-                       "Added Multicast Listener %s on interface #%d %s",
-                       stoa(addr), ep->ifnum, ep->name);
-       else
-               msyslog(LOG_ERR, "Failed to add Multicast Listener %s",
-                       stoa(addr));
-#else /* MCAST */
+       add_addr_to_list(addr, one_ep);
+#else  /* !MCAST  follows*/
        msyslog(LOG_ERR,
                "Can not add multicast address %s: no multicast support",
                stoa(addr));
-#endif /* MCAST */
+#endif
        return;
 }
 
@@ -2797,10 +2898,10 @@ static void init_nonblocking_io(
 
 static SOCKET
 open_socket(
-       sockaddr_u *            addr,
-       int                     bcast,
-       int                     turn_off_reuse,
-       struct interface *      interf
+       sockaddr_u *    addr,
+       int             bcast,
+       int             turn_off_reuse,
+       endpt *         interf
        )
 {
        SOCKET  fd;
@@ -2897,21 +2998,21 @@ open_socket(
         * IPv6 specific options go here
         */
        if (IS_IPV6(addr)) {
-#if defined(IPV6_V6ONLY)
+#ifdef IPV6_V6ONLY
                if (isc_net_probe_ipv6only() == ISC_R_SUCCESS
                    && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
                    (char*)&on, sizeof(on)))
                        msyslog(LOG_ERR,
                                "setsockopt IPV6_V6ONLY on fails on address %s: %m",
                                stoa(addr));
-#endif /* IPV6_V6ONLY */
-#if defined(IPV6_BINDV6ONLY)
+#endif
+#ifdef IPV6_BINDV6ONLY
                if (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDV6ONLY,
                    (char*)&on, sizeof(on)))
                        msyslog(LOG_ERR,
                                "setsockopt IPV6_BINDV6ONLY on fails on address %s: %m",
                                stoa(addr));
-#endif /* IPV6_BINDV6ONLY */
+#endif
        }
 
 #ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND
@@ -3057,7 +3158,7 @@ sendpkt(
                /*
                 * for the moment we use the bcast option to set multicast ttl
                 */
-               if (ttl > 0 && ttl != src->last_ttl) {
+               if (ismcast && ttl > 0 && ttl != src->last_ttl) {
                        /*
                         * set the multicast ttl for outgoing packets
                         */
@@ -3080,9 +3181,7 @@ sendpkt(
                                break;
 #endif /* INCLUDE_IPV6_SUPPORT */
 
-                       default:        /* just NOP if not supported */
-                               DPRINTF(1, ("sendpkt unknown AF %d",
-                                           AF(&src->sin)));
+                       default:
                                rc = 0;
                        }
                        
@@ -3093,14 +3192,43 @@ sendpkt(
                                        "setsockopt IP_MULTICAST_TTL/IPV6_MULTICAST_HOPS fails on address %s: %m",
                                        stoa(&src->sin));
                }
-
+               if (ismcast) {
+                       /*
+                        * select the local address from which to send to multicast.
+                        */
+                       switch (AF(&src->sin)) {
+                       case AF_INET :
+                               cttl = (u_char)ttl;
+                               rc = setsockopt(src->fd, IPPROTO_IP,
+                                               IP_MULTICAST_IF,
+                                               (void *)&NSRCADR(&src->sin),
+                                               sizeof(NSRCADR(&src->sin)));
+                               break;
+#ifdef INCLUDE_IPV6_SUPPORT
+                       case AF_INET6 :
+                               rc = setsockopt(src->fd, IPPROTO_IPV6,
+                                                IPV6_MULTICAST_IF,
+                                                (void *)&ep->ifindex,
+                                                sizeof(ep->ifindex));
+                               break;
+#endif
+                       default:
+                               DPRINTF(1, ("sendpkt unknown AF %d",
+                                           AF(&src->sin)));
+                               rc = 0;
+                       }
+                       if (rc)
+                               msyslog(LOG_ERR, 
+                                       "setsockopt IP[V6]_MULTICAST_IF fails on address %s: %m",
+                                       stoa(&src->sin));
+               }
 #endif /* MCAST */
 
 #ifdef SIM
                cc = simulate_server(dest, src, pkt);
 #else
-               cc = sendto(src->fd, (char *)pkt, (unsigned int)len, 0, 
-                           (struct sockaddr *)dest, SOCKLEN(dest));
+               cc = sendto(src->fd, (char *)pkt, (u_int)len, 0,
+                           &dest->sa, SOCKLEN(dest));
 #endif
                if (cc == -1) {
                        src->notsent++;
@@ -3823,82 +3951,6 @@ getinterface(
 }
 
 
-/*
- * findlocalcastinterface - find local *cast interface for addr
- */
-#ifdef MULTICAST_NONEWSOCKET
-static endpt *
-findlocalcastinterface(
-       sockaddr_u *    addr
-       )
-{
-       endpt * iface;
-       endpt * nif;
-#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
-       int     want_linklocal;
-#endif 
-
-       NTP_REQUIRE(addr_ismulticast(addr));
-
-       /*
-        * see how kernel maps the mcast address
-        */
-       nif = findlocalinterface(addr, 0, 0);
-
-       if (nif != NULL && !nif->ignore_packets) {
-               DPRINTF(2, ("findlocalcastinterface: kernel recommends interface #%d %s for %s\n",
-                           nif->ifnum, nif->name, stoa(addr)));
-               return nif;
-       }
-
-#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
-       want_linklocal = (IN6_IS_ADDR_MC_LINKLOCAL(PSOCK_ADDR6(addr))
-                      || IN6_IS_ADDR_MC_SITELOCAL(PSOCK_ADDR6(addr)));
-#endif
-
-       for (iface = ep_list; iface != NULL; iface = iface->elink) {
-               /* use only allowed addresses */
-               if (iface->ignore_packets)
-                       continue;
-
-               /* Skip the loopback and wildcard addresses */
-               if (iface->flags & (INT_LOOPBACK | INT_WILDCARD))
-                       continue;
-
-               /* Skip if different family */
-               if (AF(&iface->sin) != AF(addr))
-                       continue;
-
-               /* Is it multicast capable? */
-               if (!(iface->flags & INT_MULTICAST))
-                       continue;
-
-#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
-               if (want_linklocal && IS_IPV6(&iface->sin) &&
-                   IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(&iface->sin))) {
-                       nif = iface;
-                       break;
-               }
-               /* If we want a linklocal address, skip */
-               if (want_linklocal)
-                       continue;
-#endif
-               nif = iface;
-               break;
-       }       /* for loop over interfaces */
-
-       if (nif != NULL)
-               DPRINTF(3, ("findlocalcastinterface: found interface #%d %s for %s\n",
-                           nif->ifnum, nif->name, stoa(addr)));
-       else
-               DPRINTF(3, ("findlocalcastinterface: no interface found for %s\n",
-                           stoa(addr)));
-
-       return nif;
-}
-#endif /* MULTICAST_NONEWSOCKET */
-
-
 /*
  * findbcastinter - find broadcast interface corresponding to address
  */
@@ -3979,7 +4031,7 @@ findbcastinter(
                                break;
                }
 #ifdef INCLUDE_IPV6_SUPPORT
-               else if(IS_IPV6(addr)) {
+               else if (IS_IPV6(addr)) {
                        if (SOCK_EQ(&iface->bcast, addr))
                                break;
 
@@ -4276,9 +4328,6 @@ delete_interface_from_list(
                        DPRINTF(4, ("Deleted addr %s for interface #%d %s from list of addresses\n",
                                stoa(&unlinked->addr), iface->ifnum,
                                iface->name));
-                       if (addr_ismulticast(&unlinked->addr))
-                               /* find a new interface to use */
-                               io_multicast_add(&unlinked->addr);
                        free(unlinked);
                }
        } while (unlinked != NULL);
index 0e8f97d17d19a5ebe60ebb5a4bd548ef45636f2a..22a213cfa805a6455a94fa6e69ae2302f1136aab 100644 (file)
@@ -215,34 +215,34 @@ findexistingpeer(
  */
 struct peer *
 findpeer(
-       sockaddr_u *srcadr,
-       struct interface *dstadr,
-       int     pkt_mode,
-       int     *action
+       sockaddr_u *    srcadr,
+       endpt *         dstadr,
+       int             pkt_mode,
+       int *           action
        )
 {
-       register struct peer *peer;
+       struct peer *p;
        u_int hash;
 
        findpeer_calls++;
        hash = NTP_HASH_ADDR(srcadr);
-       for (peer = peer_hash[hash]; peer != NULL; peer = peer->next) {
-               if (SOCK_EQ(srcadr, &peer->srcadr) &&
-                   NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) {
+       for (p = peer_hash[hash]; p != NULL; p = p->next) {
+               if (SOCK_EQ(srcadr, &p->srcadr) &&
+                   NSRCPORT(srcadr) == NSRCPORT(&p->srcadr)) {
 
                        /*
                         * if the association matching rules determine
                         * that this is not a valid combination, then
                         * look for the next valid peer association.
                         */
-                       *action = MATCH_ASSOC(peer->hmode, pkt_mode);
+                       *action = MATCH_ASSOC(p->hmode, pkt_mode);
 
                        /*
                         * if an error was returned, exit back right
                         * here.
                         */
                        if (*action == AM_ERR)
-                               return ((struct peer *)0);
+                               return NULL;
 
                        /*
                         * if a match is found, we stop our search.
@@ -255,12 +255,14 @@ findpeer(
        /*
         * If no matching association is found
         */
-       if (peer == 0) {
+       if (NULL == p) {
                *action = MATCH_ASSOC(NO_PEER, pkt_mode);
-               return ((struct peer *)0);
+       } else if (p->dstadr != dstadr) {
+               set_peerdstadr(p, dstadr);
+               DPRINTF(1, ("changed %s local address to match response",
+                           stoa(&p->srcadr)));
        }
-       set_peerdstadr(peer, dstadr);
-       return (peer);
+       return p;
 }
 
 /*
@@ -507,41 +509,38 @@ peer_config(
  */
 void
 set_peerdstadr(
-       struct peer *peer,
-       struct interface *interface
+       struct peer *   p,
+       endpt *         dstadr
        )
 {
-       struct peer *unlinked;
+       struct peer *   unlinked;
 
-       if (peer->dstadr != interface) {
-               if (interface != NULL && (peer->cast_flags &
-                   MDF_BCLNT) && (interface->flags & INT_MCASTIF) &&
-                   peer->burst) {
+       if (p->dstadr == dstadr)
+               return;
 
-                       /*
-                        * don't accept updates to a true multicast
-                        * reception interface while a BCLNT peer is
-                        * running it's unicast protocol
-                        */
-                       return;
-               }
-               if (peer->dstadr != NULL) {
-                       peer->dstadr->peercnt--;
-                       UNLINK_SLIST(unlinked, peer->dstadr->peers,
-                           peer, ilink, struct peer);
-                       msyslog(LOG_INFO,
-                               "%s interface %s -> %s",
-                               stoa(&peer->srcadr),
-                               stoa(&peer->dstadr->sin),
-                               (interface != NULL)
-                                   ? stoa(&interface->sin)
-                                   : "(null)");
-               }
-               peer->dstadr = interface;
-               if (peer->dstadr != NULL) {
-                       LINK_SLIST(peer->dstadr->peers, peer, ilink);
-                       peer->dstadr->peercnt++;
-               }
+       if (dstadr != NULL && (MDF_BCLNT & p->cast_flags) &&
+           (dstadr->flags & INT_MCASTIF) && p->burst) {
+               /*
+                * don't accept updates to a true multicast
+                * reception interface while a BCLNT peer is
+                * running it's unicast protocol
+                */
+               return;
+       }
+       if (p->dstadr != NULL) {
+               p->dstadr->peercnt--;
+               UNLINK_SLIST(unlinked, p->dstadr->peers, p, ilink,
+                            struct peer);
+               msyslog(LOG_INFO, "%s interface %s -> %s",
+                       stoa(&p->srcadr), stoa(&p->dstadr->sin),
+                       (dstadr != NULL)
+                           ? stoa(&dstadr->sin)
+                           : "(none)");
+       }
+       p->dstadr = dstadr;
+       if (dstadr != NULL) {
+               LINK_SLIST(dstadr->peers, p, ilink);
+               dstadr->peercnt++;
        }
 }
 
@@ -568,14 +567,14 @@ peer_refresh_interface(
            peer->ttl, peer->keyid));
        if (niface != NULL) {
                DPRINTF(4, (
-                   "fd=%d, bfd=%d, name=%.16s, flags=0x%x, scope=%d, sin=%s",
+                   "fd=%d, bfd=%d, name=%.16s, flags=0x%x, ifindex=%u, sin=%s",
                    niface->fd,  niface->bfd, niface->name,
-                   niface->flags, niface->scopeid,
-                   stoa((&niface->sin))));
+                   niface->flags, niface->ifindex,
+                   stoa(&niface->sin)));
                if (niface->flags & INT_BROADCAST)
                        DPRINTF(4, (", bcast=%s",
-                               stoa((&niface->bcast))));
-               DPRINTF(4, (", mask=%s\n", stoa((&niface->mask))));
+                               stoa(&niface->bcast)));
+               DPRINTF(4, (", mask=%s\n", stoa(&niface->mask)));
        } else {
                DPRINTF(4, ("<NONE>\n"));
        }
index a658173b1763e7966f630310c830b7aea6bbf139..a172c5b582f7bbcddc6eddbba5af3f84d1daa677 100644 (file)
@@ -1682,7 +1682,8 @@ setclr_flags(
        u_long set
        )
 {
-       register u_int flags;
+       struct conf_sys_flags *sf;
+       u_int32 flags;
        int prev_kern_enable;
 
        prev_kern_enable = kern_enable;
@@ -1692,8 +1693,8 @@ setclr_flags(
                return;
        }
 
-       flags = ((struct conf_sys_flags *)inpkt->data)->flags;
-       flags = ntohl(flags);
+       sf = (struct conf_sys_flags *)inpkt->data;
+       flags = ntohl(sf->flags);
        
        if (flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS |
                      SYS_FLAG_NTP | SYS_FLAG_KERNEL | SYS_FLAG_MONITOR |
@@ -2073,6 +2074,7 @@ reset_stats(
        struct req_pkt *inpkt
        )
 {
+       struct reset_flags *rflags;
        u_long flags;
        struct reset_entry *rent;
 
@@ -2082,9 +2084,9 @@ reset_stats(
                return;
        }
 
-       flags = ((struct reset_flags *)inpkt->data)->flags;
-       flags = ntohl(flags);
-     
+       rflags = (struct reset_flags *)inpkt->data;
+       flags = ntohl(rflags->flags);
+
        if (flags & ~RESET_ALLFLAGS) {
                msyslog(LOG_ERR, "reset_stats: reset leaves %#lx",
                        flags & ~RESET_ALLFLAGS);
@@ -2094,7 +2096,7 @@ reset_stats(
 
        for (rent = reset_entries; rent->flag != 0; rent++) {
                if (flags & rent->flag)
-                   (rent->handler)();
+                       (*rent->handler)();
        }
        req_ack(srcadr, inter, inpkt, INFO_OKAY);
 }
@@ -2495,7 +2497,7 @@ set_request_keyid(
        struct req_pkt *inpkt
        )
 {
-       keyid_t keyid;
+       keyid_t *pkeyid;
 
        /*
         * Restrict ourselves to one item only.
@@ -2506,8 +2508,8 @@ set_request_keyid(
                return;
        }
 
-       keyid = ntohl(*((u_int32 *)(inpkt->data)));
-       info_auth_keyid = keyid;
+       pkeyid = (keyid_t *)inpkt->data;
+       info_auth_keyid = ntohl(*pkeyid);
        req_ack(srcadr, inter, inpkt, INFO_OKAY);
 }
 
@@ -2523,7 +2525,7 @@ set_control_keyid(
        struct req_pkt *inpkt
        )
 {
-       keyid_t keyid;
+       keyid_t *pkeyid;
        extern keyid_t ctl_auth_keyid;
 
        /*
@@ -2535,8 +2537,8 @@ set_control_keyid(
                return;
        }
 
-       keyid = ntohl(*((u_int32 *)(inpkt->data)));
-       ctl_auth_keyid = keyid;
+       pkeyid = (keyid_t *)inpkt->data;
+       ctl_auth_keyid = ntohl(*pkeyid);
        req_ack(srcadr, inter, inpkt, INFO_OKAY);
 }
 
@@ -2895,9 +2897,9 @@ fill_info_if_stats(void *data, interface_info_t *interface_info)
        ifs->received = htonl(ep->received);
        ifs->sent = htonl(ep->sent);
        ifs->notsent = htonl(ep->notsent);
-       ifs->scopeid = htonl(ep->scopeid);
-       /* ifindex was always zero, now no longer in struct interface */
-       ifs->ifindex = 0;
+       ifs->ifindex = htonl(ep->ifindex);
+       /* scope no longer in struct interface, in in6_addr typically */
+       ifs->scopeid = ifs->ifindex;
        ifs->ifnum = htonl(ep->ifnum);
        ifs->uptime = htonl(current_time - ep->starttime);
        ifs->ignore_packets = ep->ignore_packets;
index e6135615bed2cec8a00d1479e5a3e676d1608831..a1e83b764ed4e115a65c9c91421315e0f8fc42df 100644 (file)
@@ -1173,7 +1173,7 @@ getgroup:
 #ifdef HAVE_DNSREGISTRATION
                if (mdnsreg && (current_time - mdnsreg ) > 60 && mdnstries && sys_leap != LEAP_NOTINSYNC) {
                        mdnsreg = current_time;
-                       msyslog(LOG_INFO, "Attemping to register mDNS");
+                       msyslog(LOG_INFO, "Attempting to register mDNS");
                        if ( DNSServiceRegister (&mdns, 0, 0, NULL, "_ntp._udp", NULL, NULL, 
                            htons(NTP_PORT), 0, NULL, NULL, NULL) != kDNSServiceErr_NoError ) {
                                if (!--mdnstries) {