diff options
Diffstat (limited to 'ntpd/ntp_io.c')
-rw-r--r-- | ntpd/ntp_io.c | 927 |
1 files changed, 481 insertions, 446 deletions
diff --git a/ntpd/ntp_io.c b/ntpd/ntp_io.c index bb35ffd68511..9d79fe493d9b 100644 --- a/ntpd/ntp_io.c +++ b/ntpd/ntp_io.c @@ -177,11 +177,14 @@ endpt * any_interface; /* wildcard ipv4 interface */ endpt * any6_interface; /* wildcard ipv6 interface */ endpt * loopback_interface; /* loopback ipv4 interface */ -static isc_boolean_t broadcast_client_enabled; /* is broadcast client enabled */ +static isc_boolean_t broadcast_client_enabled; u_int sys_ifnum; /* next .ifnum to assign */ int ninterfaces; /* Total number of interfaces */ -int disable_dynamic_updates; /* scan interfaces once only */ +int no_periodic_scan; /* network endpoint scans */ +int scan_addrs_once; /* because dropped privs */ +int nonlocal_v4_addr_up; /* should we try IPv4 pool? */ +int nonlocal_v6_addr_up; /* should we try IPv6 pool? */ #ifdef REFCLOCK /* @@ -210,7 +213,7 @@ static int update_interfaces(u_short, interface_receiver_t, static void remove_interface(endpt *); static endpt * create_interface(u_short, endpt *); -static int is_wildcard_addr (const sockaddr_u *); +static inline int is_wildcard_addr(const sockaddr_u *psau); /* * Multicast functions @@ -229,7 +232,6 @@ static isc_boolean_t socket_multicast_disable(endpt *, sockaddr_u *); #ifdef DEBUG static void interface_dump (const endpt *); -static void sockaddr_dump (const sockaddr_u *); static void print_interface (const endpt *, const char *, const char *); #define DPRINT_INTERFACE(level, args) do { if (debug >= (level)) { print_interface args; } } while (0) #else @@ -280,13 +282,13 @@ static int addr_samesubnet (const sockaddr_u *, const sockaddr_u *, static int create_sockets (u_short); static SOCKET open_socket (sockaddr_u *, int, int, endpt *); static void set_reuseaddr (int); -static isc_boolean_t socket_broadcast_enable (struct interface *, SOCKET, sockaddr_u *); +static isc_boolean_t socket_broadcast_enable (endpt *, SOCKET, sockaddr_u *); #if !defined(HAVE_IO_COMPLETION_PORT) && !defined(HAVE_SIGNALED_IO) static char * fdbits (int, const fd_set *); #endif #ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES -static isc_boolean_t socket_broadcast_disable (struct interface *, sockaddr_u *); +static isc_boolean_t socket_broadcast_disable (endpt *, sockaddr_u *); #endif typedef struct remaddr remaddr_t; @@ -305,10 +307,16 @@ endpt * mc6_list; /* IPv6 mcast-capable unicast endpts */ static endpt * wildipv4; static endpt * wildipv6; +#define RFC3927_ADDR 0xa9fe0000 /* 169.254. */ +#define RFC3927_MASK 0xffff0000 +#define IS_AUTOCONF(addr4) \ + ((SRCADR(addr4) & RFC3927_MASK) == RFC3927_ADDR) + #ifdef SYS_WINNT int accept_wildcard_if_for_winnt; #else const int accept_wildcard_if_for_winnt = FALSE; +#define init_io_completion_port() do {} while (FALSE) #endif static void add_fd_to_list (SOCKET, enum desc_type); @@ -316,7 +324,7 @@ static endpt * find_addr_in_list (sockaddr_u *); static endpt * find_flagged_addr_in_list(sockaddr_u *, u_int32); static void delete_addr_from_list (sockaddr_u *); static void delete_interface_from_list(endpt *); -static void close_and_delete_fd_from_list(SOCKET); +static void close_and_delete_fd_from_list(SOCKET, endpt *); static void add_addr_to_list (sockaddr_u *, endpt *); static void create_wildcards (u_short); static endpt * findlocalinterface (sockaddr_u *, int, int); @@ -337,7 +345,7 @@ static int cmp_addr_distance(const sockaddr_u *, * Routines to read the ntp packets */ #if !defined(HAVE_IO_COMPLETION_PORT) -static inline int read_network_packet (SOCKET, struct interface *, l_fp); +static inline int read_network_packet (SOCKET, endpt *, l_fp); static void ntpd_addremove_io_fd (int, int, int); static void input_handler_scan (const l_fp*, const fd_set*); static int/*BOOL*/ sanitize_fdset (int errc); @@ -454,15 +462,14 @@ init_io(void) /* Init buffer free list and stat counters */ init_recvbuff(RECV_INIT); /* update interface every 5 minutes as default */ - interface_interval = 300; + endpt_scan_period = 301; #ifdef WORK_PIPE addremove_io_fd = &ntpd_addremove_io_fd; #endif -#if defined(SYS_WINNT) init_io_completion_port(); -#elif defined(HAVE_SIGNALED_IO) +#if defined(HAVE_SIGNALED_IO) (void) set_signal(input_handler); #endif } @@ -528,11 +535,8 @@ interface_dump(const endpt *itf) printf("fd = %lld\n", (long long)itf->fd); printf("bfd = %lld\n", (long long)itf->bfd); printf("sin = %s,\n", stoa(&itf->sin)); - sockaddr_dump(&itf->sin); printf("bcast = %s,\n", stoa(&itf->bcast)); - sockaddr_dump(&itf->bcast); printf("mask = %s,\n", stoa(&itf->mask)); - sockaddr_dump(&itf->mask); printf("name = %s\n", itf->name); printf("flags = 0x%08x\n", itf->flags); printf("last_ttl = %d\n", itf->last_ttl); @@ -546,27 +550,6 @@ interface_dump(const endpt *itf) printf("phase = %u\n", itf->phase); } -/* - * sockaddr_dump - hex dump the start of a sockaddr_u - */ -static void -sockaddr_dump(const sockaddr_u *psau) -{ - /* Limit the size of the sockaddr_in6 hex dump */ - const int maxsize = min(32, sizeof(psau->sa6)); - const u_char * cp; - int i; - - /* XXX: Should we limit maxsize based on psau->saX.sin_family? */ - cp = (const void *)&psau->sa6; - - for(i = 0; i < maxsize; i++) { - printf("%02x", *cp++); - if (!((i + 1) % 4)) - printf(" "); - } - printf("\n"); -} /* * print_interface - helper to output debug information @@ -637,7 +620,7 @@ add_asyncio_reader( } /* - * remove asynchio_reader + * remove asyncio_reader */ static void remove_asyncio_reader( @@ -649,9 +632,9 @@ remove_asyncio_reader( UNLINK_SLIST(unlinked, asyncio_reader_list, reader, link, struct asyncio_reader); - if (reader->fd != INVALID_SOCKET) - close_and_delete_fd_from_list(reader->fd); - + if (reader->fd != INVALID_SOCKET) { + close_and_delete_fd_from_list(reader->fd, NULL); + } reader->fd = INVALID_SOCKET; } #endif /* !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) */ @@ -743,7 +726,7 @@ interface_enumerate( /* * do standard initialization of interface structure */ -static void +static inline void init_interface( endpt *ep ) @@ -760,20 +743,19 @@ init_interface( * template structure or via standard initialization * function */ -static struct interface * +static endpt * new_interface( - struct interface *interface + endpt *protot ) { - struct interface * iface; + endpt * iface; iface = emalloc(sizeof(*iface)); - - if (NULL == interface) - init_interface(iface); - else /* use the template */ - memcpy(iface, interface, sizeof(*iface)); - + if (NULL == protot) { + ZERO(*iface); + } else { + memcpy(iface, protot, sizeof(*iface)); + } /* count every new instance of an interface in the system */ iface->ifnum = sys_ifnum++; iface->starttime = current_time; @@ -814,19 +796,16 @@ add_interface( endpt ** pmclisthead; endpt * scan; endpt * scan_next; - endpt * unlinked; - 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 */ int rc; /* Calculate the refid */ ep->addr_refid = addr2refid(&ep->sin); +# ifdef WORDS_BIGENDIAN + if (IS_IPV6(&ep->sin)) { + ep->old_refid = BYTESWAP32(ep->addr_refid); + } +# endif /* link at tail so ntpdc -c ifstats index increases each row */ LINK_TAIL_SLIST(ep_list, ep, elink, endpt); ninterfaces++; @@ -843,101 +822,26 @@ add_interface( ? &mc4_list : &mc6_list; - 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 - * out from the link-/site-local addresses by default, to avoid - * 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. + * If we have multiple global addresses from the same prefix + * on the same network interface, multicast from one. */ for (scan = *pmclisthead; scan != NULL; scan = scan_next) { scan_next = scan->mclink; - if (ep->family != scan->family) - continue; - if (strcmp(ep->name, scan->name)) + if ( ep->family != scan->family + || ep->ifindex != scan->ifindex) { continue; + } 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) - ? "tail" - : "head", - stoa(&scan->sin))); + if (same_subnet) { + DPRINTF(4, ("did not add %s to multicast-capable list" + "which already has %s\n", + stoa(&ep->sin), stoa(&scan->sin))); return; } - 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", - (unlinked != scan) - ? "Failed to remove" - : "removed", - stoa(&scan->sin), stoa(&ep->sin))); - } } - /* - * Add link/site local at the tail of the multicast- - * capable unicast interfaces list, so that ntpd will - * send from global addresses before link-/site-local - * ones. - */ - if (ep_local) - LINK_TAIL_SLIST(*pmclisthead, ep, mclink, endpt); - else - LINK_SLIST(*pmclisthead, ep, mclink); - DPRINTF(4, ("added %s to %s of IPv%s multicast-capable unicast local address list\n", - stoa(&ep->sin), - (ep_local) - ? "tail" - : "head", - (AF_INET == ep->family) - ? "4" - : "6")); - + LINK_SLIST(*pmclisthead, ep, mclink); if (INVALID_SOCKET == ep->fd) return; @@ -987,6 +891,7 @@ remove_interface( endpt * unlinked; endpt ** pmclisthead; sockaddr_u resmask; + int/*BOOL*/ success; UNLINK_SLIST(unlinked, ep_list, ep, elink, endpt); if (!ep->ignore_packets && INT_MULTICAST & ep->flags) { @@ -1007,7 +912,9 @@ remove_interface( if (ep->fd != INVALID_SOCKET) { msyslog(LOG_INFO, - "Deleting interface #%d %s, %s#%d, interface stats: received=%ld, sent=%ld, dropped=%ld, active_time=%ld secs", + "Deleting %d %s, [%s]:%hd, stats:" + " received=%ld, sent=%ld, dropped=%ld," + " active_time=%ld secs", ep->ifnum, ep->name, stoa(&ep->sin), @@ -1016,10 +923,7 @@ remove_interface( ep->sent, ep->notsent, current_time - ep->starttime); -# ifdef HAVE_IO_COMPLETION_PORT - io_completion_port_remove_socket(ep->fd, ep); -# endif - close_and_delete_fd_from_list(ep->fd); + close_and_delete_fd_from_list(ep->fd, ep); ep->fd = INVALID_SOCKET; } @@ -1027,10 +931,7 @@ remove_interface( msyslog(LOG_INFO, "stop listening for broadcasts to %s on interface #%d %s", stoa(&ep->bcast), ep->ifnum, ep->name); -# ifdef HAVE_IO_COMPLETION_PORT - io_completion_port_remove_socket(ep->bfd, ep); -# endif - close_and_delete_fd_from_list(ep->bfd); + close_and_delete_fd_from_list(ep->bfd, ep); ep->bfd = INVALID_SOCKET; } # ifdef HAVE_IO_COMPLETION_PORT @@ -1042,8 +943,14 @@ remove_interface( /* remove restrict interface entry */ SET_HOSTMASK(&resmask, AF(&ep->sin)); - hack_restrict(RESTRICT_REMOVEIF, &ep->sin, &resmask, - -3, RESM_NTPONLY | RESM_INTERFACE, RES_IGNORE, 0); + success = hack_restrict(RESTRICT_REMOVEIF, &ep->sin, &resmask, 0, + RESM_NTPONLY | RESM_INTERFACE, 0, 0); + if (!success) { + msyslog(LOG_ERR, + "unable to remove self-restriction for %s", + stoa(&ep->sin)); + } + } @@ -1073,7 +980,7 @@ create_wildcards( #endif sockaddr_u wildaddr; nic_rule_action action; - struct interface * wildif; + endpt * wildif; /* * silence "potentially uninitialized" warnings from VC9 @@ -1404,9 +1311,6 @@ convert_isc_if( u_short port ) { - const u_char v6loop[16] = {0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1}; - strlcpy(itf->name, isc_if->name, sizeof(itf->name)); itf->ifindex = isc_if->ifindex; itf->family = (u_short)isc_if->af; @@ -1456,15 +1360,8 @@ convert_isc_if( * Clear the loopback flag if the address is not localhost. * http://bugs.ntp.org/1683 */ - if (INT_LOOPBACK & itf->flags) { - if (AF_INET == itf->family) { - if (127 != (SRCADR(&itf->sin) >> 24)) - itf->flags &= ~INT_LOOPBACK; - } else { - if (memcmp(v6loop, NSRCADR6(&itf->sin), - sizeof(NSRCADR6(&itf->sin)))) - itf->flags &= ~INT_LOOPBACK; - } + if ((INT_LOOPBACK & itf->flags) && !IS_LOOPBACK_ADDR(&itf->sin)) { + itf->flags &= ~INT_LOOPBACK; } } @@ -1480,33 +1377,33 @@ convert_isc_if( */ static int refresh_interface( - struct interface * interface + endpt * iface ) { #ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES - if (interface->fd != INVALID_SOCKET) { - int bcast = (interface->flags & INT_BCASTXMIT) != 0; + if (iface->fd != INVALID_SOCKET) { + int bcast = (iface->flags & INT_BCASTXMIT) != 0; /* as we forcibly close() the socket remove the broadcast permission indication */ if (bcast) - socket_broadcast_disable(interface, &interface->sin); + socket_broadcast_disable(iface, &iface->sin); - close_and_delete_fd_from_list(interface->fd); + close_and_delete_fd_from_list(iface->fd); /* create new socket picking up a new first hop binding at connect() time */ - interface->fd = open_socket(&interface->sin, - bcast, 0, interface); + iface->fd = open_socket(&iface->sin, + bcast, 0, iface); /* * reset TTL indication so TTL is is set again * next time around */ - interface->last_ttl = 0; - return (interface->fd != INVALID_SOCKET); + iface->last_ttl = 0; + return (iface->fd != INVALID_SOCKET); } else return 0; /* invalid sockets are not refreshable */ #else /* !OS_MISSES_SPECIFIC_ROUTE_UPDATES */ - return (interface->fd != INVALID_SOCKET); + return (iface->fd != INVALID_SOCKET); #endif /* !OS_MISSES_SPECIFIC_ROUTE_UPDATES */ } @@ -1516,20 +1413,21 @@ refresh_interface( void interface_update( interface_receiver_t receiver, - void * data) + void * data + ) { int new_interface_found; - if (disable_dynamic_updates) + if (scan_addrs_once) { return; - + } BLOCKIO(); new_interface_found = update_interfaces(NTP_PORT, receiver, data); UNBLOCKIO(); - if (!new_interface_found) + if (!new_interface_found) { return; - + } #ifdef DEBUG msyslog(LOG_DEBUG, "new interface(s) found: waking up resolver"); #endif @@ -1552,13 +1450,11 @@ sau_from_netaddr( switch (pna->family) { case AF_INET: - memcpy(&psau->sa4.sin_addr, &pna->type.in, - sizeof(psau->sa4.sin_addr)); + psau->sa4.sin_addr = pna->type.in; break; case AF_INET6: - memcpy(&psau->sa6.sin6_addr, &pna->type.in6, - sizeof(psau->sa6.sin6_addr)); + psau->sa6.sin6_addr = pna->type.in6; break; } } @@ -1581,6 +1477,30 @@ is_wildcard_addr( } +isc_boolean_t +is_linklocal( + sockaddr_u * psau +) +{ + struct in6_addr * p6addr; + + if (IS_IPV6(psau)) { + p6addr = &psau->sa6.sin6_addr; + if ( IN6_IS_ADDR_LINKLOCAL(p6addr) + || IN6_IS_ADDR_SITELOCAL(p6addr)) { + + return TRUE; + } + } else if (IS_IPV4(psau)) { + /* autoconf are link-local 169.254.0.0/16 */ + if (IS_AUTOCONF(psau)) { + return TRUE; + } + } + return FALSE; +} + + #ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND /* * enable/disable re-use of wildcard address socket @@ -1591,7 +1511,7 @@ set_wildcard_reuse( int on ) { - struct interface *any; + endpt *any; SOCKET fd = INVALID_SOCKET; any = ANY_INTERFACE_BYFAM(family); @@ -1722,13 +1642,18 @@ is_valid( * * toggle configuration phase * - * Phase 1: + * Phase 1a: * forall currently existing interfaces * if address is known: * drop socket - rebind again * * if address is NOT known: - * attempt to create a new interface entry + * Add address to list of new addresses + * + * Phase 1b: + * Scan the list of new addresses marking IPv6 link-local addresses + * which also have a global v6 address using the same OS ifindex. + * Attempt to create a new interface entry * * Phase 2: * forall currently known non MCAST and WILDCARD interfaces @@ -1759,17 +1684,22 @@ update_interfaces( endpt enumep; endpt * ep; endpt * next_ep; + endpt * newaddrs; + endpt * newaddrs_tail; + endpt * ep2; DPRINTF(3, ("update_interfaces(%d)\n", port)); /* - * phase one - scan interfaces - * - create those that are not found - * - update those that are found + * phase 1a - scan OS local addresses + * - update those that ntpd already knows + * - build a list of newly-discovered addresses. */ new_interface_found = FALSE; + nonlocal_v4_addr_up = nonlocal_v6_addr_up = FALSE; iter = NULL; + newaddrs = newaddrs_tail = NULL; result = isc_interfaceiter_create(mctx, &iter); if (result != ISC_R_SUCCESS) @@ -1787,9 +1717,9 @@ update_interfaces( result = isc_interfaceiter_current(iter, &isc_if); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { break; - + } /* See if we have a valid family to use */ family = isc_if.address.family; if (AF_INET != family && AF_INET6 != family) @@ -1855,6 +1785,19 @@ update_interfaces( continue; /* + * Keep track of having non-linklocal connectivity + * for IPv4 and IPv6 so we don't solicit pool hosts + * when it can't work. + */ + if ( !(INT_LOOPBACK & enumep.flags) + && !is_linklocal(&enumep.sin)) { + if (IS_IPV6(&enumep.sin)) { + nonlocal_v6_addr_up = TRUE; + } else { + nonlocal_v4_addr_up = TRUE; + } + } + /* * map to local *address* in order to map all duplicate * interfaces to an endpt structure with the appropriate * socket. Our name space is (ip-address), NOT @@ -1862,107 +1805,132 @@ update_interfaces( */ ep = getinterface(&enumep.sin, INT_WILDCARD); - if (ep != NULL && refresh_interface(ep)) { - /* - * found existing and up to date interface - - * mark present. - */ - 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. - * We reset ignore_packets from the - * new prototype to respect any runtime - * changes to the nic rules. - */ - strlcpy(ep->name, enumep.name, - sizeof(ep->name)); - ep->ignore_packets = - enumep.ignore_packets; + if (NULL == ep) { + ep = emalloc(sizeof(*ep)); + memcpy(ep, &enumep, sizeof(*ep)); + if (NULL != newaddrs_tail) { + newaddrs_tail->elink = ep; + newaddrs_tail = ep; } else { - /* name collision - rename interface */ - strlcpy(ep->name, "*multiple*", - sizeof(ep->name)); + newaddrs_tail = newaddrs = ep; } + continue; + } - DPRINT_INTERFACE(4, (ep, "updating ", - " present\n")); - - if (ep->ignore_packets != - enumep.ignore_packets) { - /* - * We have conflicting configurations - * for the interface address. This is - * caused by using -I <interfacename> - * for an interface that shares its - * address with other interfaces. We - * can not disambiguate incoming - * packets delivered to this socket - * without extra syscalls/features. - * These are not (commonly) available. - * Note this is a more unusual - * configuration where several - * interfaces share an address but - * filtering via interface name is - * attempted. We resolve the - * configuration conflict by disabling - * the processing of received packets. - * This leads to no service on the - * interface address where the conflict - * occurs. - */ - msyslog(LOG_ERR, - "WARNING: conflicting enable configuration for interfaces %s and %s for address %s - unsupported configuration - address DISABLED", - enumep.name, ep->name, - stoa(&enumep.sin)); - - ep->ignore_packets = ISC_TRUE; - } + if (!refresh_interface(ep)) { + /* + * Refreshing failed, we will delete the endpt + * in phase 2 because it was not marked current. + * We can bind to the address as the refresh + * code already closed the endpt's socket. + */ + continue; + } + /* + * found existing and up to date interface - + * mark present. + */ + 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. + * We reset ignore_packets from the + * new prototype to respect any runtime + * changes to the nic rules. + */ + strlcpy(ep->name, enumep.name, sizeof(ep->name)); + ep->ignore_packets = enumep.ignore_packets; + } else { + /* + * DLH: else branch might be dead code from + * when both address and name were compared. + */ + msyslog(LOG_INFO, "%s on %u %s -> *multiple*", + stoa(&ep->sin), ep->ifnum, ep->name); + /* name collision - rename interface */ + strlcpy(ep->name, "*multiple*", sizeof(ep->name)); + } - ep->phase = sys_interphase; + DPRINT_INTERFACE(4, (ep, "updating ", " present\n")); - ifi.action = IFS_EXISTS; - ifi.ep = ep; - if (receiver != NULL) - (*receiver)(data, &ifi); - } else { + if (ep->ignore_packets != enumep.ignore_packets) { /* - * This is new or refreshing failed - add to - * our interface list. If refreshing failed we - * will delete the interface structure in phase - * 2 as the interface was not marked current. - * We can bind to the address as the refresh - * code already closed the offending socket + * We have conflicting configurations for the + * address. This can happen with + * -I <interfacename> on the command line for an + * interface that shares its address with other + * interfaces. We cannot disambiguate incoming + * packets delivered to this socket without extra + * syscalls/features. Note this is an unusual + * configuration where several interfaces share + * an address but filtering via interface name is + * attempted. We resolve the config conflict by + * disabling the processing of received packets. + * This leads to no service on the address where + * the conflict occurs. */ - ep = create_interface(port, &enumep); - - if (ep != NULL) { - ifi.action = IFS_CREATED; - ifi.ep = ep; - if (receiver != NULL) - (*receiver)(data, &ifi); - - new_interface_found = TRUE; - DPRINT_INTERFACE(3, - (ep, "updating ", - " new - created\n")); - } else { - DPRINT_INTERFACE(3, - (&enumep, "updating ", - " new - creation FAILED")); + msyslog(LOG_WARNING, + "conflicting listen configuration between" + " %s and %s for %s, disabled", + enumep.name, ep->name, stoa(&enumep.sin)); - msyslog(LOG_INFO, - "failed to init interface for address %s", - stoa(&enumep.sin)); - continue; - } + ep->ignore_packets = TRUE; + } + + ep->phase = sys_interphase; + + ifi.action = IFS_EXISTS; + ifi.ep = ep; + if (receiver != NULL) { + (*receiver)(data, &ifi); } } isc_interfaceiter_destroy(&iter); /* + * Phase 1b + */ + for (ep = newaddrs; ep != NULL; ep = ep->elink) { + if (IS_IPV6(&ep->sin) && is_linklocal(&ep->sin)) { + for (ep2 = newaddrs; ep2 != NULL; ep2 = ep2->elink) { + if ( IS_IPV6(&ep2->sin) + && ep != ep2 + && !is_linklocal(&ep2->sin)) { + + ep->flags |= INT_LL_OF_GLOB; + break; + } + } + } + } + for (ep2 = newaddrs; ep2 != NULL; ep2 = next_ep) { + next_ep = ep2->elink; + ep2->elink = NULL; + ep = create_interface(port, ep2); + if (ep != NULL) { + ifi.action = IFS_CREATED; + ifi.ep = ep; + if (receiver != NULL) { + (*receiver)(data, &ifi); + } + new_interface_found = TRUE; + DPRINT_INTERFACE(3, + (ep, "updating ", " new - created\n")); + } + else { + DPRINT_INTERFACE(3, + (ep, "updating ", " new - FAILED")); + + msyslog(LOG_ERR, + "cannot bind address %s", + stoa(&ep->sin)); + } + free(ep2); + } + + /* * phase 2 - delete gone interfaces - reassigning peers to * other interfaces */ @@ -1986,20 +1954,20 @@ update_interfaces( ifi.action = IFS_DELETED; ifi.ep = ep; - if (receiver != NULL) + if (receiver != NULL) { (*receiver)(data, &ifi); - + } /* disconnect peers from deleted endpt. */ - while (ep->peers != NULL) + while (ep->peers != NULL) { set_peerdstadr(ep->peers, NULL); - + } /* * update globals in case we lose * a loopback interface */ - if (ep == loopback_interface) + if (ep == loopback_interface) { loopback_interface = NULL; - + } delete_interface(ep); } @@ -2011,20 +1979,20 @@ update_interfaces( */ refresh_all_peerinterfaces(); - if (sys_bclient) + if (sys_bclient) { io_setbclient(); - + } #ifdef MCAST /* * Check multicast interfaces and try to join multicast groups if - * not joined yet. - */ + * not joined yet. + */ for (ep = ep_list; ep != NULL; ep = ep->elink) { remaddr_t *entry; - if (!(INT_MCASTIF & ep->flags) || (INT_MCASTOPEN & ep->flags)) + if (!(INT_MCASTIF & ep->flags) || (INT_MCASTOPEN & ep->flags)) { continue; - + } /* Find remote address that was linked to this interface */ for (entry = remoteaddr_list; entry != NULL; @@ -2084,20 +2052,20 @@ create_sockets( * create_interface - create a new interface for a given prototype * binding the socket. */ -static struct interface * +static endpt * create_interface( - u_short port, - struct interface * protot + u_short port, + endpt * protot ) { sockaddr_u resmask; endpt * iface; + int/*BOOL*/ success; #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)); + DPRINTF(2, ("create_interface(%s)\n", sptoa(&protot->sin))); /* build an interface */ iface = new_interface(protot); @@ -2112,16 +2080,15 @@ create_interface( if ((INT_BROADCAST & iface->flags) && iface->bfd != INVALID_SOCKET) - msyslog(LOG_INFO, "Listening on broadcast address %s#%d", - stoa((&iface->bcast)), port); + msyslog(LOG_INFO, "Listening on broadcast address %s", + sptoa(&iface->bcast)); if (INVALID_SOCKET == iface->fd && INVALID_SOCKET == iface->bfd) { - msyslog(LOG_ERR, "unable to create socket on %s (%d) for %s#%d", + msyslog(LOG_ERR, "unable to create socket on %s (%d) for %s", iface->name, iface->ifnum, - stoa((&iface->sin)), - port); + sptoa(&iface->sin)); delete_interface(iface); return NULL; } @@ -2130,8 +2097,13 @@ create_interface( * Blacklist our own addresses, no use talking to ourself */ SET_HOSTMASK(&resmask, AF(&iface->sin)); - hack_restrict(RESTRICT_FLAGS, &iface->sin, &resmask, - -4, RESM_NTPONLY | RESM_INTERFACE, RES_IGNORE, 0); + success = hack_restrict(RESTRICT_FLAGS, &iface->sin, &resmask, + -4, RESM_NTPONLY | RESM_INTERFACE, + RES_IGNORE, 0); + if (!success) { + msyslog(LOG_ERR, + "unable to self-restrict %s", stoa(&iface->sin)); + } /* * set globals with the first found @@ -2181,6 +2153,85 @@ create_interface( } +#ifdef DEBUG +const char * +iflags_str( + u_int32 iflags +) +{ + const size_t sz = LIB_BUFLENGTH; + char * ifs; + + LIB_GETBUF(ifs); + ifs[0] = '\0'; + + if (iflags & INT_UP) { + CLEAR_BIT_IF_DEBUG(INT_UP, iflags); + append_flagstr(ifs, sz, "up"); + } + + if (iflags & INT_PPP) { + CLEAR_BIT_IF_DEBUG(INT_PPP, iflags); + append_flagstr(ifs, sz, "ppp"); + } + + if (iflags & INT_LOOPBACK) { + CLEAR_BIT_IF_DEBUG(INT_LOOPBACK, iflags); + append_flagstr(ifs, sz, "loopback"); + } + + if (iflags & INT_BROADCAST) { + CLEAR_BIT_IF_DEBUG(INT_BROADCAST, iflags); + append_flagstr(ifs, sz, "broadcast"); + } + + if (iflags & INT_MULTICAST) { + CLEAR_BIT_IF_DEBUG(INT_MULTICAST, iflags); + append_flagstr(ifs, sz, "multicast"); + } + + if (iflags & INT_BCASTOPEN) { + CLEAR_BIT_IF_DEBUG(INT_BCASTOPEN, iflags); + append_flagstr(ifs, sz, "bcastopen"); + } + + if (iflags & INT_MCASTOPEN) { + CLEAR_BIT_IF_DEBUG(INT_MCASTOPEN, iflags); + append_flagstr(ifs, sz, "mcastopen"); + } + + if (iflags & INT_WILDCARD) { + CLEAR_BIT_IF_DEBUG(INT_WILDCARD, iflags); + append_flagstr(ifs, sz, "wildcard"); + } + + if (iflags & INT_MCASTIF) { + CLEAR_BIT_IF_DEBUG(INT_MCASTIF, iflags); + append_flagstr(ifs, sz, "mcastif"); + } + + if (iflags & INT_PRIVACY) { + CLEAR_BIT_IF_DEBUG(INT_PRIVACY, iflags); + append_flagstr(ifs, sz, "IPv6privacy"); + } + + if (iflags & INT_BCASTXMIT) { + CLEAR_BIT_IF_DEBUG(INT_BCASTXMIT, iflags); + append_flagstr(ifs, sz, "bcastxmit"); + } + + if (iflags & INT_LL_OF_GLOB) { + CLEAR_BIT_IF_DEBUG(INT_LL_OF_GLOB, iflags); + append_flagstr(ifs, sz, "linklocal-w-global"); + } + + DEBUG_INVARIANT(!iflags); + + return ifs; +} +#endif /* DEBUG */ + + #ifdef SO_EXCLUSIVEADDRUSE static void set_excladdruse( @@ -2263,8 +2314,8 @@ set_reuseaddr( */ void enable_broadcast( - struct interface * iface, - sockaddr_u * baddr + endpt * iface, + sockaddr_u * baddr ) { #ifdef OPEN_BCAST_SOCKET @@ -2280,9 +2331,9 @@ enable_broadcast( */ static isc_boolean_t socket_broadcast_enable( - struct interface * iface, - SOCKET fd, - sockaddr_u * baddr + endpt * iface, + SOCKET fd, + sockaddr_u * baddr ) { #ifdef SO_BROADCAST @@ -2314,7 +2365,7 @@ socket_broadcast_enable( */ static isc_boolean_t socket_broadcast_disable( - struct interface * iface, + endpt * iface, sockaddr_u * baddr ) { @@ -2337,15 +2388,6 @@ socket_broadcast_disable( #endif /* OPEN_BCAST_SOCKET */ -/* - * return the broadcast client flag value - */ -/*isc_boolean_t -get_broadcastclient_flag(void) -{ - return (broadcast_client_enabled); -} -*/ /* * Check to see if the address is a multicast address @@ -2381,8 +2423,8 @@ addr_ismulticast( */ void enable_multicast_if( - struct interface * iface, - sockaddr_u * maddr + endpt * iface, + sockaddr_u * maddr ) { #ifdef MCAST @@ -2526,7 +2568,7 @@ socket_multicast_enable( #ifdef MCAST static isc_boolean_t socket_multicast_disable( - struct interface * iface, + endpt * iface, sockaddr_u * maddr ) { @@ -2535,8 +2577,6 @@ socket_multicast_disable( # endif struct ip_mreq mreq; - ZERO(mreq); - if (find_addr_in_list(maddr) == NULL) { DPRINTF(4, ("socket_multicast_disable(%s): not found\n", stoa(maddr))); @@ -2546,6 +2586,7 @@ socket_multicast_disable( switch (AF(maddr)) { case AF_INET: + ZERO(mreq); mreq.imr_multiaddr = SOCK_ADDR4(maddr); mreq.imr_interface = SOCK_ADDR4(&iface->sin); if (setsockopt(iface->fd, IPPROTO_IP, @@ -2569,6 +2610,7 @@ socket_multicast_disable( * for other types of multicast addresses. For now let * the kernel figure it out. */ + ZERO(mreq6); mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr); mreq6.ipv6mr_interface = iface->ifindex; @@ -2589,13 +2631,14 @@ socket_multicast_disable( } iface->num_mcast--; - if (!iface->num_mcast) + if (iface->num_mcast <= 0) { iface->flags &= ~INT_MCASTOPEN; - + } return ISC_TRUE; } #endif /* MCAST */ + /* * io_setbclient - open the broadcast client sockets */ @@ -2705,6 +2748,7 @@ io_setbclient(void) #endif /* OPEN_BCAST_SOCKET */ } + /* * io_unsetbclient - close the broadcast client sockets */ @@ -2724,10 +2768,7 @@ io_unsetbclient(void) msyslog(LOG_INFO, "stop listening for broadcasts to %s on interface #%d %s", stoa(&ep->bcast), ep->ifnum, ep->name); -# ifdef HAVE_IO_COMPLETION_PORT - io_completion_port_remove_socket(ep->bfd, ep); -# endif - close_and_delete_fd_from_list(ep->bfd); + close_and_delete_fd_from_list(ep->bfd, ep); ep->bfd = INVALID_SOCKET; } ep->flags &= ~INT_BCASTOPEN; @@ -2735,6 +2776,7 @@ io_unsetbclient(void) broadcast_client_enabled = ISC_FALSE; } + /* * io_multicast_add() - add multicast group address */ @@ -2755,9 +2797,6 @@ io_multicast_add( /* If we already have it we can just return */ if (NULL != find_flagged_addr_in_list(addr, INT_MCASTOPEN)) { - msyslog(LOG_INFO, - "Duplicate request found for multicast address %s", - stoa(addr)); return; } @@ -3041,9 +3080,9 @@ open_socket( #endif ) { msyslog(LOG_ERR, - "bind(%d) AF_INET%s %s#%d%s flags 0x%x failed: %m", + "bind(%d) AF_INET%s %s%s flags 0x%x failed: %m", fd, IS_IPV6(addr) ? "6" : "", - stoa(addr), SRCPORT(addr), + sptoa(addr), IS_MCAST(addr) ? " (multicast)" : "", interf->flags); } @@ -3090,9 +3129,8 @@ open_socket( } #endif - DPRINTF(4, ("bind(%d) AF_INET%s, addr %s%%%d#%d, flags 0x%x\n", - fd, IS_IPV6(addr) ? "6" : "", stoa(addr), - SCOPE(addr), SRCPORT(addr), interf->flags)); + DPRINTF(4, ("bind(%d) addr %s, flags 0x%x\n", + fd, sptoa(addr), interf->flags)); make_socket_nonblocking(fd); @@ -3123,17 +3161,16 @@ open_socket( /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ /* - * sendpkt - send a packet to the specified destination. Maintain a - * send error cache so that only the first consecutive error for a - * destination is logged. + * sendpkt - send a packet to the specified destination from the given endpt + * except for multicast, which may be sent from several addresses. */ void sendpkt( - sockaddr_u * dest, - struct interface * ep, - int ttl, - struct pkt * pkt, - int len + sockaddr_u * dest, + endpt * ep, + int ttl, + struct pkt * pkt, + int len ) { endpt * src; @@ -3145,12 +3182,16 @@ sendpkt( l_fp org, rec, xmt; ismcast = IS_MCAST(dest); - if (!ismcast) + if (!ismcast) { src = ep; - else + } else { +#ifndef MCAST + return; +#endif src = (IS_IPV4(dest)) - ? mc4_list - : mc6_list; + ? mc4_list + : mc6_list; + } if (NULL == src) { /* @@ -3164,13 +3205,14 @@ sendpkt( } do { + if (INT_LL_OF_GLOB & src->flags) { + /* avoid duplicate multicasts on same IPv6 net */ + goto loop; + } DPRINTF(2, ("%ssendpkt(%d, dst=%s, src=%s, ttl=%d, len=%d)\n", ismcast ? "\tMCAST\t***** " : "", src->fd, stoa(dest), stoa(&src->sin), ttl, len)); #ifdef MCAST - /* - * for the moment we use the bcast option to set multicast ttl - */ if (ismcast && ttl > 0 && ttl != src->last_ttl) { /* * set the multicast ttl for outgoing packets @@ -3211,7 +3253,7 @@ sendpkt( cc = simulate_server(dest, src, pkt); #elif defined(HAVE_IO_COMPLETION_PORT) cc = io_completion_port_sendto(src, src->fd, pkt, - (size_t)len, (sockaddr_u *)&dest->sa); + (size_t)len, dest); #else cc = sendto(src->fd, (char *)pkt, (u_int)len, 0, &dest->sa, SOCKLEN(dest)); @@ -3223,6 +3265,7 @@ sendpkt( src->sent++; packets_sent++; } + loop: if (ismcast) src = src->mclink; } while (ismcast && src != NULL); @@ -3241,8 +3284,6 @@ sendpkt( FPTOD(NTOHS_FP(pkt->rootdelay)), FPTOD(NTOHS_FP(pkt->rootdisp)), pkt->refid, len - MIN_V4_PKT_LEN, (u_char *)&pkt->exten); - - return; } @@ -3261,7 +3302,7 @@ fdbits( static char buffer[256]; char * buf = buffer; - count = min(count, 255); + count = min(count, sizeof(buffer) - 1); while (count >= 0) { *buf++ = FD_ISSET(count, set) ? '#' : '-'; @@ -3334,7 +3375,7 @@ read_refclock_packet( */ rb->recv_length = buflen; rb->recv_peer = rp->srcclock; - rb->dstadr = 0; + rb->dstadr = NULL; rb->fd = fd; rb->recv_time = ts; rb->receiver = rp->clock_recv; @@ -3476,9 +3517,9 @@ fetch_timestamp( */ static inline int read_network_packet( - SOCKET fd, - struct interface * itf, - l_fp ts + SOCKET fd, + endpt * itf, + l_fp ts ) { GETSOCKNAME_SOCKLEN_TYPE fromlen; @@ -3580,23 +3621,14 @@ read_network_packet( ** Bug 2672: Some OSes (MacOSX and Linux) don't block spoofed ::1 */ - if (AF_INET6 == itf->family) { - DPRINTF(2, ("Got an IPv6 packet, from <%s> (%d) to <%s> (%d)\n", - stoa(&rb->recv_srcadr), - IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&rb->recv_srcadr)), - stoa(&itf->sin), - !IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&itf->sin)) - )); - - if ( IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&rb->recv_srcadr)) - && !IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&itf->sin)) - ) { - packets_dropped++; - DPRINTF(2, ("DROPPING that packet\n")); - freerecvbuf(rb); - return buflen; - } - DPRINTF(2, ("processing that packet\n")); + if ( IS_IPV6(&rb->recv_srcadr) + && IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&rb->recv_srcadr)) + && !(INT_LOOPBACK & itf->flags)) { + + packets_dropped++; + DPRINTF(2, ("DROPPING pkt with spoofed ::1 source on %s\n", latoa(itf))); + freerecvbuf(rb); + return -1; } /* @@ -3954,8 +3986,9 @@ select_peerinterface( stoa(srcadr))); } else { ep = dstadr; - if (NULL == ep) + if (NULL == ep) { ep = wild; + } } /* * If it is a multicast address, findbcastinter() may not find @@ -3963,16 +3996,19 @@ select_peerinterface( * given to us as the wildcard (ANY_INTERFACE_CHOOSE). Either * way, try a little harder. */ - if (wild == ep) + if (wild == ep) { ep = findinterface(srcadr); + } /* * we do not bind to the wildcard interfaces for output * as our (network) source address would be undefined and * crypto will not work without knowing the own transmit address */ - if (ep != NULL && INT_WILDCARD & ep->flags) - if (!accept_wildcard_if_for_winnt) + if (ep != NULL && (INT_WILDCARD & ep->flags)) { + if (!accept_wildcard_if_for_winnt) { ep = NULL; + } + } #else /* SIM follows */ ep = loopback_interface; #endif @@ -4007,7 +4043,7 @@ findinterface( /* * findlocalinterface - find local interface corresponding to addr, - * which does not have any of flags set. If bast is nonzero, addr is + * which does not have any of flags set. If bcast is nonzero, addr is * a broadcast address. * * This code attempts to find the local sending address for an outgoing @@ -4037,21 +4073,21 @@ findlocalinterface( DPRINTF(4, ("Finding interface for addr %s in list of addresses\n", stoa(addr))); - /* [Bug 3437] The dummy POOL peer comes in with an AF of - * zero. This is bound to fail, but on the way to nowhere it + /* [Bug 3437] The prototype POOL peer can be AF_UNSPEC. + * This is bound to fail, but on the way to nowhere it * triggers a security incident on SELinux. * - * Checking the condition and failing early is probably a good + * Checking the condition and failing early is probably good * advice, and even saves us some syscalls in that case. * Thanks to Miroslav Lichvar for finding this. */ - if (AF_UNSPEC == AF(addr)) + if (AF_UNSPEC == AF(addr)) { return NULL; - + } s = socket(AF(addr), SOCK_DGRAM, 0); - if (INVALID_SOCKET == s) + if (INVALID_SOCKET == s) { return NULL; - + } /* * If we are looking for broadcast interface we need to set this * socket to allow broadcast @@ -4092,14 +4128,18 @@ findlocalinterface( * See http://bugs.ntp.org/1184 and http://bugs.ntp.org/1683 * for more background. */ - if (NULL == iface || iface->ignore_packets) + if (NULL == iface || iface->ignore_packets) { iface = findclosestinterface(&saddr, flags | INT_LOOPBACK); - - /* Don't use an interface which will ignore replies */ - if (iface != NULL && iface->ignore_packets) + } + /* + * Don't select an interface which will ignore replies, or one + * dedicated to multicast receive. + */ + if ( iface != NULL + && (iface->ignore_packets || (INT_MCASTIF & iface->flags))) { iface = NULL; - + } return iface; } @@ -4169,47 +4209,40 @@ calc_addr_distance( const sockaddr_u * a2 ) { - u_int32 a1val; - u_int32 a2val; - u_int32 v4dist; - int found_greater; - int a1_greater; - int i; + u_char * pdist; + const u_char * p1; + const u_char * p2; + size_t cb; + int different; + int a1_greater; + u_int u; REQUIRE(AF(a1) == AF(a2)); ZERO_SOCK(dist); AF(dist) = AF(a1); - /* v4 can be done a bit simpler */ if (IS_IPV4(a1)) { - a1val = SRCADR(a1); - a2val = SRCADR(a2); - v4dist = (a1val > a2val) - ? a1val - a2val - : a2val - a1val; - SET_ADDR4(dist, v4dist); - - return; + pdist = ( u_char *)&NSRCADR(dist); + p1 = (const u_char *)&NSRCADR(a1); + p2 = (const u_char *)&NSRCADR(a2); + } else { + pdist = ( u_char *)&NSRCADR(dist); + p1 = (const u_char *)&NSRCADR(a1); + p2 = (const u_char *)&NSRCADR(a2); } - - found_greater = FALSE; - a1_greater = FALSE; /* suppress pot. uninit. warning */ - for (i = 0; i < (int)sizeof(NSRCADR6(a1)); i++) { - if (!found_greater && - NSRCADR6(a1)[i] != NSRCADR6(a2)[i]) { - found_greater = TRUE; - a1_greater = (NSRCADR6(a1)[i] > NSRCADR6(a2)[i]); + cb = SIZEOF_INADDR(AF(dist)); + different = FALSE; + a1_greater = FALSE; + for (u = 0; u < cb; u++) { + if (!different && p1[u] != p2[u]) { + a1_greater = (p1[u] > p2[u]); + different = TRUE; } - if (!found_greater) { - NSRCADR6(dist)[i] = 0; + if (a1_greater) { + pdist[u] = p1[u] - p2[u]; } else { - if (a1_greater) - NSRCADR6(dist)[i] = NSRCADR6(a1)[i] - - NSRCADR6(a2)[i]; - else - NSRCADR6(dist)[i] = NSRCADR6(a2)[i] - - NSRCADR6(a1)[i]; + pdist[u] = p2[u] - p1[u]; } } } @@ -4468,7 +4501,7 @@ io_closeclock( # ifdef HAVE_IO_COMPLETION_PORT io_completion_port_remove_clock_io(rio); # endif - close_and_delete_fd_from_list(rio->fd); + close_and_delete_fd_from_list(rio->fd, NULL); purge_recv_buffers_for_fd(rio->fd); rio->fd = -1; } @@ -4503,7 +4536,7 @@ kill_asyncio( maxactivefd = 0; while (fd_list != NULL) - close_and_delete_fd_from_list(fd_list->fd); + close_and_delete_fd_from_list(fd_list->fd, NULL); UNBLOCKIO(); } @@ -4531,7 +4564,8 @@ add_fd_to_list( static void close_and_delete_fd_from_list( - SOCKET fd + SOCKET fd, + endpt *ep /* req. if fd is in struct endpt */ ) { vsock_t *lsock; @@ -4545,6 +4579,11 @@ close_and_delete_fd_from_list( switch (lsock->type) { case FD_TYPE_SOCKET: + #ifdef HAVE_IO_COMPLETION_PORT + if (ep != NULL) { + io_completion_port_remove_socket(fd, ep); + } + #endif closesocket(lsock->fd); break; @@ -4635,7 +4674,7 @@ delete_interface_from_list( } -static struct interface * +static endpt * find_addr_in_list( sockaddr_u *addr ) @@ -4707,7 +4746,7 @@ localaddrtoa( static void process_routing_msgs(struct asyncio_reader *reader) { - static char * buffer; + static void * buffer; static size_t buffsz = 8192; int cnt, new, msg_type; socklen_t len; @@ -4716,16 +4755,15 @@ process_routing_msgs(struct asyncio_reader *reader) #else struct rt_msghdr rtm; char *p; + char *endp; #endif - if (disable_dynamic_updates) { + if (scan_addrs_once) { /* * discard ourselves if we are not needed any more * usually happens when running unprivileged */ - remove_asyncio_reader(reader); - delete_asyncio_reader(reader); - return; + goto disable; } if (NULL == buffer) { @@ -4758,22 +4796,20 @@ process_routing_msgs(struct asyncio_reader *reader) disable: remove_asyncio_reader(reader); delete_asyncio_reader(reader); + return; } - return; } /* * process routing message */ #ifdef HAVE_RTNETLINK - for (nh = UA_PTR(struct nlmsghdr, buffer); - NLMSG_OK(nh, cnt); - nh = NLMSG_NEXT(nh, cnt)) + for (nh = buffer; NLMSG_OK(nh, cnt); nh = NLMSG_NEXT(nh, cnt)) { msg_type = nh->nlmsg_type; #else - for (p = buffer; - (p + sizeof(struct rt_msghdr)) <= (buffer + cnt); + for (p = buffer, endp = p + cnt; + (p + sizeof(struct rt_msghdr)) <= endp; p += rtm.rtm_msglen) { memcpy(&rtm, p, sizeof(rtm)); @@ -4787,7 +4823,7 @@ process_routing_msgs(struct asyncio_reader *reader) return; } msg_type = rtm.rtm_type; -#endif +#endif /* !HAVE_RTNETLINK */ switch (msg_type) { #ifdef RTM_NEWADDR case RTM_NEWADDR: @@ -4835,7 +4871,7 @@ process_routing_msgs(struct asyncio_reader *reader) */ DPRINTF(3, ("routing message op = %d: scheduling interface update\n", msg_type)); - timer_interfacetimeout(current_time + UPDATE_GRACE); + endpt_scan_timer = UPDATE_GRACE + current_time; break; #ifdef HAVE_RTNETLINK case NLMSG_DONE: @@ -4857,14 +4893,14 @@ process_routing_msgs(struct asyncio_reader *reader) * set up routing notifications */ static void -init_async_notifications() +init_async_notifications(void) { struct asyncio_reader *reader; #ifdef HAVE_RTNETLINK int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); struct sockaddr_nl sa; #else - int fd = socket(PF_ROUTE, SOCK_RAW, 0); + int fd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); #endif if (fd < 0) { msyslog(LOG_ERR, @@ -4908,4 +4944,3 @@ init_async_notifications(void) { } #endif - |