From: Dave Hart Date: Sun, 12 Dec 2010 07:11:37 +0000 (+0000) Subject: [Bug 1741] Enable multicast reception on each address (Windows). X-Git-Tag: NTP_4_2_7P93~3^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5d288a445d90692ee32d3555012539e313f7bf22;p=thirdparty%2Fntp.git [Bug 1741] Enable multicast reception on each address (Windows). 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 --- diff --git a/ChangeLog b/ChangeLog index ae8d367f7..d52bfca4b 100644 --- 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 diff --git a/include/isc/mem.h b/include/isc/mem.h index e6b0e2236..f5cf9ec57 100644 --- a/include/isc/mem.h +++ b/include/isc/mem.h @@ -42,25 +42,26 @@ #include -#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") diff --git a/include/ntp.h b/include/ntp.h index d10a01fff..2a764147d 100644 --- a/include/ntp.h +++ b/include/ntp.h @@ -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) diff --git a/include/ntp_control.h b/include/ntp_control.h index f056fddda..3bca32b6e 100644 --- a/include/ntp_control.h +++ b/include/ntp_control.h @@ -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 diff --git a/include/ntp_io.h b/include/ntp_io.h index 7d88314ea..920fd0d36 100644 --- a/include/ntp_io.h +++ b/include/ntp_io.h @@ -31,12 +31,12 @@ #include #include -#if HAVE_NETINET_IN_H && HAVE_NETINET_IP_H -#include -# if HAVE_NETINET_IN_SYSTM_H +#if defined(HAVE_NETINET_IN_H) && defined(HAVE_NETINET_IP_H) +# include +# ifdef HAVE_NETINET_IN_SYSTM_H # include # endif -#include +# include #endif /* diff --git a/include/ntp_net.h b/include/ntp_net.h index 97e7805ea..d417cea4d 100644 --- a/include/ntp_net.h +++ b/include/ntp_net.h @@ -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) \ diff --git a/include/ntp_stdlib.h b/include/ntp_stdlib.h index 0abc49072..1f8e40480 100644 --- a/include/ntp_stdlib.h +++ b/include/ntp_stdlib.h @@ -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 *); diff --git a/include/ntpd.h b/include/ntpd.h index 734288999..9bc541054 100644 --- a/include/ntpd.h +++ b/include/ntpd.h @@ -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 */ diff --git a/lib/isc/include/isc/interfaceiter.h b/lib/isc/include/isc/interfaceiter.h index 8d04d04f5..544f54b12 100644 --- a/lib/isc/include/isc/interfaceiter.h +++ b/lib/isc/include/isc/interfaceiter.h @@ -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 */ /*@}*/ /*** diff --git a/lib/isc/unix/ifiter_ioctl.c b/lib/isc/unix/ifiter_ioctl.c index 36ce4c0dd..a69979326 100644 --- a/lib/isc/unix/ifiter_ioctl.c +++ b/lib/isc/unix/ifiter_ioctl.c @@ -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); diff --git a/lib/isc/unix/ifiter_sysctl.c b/lib/isc/unix/ifiter_sysctl.c index 7215d9844..072e3494f 100644 --- a/lib/isc/unix/ifiter_sysctl.c +++ b/lib/isc/unix/ifiter_sysctl.c @@ -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; diff --git a/lib/isc/unix/interfaceiter.c b/lib/isc/unix/interfaceiter.c index 87af69e99..3524a02c6 100644 --- a/lib/isc/unix/interfaceiter.c +++ b/lib/isc/unix/interfaceiter.c @@ -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); diff --git a/lib/isc/win32/include/isc/ipv6.h b/lib/isc/win32/include/isc/ipv6.h index a212a504b..51a609071 100644 --- a/lib/isc/win32/include/isc/ipv6.h +++ b/lib/isc/win32/include/isc/ipv6.h @@ -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 */ diff --git a/lib/isc/win32/interfaceiter.c b/lib/isc/win32/interfaceiter.c index fe8979b92..34c9428bc 100644 --- a/lib/isc/win32/interfaceiter.c +++ b/lib/isc/win32/interfaceiter.c @@ -29,7 +29,6 @@ #include #include -//#include #include #include #include @@ -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; } diff --git a/libntp/socktoa.c b/libntp/socktoa.c index bd97e6806..62e453726 100644 --- a/libntp/socktoa.c +++ b/libntp/socktoa.c @@ -29,7 +29,7 @@ char * socktoa( - sockaddr_u *sock + const sockaddr_u *sock ) { register char *buffer; diff --git a/libntp/socktohost.c b/libntp/socktohost.c index 325eea40d..05bbdd643 100644 --- a/libntp/socktohost.c +++ b/libntp/socktohost.c @@ -21,7 +21,7 @@ char * socktohost( - sockaddr_u *sock + const sockaddr_u *sock ) { register char *buffer; diff --git a/ntpd/ntp_control.c b/ntpd/ntp_control.c index 7ffeacb5a..a4d4afefc 100644 --- a/ntpd/ntp_control.c +++ b/ntpd/ntp_control.c @@ -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, diff --git a/ntpd/ntp_io.c b/ntpd/ntp_io.c index 5b7b7d86a..cf253ca95 100644 --- a/ntpd/ntp_io.c +++ b/ntpd/ntp_io.c @@ -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 %u (%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); diff --git a/ntpd/ntp_peer.c b/ntpd/ntp_peer.c index 0e8f97d17..22a213cfa 100644 --- a/ntpd/ntp_peer.c +++ b/ntpd/ntp_peer.c @@ -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, ("\n")); } diff --git a/ntpd/ntp_request.c b/ntpd/ntp_request.c index a658173b1..a172c5b58 100644 --- a/ntpd/ntp_request.c +++ b/ntpd/ntp_request.c @@ -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; diff --git a/ntpd/ntpd.c b/ntpd/ntpd.c index e6135615b..a1e83b764 100644 --- a/ntpd/ntpd.c +++ b/ntpd/ntpd.c @@ -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) {