diff options
Diffstat (limited to 'ntpd/ntp_io.c')
-rw-r--r-- | ntpd/ntp_io.c | 240 |
1 files changed, 155 insertions, 85 deletions
diff --git a/ntpd/ntp_io.c b/ntpd/ntp_io.c index faa46461f484..5cf9f1d858d4 100644 --- a/ntpd/ntp_io.c +++ b/ntpd/ntp_io.c @@ -94,7 +94,12 @@ extern const char *specific_interface; #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) #endif -#endif +/* + * Windows C runtime ioctl() can't deal properly with sockets, + * map to ioctlsocket for this source file. + */ +#define ioctl(fd, opt, val) ioctlsocket((fd), (opt), (u_long *)(val)) +#endif /* SYS_WINNT */ /* * We do asynchronous input using the SIGIO facility. A number of @@ -194,7 +199,7 @@ static isc_boolean_t socket_multicast_disable P((struct interface *, struct sock static void print_interface P((struct interface *, char *, char *)); #define DPRINT_INTERFACE(_LVL_, _ARGS_) do { if (debug >= (_LVL_)) { print_interface _ARGS_; } } while (0) #else -#define DPRINT_INTERFACE(_LVL_, _ARGS_) +#define DPRINT_INTERFACE(_LVL_, _ARGS_) do {} while (0) #endif typedef struct vsock vsock_t; @@ -289,23 +294,29 @@ static inline int read_refclock_packet P((SOCKET, struct refclockio *, l_fp) * systems are not affected by this and work correctly. * See Microsoft Knowledge Base Article Q263823 for details of this. */ -isc_result_t -connection_reset_fix(SOCKET fd) { +void +connection_reset_fix( + SOCKET fd, + struct sockaddr_storage *addr + ) +{ DWORD dwBytesReturned = 0; BOOL bNewBehavior = FALSE; DWORD status; - if(isc_win32os_majorversion() < 5) - return (ISC_R_SUCCESS); /* NT 4.0 has no problem */ - - /* disable bad behavior using IOCTL: SIO_UDP_CONNRESET */ - status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior, - sizeof(bNewBehavior), NULL, 0, - &dwBytesReturned, NULL, NULL); - if (status != SOCKET_ERROR) - return (ISC_R_SUCCESS); - else - return (ISC_R_UNEXPECTED); + /* + * disable bad behavior using IOCTL: SIO_UDP_CONNRESET + * NT 4.0 has no problem + */ + if (isc_win32os_majorversion() >= 5) { + status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior, + sizeof(bNewBehavior), NULL, 0, + &dwBytesReturned, NULL, NULL); + if (SOCKET_ERROR == status) + netsyslog(LOG_ERR, "connection_reset_fix() " + "failed for address %s: %m", + stoa(addr)); + } } #endif @@ -477,6 +488,8 @@ void init_io(void) { #ifdef SYS_WINNT + init_io_completion_port(); + if (!Win32InitSockets()) { netsyslog(LOG_ERR, "No useable winsock.dll: %m"); @@ -748,6 +761,24 @@ delete_interface(struct interface *interface) static void add_interface(struct interface *interface) { + static struct interface *listhead = NULL; + + /* + * For ntpd, the first few interfaces (wildcard, localhost) + * will never be removed. This means inter_list.head is + * unchanging once initialized. Take advantage of that to + * watch for changes and catch corruption earlier. This + * helped track down corruption caused by using FD_SET with + * a descriptor numerically larger than FD_SETSIZE. + */ + if (NULL == listhead) + listhead = inter_list.head; + + if (listhead != inter_list.head) { + msyslog(LOG_ERR, "add_interface inter_list.head corrupted: was %p now %p", + listhead, inter_list.head); + exit(1); + } /* * Calculate the address hash */ @@ -1184,7 +1215,7 @@ update_interfaces( scan_ipv6 = ISC_TRUE; #if defined(DEBUG) else - if(debug) + if (debug) netsyslog(LOG_ERR, "no IPv6 interfaces found"); #endif #endif @@ -1192,7 +1223,7 @@ update_interfaces( scan_ipv6 = ISC_TRUE; #if defined(ISC_PLATFORM_HAVEIPV6) && defined(DEBUG) else - if(debug) + if (debug) netsyslog(LOG_ERR, "no IPv6 interfaces found"); #endif @@ -1501,6 +1532,24 @@ create_interface( return interface; } + +#ifdef SO_EXCLUSIVEADDRUSE +static void +set_excladdruse(int fd) +{ + int one = 1; + int failed; + + failed = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, + (char *)&one, sizeof(one)); + + if (failed) + netsyslog(LOG_ERR, + "setsockopt(%d, SO_EXCLUSIVEADDRUSE, on): %m", fd); +} +#endif /* SO_EXCLUSIVEADDRUSE */ + + /* * set_reuseaddr() - set/clear REUSEADDR on all sockets * NB possible hole - should we be doing this on broadcast @@ -1508,13 +1557,16 @@ create_interface( */ static void set_reuseaddr(int flag) { - struct interface *interf; + struct interface *interf; + +#ifndef SO_EXCLUSIVEADDRUSE for (interf = ISC_LIST_HEAD(inter_list); interf != NULL; interf = ISC_LIST_NEXT(interf, link)) { - if (interf->flags & INT_WILDCARD) - continue; + + if (interf->flags & INT_WILDCARD) + continue; /* * if interf->fd is INVALID_SOCKET, we might have a adapter @@ -1530,6 +1582,7 @@ set_reuseaddr(int flag) { } } } +#endif /* ! SO_EXCLUSIVEADDRUSE */ } /* @@ -1691,7 +1744,7 @@ enable_multicast_if(struct interface *iface, struct sockaddr_storage *maddr) case AF_INET6: #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, - &iface->scopeid, sizeof(iface->scopeid)) == -1) { + (char *) &iface->scopeid, sizeof(iface->scopeid)) == -1) { netsyslog(LOG_ERR, "setsockopt IPV6_MULTICAST_IF failure: %m on socket %d, addr %s, scope %d for multicast address %s", iface->fd, stoa(&iface->sin), iface->scopeid, @@ -1703,7 +1756,7 @@ enable_multicast_if(struct interface *iface, struct sockaddr_storage *maddr) * Don't send back to itself, but allow it to fail to set it */ if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, - &off, sizeof(off)) == -1) { + (char *) &off, sizeof(off)) == -1) { netsyslog(LOG_ERR, "setsockopt IP_MULTICAST_LOOP failure: %m on socket %d, addr %s for multicast address %s", iface->fd, stoa(&iface->sin), stoa(maddr)); @@ -1981,7 +2034,10 @@ io_multicast_add( ) { #ifdef MCAST - struct interface *interface, *iface; + struct interface *interface; +#ifndef MULTICAST_NONEWSOCKET + struct interface *iface; +#endif int lscope = 0; /* @@ -2058,7 +2114,7 @@ io_multicast_add( } else { - delete_interface(interface); /* re-use existing interface */ + delete_interface(interface); /* re-use existing interface */ interface = NULL; if (addr.ss_family == AF_INET) interface = wildipv4; @@ -2227,12 +2283,7 @@ static void init_nonblocking_io(SOCKET fd) #elif defined(FIONBIO) { int on = 1; -# if defined(SYS_WINNT) - - if (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) -# else if (ioctl(fd,FIONBIO,&on) < 0) -# endif { netsyslog(LOG_ERR, "ioctl(FIONBIO) fails on fd #%d: %m", fd); @@ -2267,8 +2318,13 @@ open_socket( { int errval; SOCKET fd; - int on = 1, off = 0; /* int is OK for REUSEADR per */ - /* http://www.kohala.com/start/mcast.api.txt */ + /* + * int is OK for REUSEADR per + * http://www.kohala.com/start/mcast.api.txt + */ + int on = 1; + int off = 0; + #if defined(IPTOS_LOWDELAY) && defined(IPPROTO_IP) && defined(IP_TOS) int tos; #endif /* IPTOS_LOWDELAY && IPPROTO_IP && IP_TOS */ @@ -2277,38 +2333,30 @@ open_socket( return (INVALID_SOCKET); /* create a datagram (UDP) socket */ + fd = socket(addr->ss_family, SOCK_DGRAM, 0); + if (INVALID_SOCKET == fd) { #ifndef SYS_WINNT - if ( (fd = socket(addr->ss_family, SOCK_DGRAM, 0)) < 0) { errval = errno; #else - if ( (fd = socket(addr->ss_family, SOCK_DGRAM, 0)) == INVALID_SOCKET) { errval = WSAGetLastError(); #endif - if(addr->ss_family == AF_INET) - netsyslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed on address %s: %m", - stoa(addr)); - else if(addr->ss_family == AF_INET6) - netsyslog(LOG_ERR, "socket(AF_INET6, SOCK_DGRAM, 0) failed on address %s: %m", - stoa(addr)); -#ifndef SYS_WINNT - if (errval == EPROTONOSUPPORT || errval == EAFNOSUPPORT || + netsyslog(LOG_ERR, + "socket(AF_INET%s, SOCK_DGRAM, 0) failed on address %s: %m", + (addr->ss_family == AF_INET6) ? "6" : "", + stoa(addr)); + + if (errval == EPROTONOSUPPORT || + errval == EAFNOSUPPORT || errval == EPFNOSUPPORT) -#else - if (errval == WSAEPROTONOSUPPORT || errval == WSAEAFNOSUPPORT || - errval == WSAEPFNOSUPPORT) -#endif return (INVALID_SOCKET); msyslog(LOG_ERR, "unexpected error code %d (not PROTONOSUPPORT|AFNOSUPPORT|FPNOSUPPORT) - exiting", errval); exit(1); /*NOTREACHED*/ } -#ifdef SYS_WINNT - if (connection_reset_fix(fd) != ISC_R_SUCCESS) { - netsyslog(LOG_ERR, "connection_reset_fix(fd) failed on address %s: %m", - stoa(addr)); - } -#endif /* SYS_WINNT */ +#ifdef SYS_WINNT + connection_reset_fix(fd, addr); +#endif /* * Fixup the file descriptor for some systems * See bug #530 for details of the issue. @@ -2317,18 +2365,36 @@ open_socket( /* * set SO_REUSEADDR since we will be binding the same port - * number on each interface according to flag + * number on each interface according to turn_off_reuse. + * This is undesirable on Windows versions starting with + * Windows XP (numeric version 5.1). */ - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - turn_off_reuse ? (char *)&off : (char *)&on, sizeof(on))) - { - netsyslog(LOG_ERR, "setsockopt SO_REUSEADDR %s on fails on address %s: %m", - turn_off_reuse ? "off" : "on", stoa(addr)); - - closesocket(fd); - - return INVALID_SOCKET; - } +#ifdef SYS_WINNT + if (isc_win32os_versioncheck(5, 1, 0, 0) < 0) /* before 5.1 */ +#endif + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (char *)(turn_off_reuse + ? &off + : &on), + sizeof(on))) { + + netsyslog(LOG_ERR, "setsockopt SO_REUSEADDR %s" + " fails for address %s: %m", + turn_off_reuse + ? "off" + : "on", + stoa(addr)); + closesocket(fd); + return INVALID_SOCKET; + } +#ifdef SO_EXCLUSIVEADDRUSE + /* + * setting SO_EXCLUSIVEADDRUSE on the wildcard we open + * first will cause more specific binds to fail. + */ + if (!(interf->flags & INT_WILDCARD)) + set_excladdruse(fd); +#endif /* * IPv4 specific options go here @@ -2406,22 +2472,24 @@ open_socket( ) { if (addr->ss_family == AF_INET) netsyslog(LOG_ERR, - "bind() fd %d, family %d, port %d, addr %s, in_classd=%d flags=0x%x fails: %m", - fd, addr->ss_family, (int)ntohs(((struct sockaddr_in*)addr)->sin_port), + "bind() fd %d, family AF_INET, port %d, addr %s, in_classd=%d flags=0x%x fails: %m", + fd, (int)ntohs(((struct sockaddr_in*)addr)->sin_port), stoa(addr), - IN_CLASSD(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr)), flags); + IN_CLASSD(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr)), + flags); #ifdef INCLUDE_IPV6_SUPPORT else if (addr->ss_family == AF_INET6) - netsyslog(LOG_ERR, - "bind() fd %d, family %d, port %d, scope %d, addr %s, in6_is_addr_multicast=%d flags=0x%x fails: %m", - fd, addr->ss_family, (int)ntohs(((struct sockaddr_in6*)addr)->sin6_port), + netsyslog(LOG_ERR, + "bind() fd %d, family AF_INET6, port %d, scope %d, addr %s, mcast=%d flags=0x%x fails: %m", + fd, (int)ntohs(((struct sockaddr_in6*)addr)->sin6_port), # ifdef ISC_PLATFORM_HAVESCOPEID ((struct sockaddr_in6*)addr)->sin6_scope_id # else -1 # endif , stoa(addr), - IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr), flags); + IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr), + flags); #endif } @@ -2452,7 +2520,7 @@ open_socket( addr->ss_family, (int)ntohs(((struct sockaddr_in*)addr)->sin_port), stoa(addr), - flags)); + interf->flags)); init_nonblocking_io(fd); @@ -2496,9 +2564,6 @@ sendpkt( ) { int cc, slot; -#ifdef SYS_WINNT - DWORD err; -#endif /* SYS_WINNT */ /* * Send error caches. Empty slots have port == 0 @@ -2618,8 +2683,8 @@ sendpkt( #endif /* INCLUDE_IPV6_SUPPORT */ #if defined(HAVE_IO_COMPLETION_PORT) - err = io_completion_port_sendto(inter, pkt, len, dest); - if (err != ERROR_SUCCESS) + cc = io_completion_port_sendto(inter, pkt, len, dest); + if (cc != ERROR_SUCCESS) #else #ifdef SIM cc = srvr_rply(&ntp_node, dest, inter, pkt); @@ -2632,9 +2697,9 @@ sendpkt( { inter->notsent++; packets_notsent++; + #if defined(HAVE_IO_COMPLETION_PORT) - err = WSAGetLastError(); - if (err != WSAEWOULDBLOCK && err != WSAENOBUFS && slot < 0) + if (cc != WSAEWOULDBLOCK && cc != WSAENOBUFS && slot < 0) #else if (errno != EWOULDBLOCK && errno != ENOBUFS && slot < 0) #endif @@ -2659,13 +2724,13 @@ sendpkt( case AF_INET6 : for (slot = ERRORCACHESIZE; --slot >= 0; ) - if (badaddrs6[slot].port == 0) - { - badaddrs6[slot].port = SRCPORT(dest); - badaddrs6[slot].addr = ((struct sockaddr_in6*)dest)->sin6_addr; - break; - } - break; + if (badaddrs6[slot].port == 0) + { + badaddrs6[slot].port = SRCPORT(dest); + badaddrs6[slot].addr = ((struct sockaddr_in6*)dest)->sin6_addr; + break; + } + break; #endif /* INCLUDE_IPV6_SUPPORT */ default: /* don't care if not supported */ break; @@ -3207,7 +3272,7 @@ findlocalinterface( struct interface *iface; DPRINTF(4, ("Finding interface for addr %s in list of addresses\n", - stoa(addr));) + stoa(addr))); memset(&saddr, 0, sizeof(saddr)); saddr.ss_family = addr->ss_family; @@ -3624,6 +3689,11 @@ add_fd_to_list(SOCKET fd, enum desc_type type) { * I/O Completion Ports don't care about the select and FD_SET */ #ifndef HAVE_IO_COMPLETION_PORT + if (fd < 0 || fd >= FD_SETSIZE) { + msyslog(LOG_ERR, "Too many sockets in use, FD_SETSIZE %d exceeded", + FD_SETSIZE); + exit(1); + } /* * keep activefds in sync */ |