diff options
Diffstat (limited to 'contrib/ntp/ntpd/ntp_io.c')
-rw-r--r-- | contrib/ntp/ntpd/ntp_io.c | 1933 |
1 files changed, 1214 insertions, 719 deletions
diff --git a/contrib/ntp/ntpd/ntp_io.c b/contrib/ntp/ntpd/ntp_io.c index ef0c146..9f2acea 100644 --- a/contrib/ntp/ntpd/ntp_io.c +++ b/contrib/ntp/ntpd/ntp_io.c @@ -14,6 +14,17 @@ #include "ntp_refclock.h" #include "ntp_if.h" #include "ntp_stdlib.h" +#include "ntp.h" + +/* Don't include ISC's version of IPv6 variables and structures */ +#define ISC_IPV6_H 1 +#include <isc/interfaceiter.h> +#include <isc/list.h> +#include <isc/result.h> + +#ifdef SIM +#include "ntpsim.h" +#endif #include <stdio.h> #include <signal.h> @@ -43,46 +54,20 @@ extern int listen_to_virtual_ips; -#if _BSDI_VERSION >= 199510 -# include <ifaddrs.h> +#if defined(SYS_WINNT) +#include <transmitbuff.h> +#include <isc/win32os.h> +/* + * Define this macro to control the behavior of connection + * resets on UDP sockets. See Microsoft KnowledgeBase Article Q263823 + * for details. + * NOTE: This requires that Windows 2000 systems install Service Pack 2 + * or later. + */ +#ifndef SIO_UDP_CONNRESET +#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) #endif -#if defined(VMS) /* most likely UCX-specific */ - -#include <UCX$INETDEF.H> - -/* "un*x"-compatible names for some items in UCX$INETDEF.H */ -#define ifreq IFREQDEF -#define ifr_name IFR$T_NAME -#define ifr_addr IFR$R_DUMMY.IFR$T_ADDR -#define ifr_broadaddr IFR$R_DUMMY.IFR$T_BROADADDR -#define ifr_flags IFR$R_DUMMY.IFR$R_DUMMY_1_OVRL.IFR$W_FLAGS -#define IFF_UP IFR$M_IFF_UP -#define IFF_BROADCAST IFR$M_IFF_BROADCAST -#define IFF_LOOPBACK IFR$M_IFF_LOOPBACK - -#endif /* VMS */ - - -#if defined(VMS) || defined(SYS_WINNT) -/* structure used in SIOCGIFCONF request (after [KSR] OSF/1) */ -struct ifconf { - int ifc_len; /* size of buffer */ - union { - caddr_t ifcu_buf; - struct ifreq *ifcu_req; - } ifc_ifcu; -}; -#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ -#define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ - -#endif /* VMS */ - -#if defined(USE_TTY_SIGPOLL) || defined(USE_UDP_SIGPOLL) -# if defined(SYS_AIX) && defined(_IO) /* XXX Identify AIX some other way */ -# undef _IO -# endif -# include <stropts.h> #endif /* @@ -118,10 +103,15 @@ u_long io_timereset; /* time counters were reset */ /* * Interface stuff */ -struct interface *any_interface; /* default interface */ -struct interface *loopback_interface; /* loopback interface */ -struct interface inter_list[MAXINTERFACES]; -int ninterfaces; +struct interface *any_interface; /* default ipv4 interface */ +struct interface *any6_interface; /* default ipv6 interface */ +struct interface *loopback_interface; /* loopback ipv4 interface */ +struct interface *loopback6_interface; /* loopback ipv6 interface */ +struct interface inter_list[MAXINTERFACES]; /* Interface list */ +int ninterfaces; /* Total number of interfaces */ +int nwilds; /* Total number of wildcard intefaces */ +int wildipv4 = -1; /* Index into inter_list for IPv4 wildcard */ +int wildipv6 = -1; /* Index into inter_list for IPv6 wildcard */ #ifdef REFCLOCK /* @@ -131,18 +121,94 @@ int ninterfaces; static struct refclockio *refio; #endif /* REFCLOCK */ + +/* + * Define what the possible "soft" errors can be. These are non-fatal returns + * of various network related functions, like recv() and so on. + * + * For some reason, BSDI (and perhaps others) will sometimes return <0 + * from recv() but will have errno==0. This is broken, but we have to + * work around it here. + */ +#define SOFT_ERROR(e) ((e) == EAGAIN || \ + (e) == EWOULDBLOCK || \ + (e) == EINTR || \ + (e) == 0) + /* * File descriptor masks etc. for call to select + * Not needed for I/O Completion Ports */ fd_set activefds; int maxactivefd; -static int create_sockets P((u_int)); -static int open_socket P((struct sockaddr_in *, int, int)); -static void close_socket P((int)); -static void close_file P((int)); +static int create_sockets P((u_short)); +static SOCKET open_socket P((struct sockaddr_storage *, int, int)); +static void close_socket P((SOCKET)); +#ifdef REFCLOCK +static void close_file P((SOCKET)); +#endif static char * fdbits P((int, fd_set *)); +static void set_reuseaddr P((int)); + +typedef struct vsock vsock_t; + +struct vsock { + SOCKET fd; + ISC_LINK(vsock_t) link; +}; + +ISC_LIST(vsock_t) sockets_list; + +typedef struct remaddr remaddr_t; + +struct remaddr { + struct sockaddr_storage addr; + int if_index; + ISC_LINK(remaddr_t) link; +}; + +ISC_LIST(remaddr_t) remoteaddr_list; + +void add_socket_to_list P((SOCKET)); +void delete_socket_from_list P((SOCKET)); +void add_addr_to_list P((struct sockaddr_storage *, int)); +void delete_addr_from_list P((struct sockaddr_storage *)); +int find_addr_in_list P((struct sockaddr_storage *)); +int create_wildcards P((u_short)); +isc_boolean_t address_okay P((isc_interface_t *)); +void convert_isc_if P((isc_interface_t *, struct interface *, u_short)); +#ifdef SYS_WINNT +/* + * Windows 2000 systems incorrectly cause UDP sockets using WASRecvFrom + * to not work correctly, returning a WSACONNRESET error when a WSASendTo + * fails with an "ICMP port unreachable" response and preventing the + * socket from using the WSARecvFrom in subsequent operations. + * The function below fixes this, but requires that Windows 2000 + * Service Pack 2 or later be installed on the system. NT 4.0 + * 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) { + 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); +} +#endif /* * init_io - initialize I/O data structures and call socket creation routine */ @@ -150,8 +216,6 @@ void init_io(void) { #ifdef SYS_WINNT - WORD wVersionRequested; - WSADATA wsaData; init_transmitbuff(); #endif /* SYS_WINNT */ @@ -165,7 +229,8 @@ init_io(void) packets_sent = packets_notsent = 0; handler_calls = handler_pkts = 0; io_timereset = 0; - loopback_interface = 0; + loopback_interface = NULL; + loopback6_interface = NULL; #ifdef REFCLOCK refio = 0; @@ -176,14 +241,17 @@ init_io(void) #endif #ifdef SYS_WINNT - wVersionRequested = MAKEWORD(1,1); - if (WSAStartup(wVersionRequested, &wsaData)) + if (!Win32InitSockets()) { - msyslog(LOG_ERR, "No useable winsock.dll: %m"); + netsyslog(LOG_ERR, "No useable winsock.dll: %m"); exit(1); } #endif /* SYS_WINNT */ + ISC_LIST_INIT(sockets_list); + + ISC_LIST_INIT(remoteaddr_list); + /* * Create the sockets */ @@ -197,456 +265,274 @@ init_io(void) #endif } -/* - * create_sockets - create a socket for each interface plus a default - * socket for when we don't know where to send - */ -static int -create_sockets( - u_int port - ) -{ -#if _BSDI_VERSION >= 199510 - int i, j; - struct ifaddrs *ifaddrs, *ifap; - struct sockaddr_in resmask; -#if _BSDI_VERSION < 199701 - struct ifaddrs *lp; - int num_if; -#endif -#else /* _BSDI_VERSION >= 199510 */ -# ifdef STREAMS_TLI - struct strioctl ioc; -# endif /* STREAMS_TLI */ - char buf[MAXINTERFACES*sizeof(struct ifreq)]; - struct ifconf ifc; - struct ifreq ifreq, *ifr; - int n, i, j, vs, size = 0; - struct sockaddr_in resmask; -#endif /* _BSDI_VERSION >= 199510 */ +int +create_wildcards(u_short port) { -#ifdef DEBUG - if (debug) - printf("create_sockets(%d)\n", ntohs( (u_short) port)); -#endif + int idx = 0; + /* + * create pseudo-interface with wildcard IPv4 address + */ + inter_list[idx].sin.ss_family = AF_INET; + ((struct sockaddr_in*)&inter_list[idx].sin)->sin_addr.s_addr = htonl(INADDR_ANY); + ((struct sockaddr_in*)&inter_list[idx].sin)->sin_port = port; + (void) strncpy(inter_list[idx].name, "wildcard", sizeof(inter_list[idx].name)); + inter_list[idx].mask.ss_family = AF_INET; + ((struct sockaddr_in*)&inter_list[idx].mask)->sin_addr.s_addr = htonl(~(u_int32)0); + inter_list[idx].bfd = INVALID_SOCKET; + inter_list[idx].num_mcast = 0; + inter_list[idx].received = 0; + inter_list[idx].sent = 0; + inter_list[idx].notsent = 0; + inter_list[idx].flags = INT_BROADCAST; + any_interface = &inter_list[idx]; +#if defined(MCAST) + /* + * enable possible multicast reception on the broadcast socket + */ + inter_list[idx].bcast.ss_family = AF_INET; + ((struct sockaddr_in*)&inter_list[idx].bcast)->sin_port = port; + ((struct sockaddr_in*)&inter_list[idx].bcast)->sin_addr.s_addr = htonl(INADDR_ANY); +#endif /* MCAST */ + wildipv4 = idx; + idx++; +#ifdef HAVE_IPV6 /* - * create pseudo-interface with wildcard address + * create pseudo-interface with wildcard IPv6 address */ - inter_list[0].sin.sin_family = AF_INET; - inter_list[0].sin.sin_port = port; - inter_list[0].sin.sin_addr.s_addr = htonl(INADDR_ANY); - (void) strncpy(inter_list[0].name, "wildcard", - sizeof(inter_list[0].name)); - inter_list[0].mask.sin_addr.s_addr = htonl(~ (u_int32)0); - inter_list[0].received = 0; - inter_list[0].sent = 0; - inter_list[0].notsent = 0; - inter_list[0].flags = INT_BROADCAST; - any_interface = &inter_list[0]; - -#if _BSDI_VERSION >= 199510 -#if _BSDI_VERSION >= 199701 - if (getifaddrs(&ifaddrs) < 0) - { - msyslog(LOG_ERR, "getifaddrs: %m"); - exit(1); + if (isc_net_probeipv6() == ISC_R_SUCCESS) { + inter_list[idx].sin.ss_family = AF_INET6; + ((struct sockaddr_in6*)&inter_list[idx].sin)->sin6_addr = in6addr_any; + ((struct sockaddr_in6*)&inter_list[idx].sin)->sin6_port = port; + (void) strncpy(inter_list[idx].name, "wildcard", sizeof(inter_list[idx].name)); + inter_list[idx].mask.ss_family = AF_INET6; + memset(&((struct sockaddr_in6*)&inter_list[idx].mask)->sin6_addr.s6_addr, 0xff, sizeof(struct in6_addr)); + inter_list[idx].bfd = INVALID_SOCKET; + inter_list[idx].num_mcast = 0; + inter_list[idx].received = 0; + inter_list[idx].sent = 0; + inter_list[idx].notsent = 0; + inter_list[idx].flags = 0; + any6_interface = &inter_list[idx]; + wildipv6 = idx; + idx++; } - i = 1; - for (ifap = ifaddrs; ifap != NULL; ifap = ifap->ifa_next) -#else - if (getifaddrs(&ifaddrs, &num_if) < 0) - { - msyslog(LOG_ERR, "create_sockets: getifaddrs() failed: %m"); - exit(1); - } +#endif + return (idx); +} - i = 1; +isc_boolean_t +address_okay(isc_interface_t *isc_if) { - for (ifap = ifaddrs, lp = ifap + num_if; ifap < lp; ifap++) +#ifdef DEBUG + if (debug > 2) + printf("address_okay: listen Virtual: %d, IF name: %s, Up Flag: %d\n", + listen_to_virtual_ips, isc_if->name, (isc_if->flags & INTERFACE_F_UP)); #endif - { - struct sockaddr_in *sin; - if (!ifap->ifa_addr) - continue; + if (listen_to_virtual_ips == 0 && (strchr(isc_if->name, (int)':') != NULL)) + return (ISC_FALSE); - if (ifap->ifa_addr->sa_family != AF_INET) - continue; + /* XXXPDM This should be fixed later, but since we may not have set + * the UP flag, we at least get to use the interface. + * The UP flag is not always set so we don't do this right now. + */ +/* if ((isc_if->flags & INTERFACE_F_UP) == 0) + return (ISC_FALSE); +*/ + return (ISC_TRUE); +} +void +convert_isc_if(isc_interface_t *isc_if, struct interface *itf, u_short port) { + + if(isc_if->af == AF_INET) { + itf->sin.ss_family = (u_short) isc_if->af; + strcpy(itf->name, isc_if->name); + memcpy(&(((struct sockaddr_in*)&itf->sin)->sin_addr), + &(isc_if->address.type.in), + sizeof(struct in_addr)); + ((struct sockaddr_in*)&itf->sin)->sin_port = port; + + if((isc_if->flags & INTERFACE_F_BROADCAST) != 0) { + itf->flags |= INT_BROADCAST; + itf->bcast.ss_family = itf->sin.ss_family; + memcpy(&(((struct sockaddr_in*)&itf->bcast)->sin_addr), + &(isc_if->broadcast.type.in), + sizeof(struct in_addr)); + ((struct sockaddr_in*)&itf->bcast)->sin_port = port; + } - if ((ifap->ifa_flags & IFF_UP) == 0) - continue; + itf->mask.ss_family = itf->sin.ss_family; + memcpy(&(((struct sockaddr_in*)&itf->mask)->sin_addr), + &(isc_if->netmask.type.in), + sizeof(struct in_addr)); + ((struct sockaddr_in*)&itf->mask)->sin_port = port; - if (debug) - printf("after getifaddrs(), considering %s (%s)\n", - ifap->ifa_name, - inet_ntoa(((struct sockaddr_in *)ifap->ifa_addr)->sin_addr)); - - if (ifap->ifa_flags & IFF_LOOPBACK) { - sin = (struct sockaddr_in *)ifap->ifa_addr; - if (ntohl(sin->sin_addr.s_addr) != 0x7f000001 && - !listen_to_virtual_ips) - continue; - } - inter_list[i].flags = 0; - if (ifap->ifa_flags & IFF_BROADCAST) - inter_list[i].flags |= INT_BROADCAST; - strcpy(inter_list[i].name, ifap->ifa_name); - sin = (struct sockaddr_in *)ifap->ifa_addr; - inter_list[i].sin = *sin; - inter_list[i].sin.sin_port = port; - if (ifap->ifa_flags & IFF_LOOPBACK) { - inter_list[i].flags = INT_LOOPBACK; - if (loopback_interface == NULL - || ntohl(sin->sin_addr.s_addr) != 0x7f000001) - loopback_interface = &inter_list[i]; - } - if (inter_list[i].flags & INT_BROADCAST) { - sin = (struct sockaddr_in *)ifap->ifa_broadaddr; - inter_list[i].bcast = *sin; - inter_list[i].bcast.sin_port = port; - } - if (ifap->ifa_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) { - inter_list[i].mask.sin_addr.s_addr = 0xffffffff; - } else { - sin = (struct sockaddr_in *)ifap->ifa_netmask; - inter_list[i].mask = *sin; + if (((isc_if->flags & INTERFACE_F_LOOPBACK) != 0) && (loopback_interface == NULL)) + { + loopback_interface = itf; } - inter_list[i].mask.sin_family = AF_INET; - inter_list[i].mask.sin_len = sizeof *sin; - - /* - * look for an already existing source interface address. If - * the machine has multiple point to point interfaces, then - * the local address may appear more than once. - * - * A second problem exists if we have two addresses on - * the same network (via "ifconfig alias ..."). Don't - * make two xntp interfaces for the two aliases on the - * one physical interface. -wsr - */ - for (j=0; j < i; j++) - if ((inter_list[j].sin.sin_addr.s_addr & - inter_list[j].mask.sin_addr.s_addr) == - (inter_list[i].sin.sin_addr.s_addr & - inter_list[i].mask.sin_addr.s_addr)) - { - if (inter_list[j].flags & INT_LOOPBACK) - inter_list[j] = inter_list[i]; - break; - } - if (j == i) - i++; - if (i > MAXINTERFACES) - break; } - free(ifaddrs); -#else /* _BSDI_VERSION >= 199510 */ -# ifdef USE_STREAMS_DEVICE_FOR_IF_CONFIG - if ((vs = open("/dev/ip", O_RDONLY)) < 0) - { - msyslog(LOG_ERR, "create_sockets: open(/dev/ip) failed: %m"); - exit(1); - } -# else /* not USE_STREAMS_DEVICE_FOR_IF_CONFIG */ - if ( - (vs = socket(AF_INET, SOCK_DGRAM, 0)) -# ifndef SYS_WINNT - < 0 -# else /* SYS_WINNT */ - == INVALID_SOCKET -# endif /* SYS_WINNT */ - ) { - msyslog(LOG_ERR, "create_sockets: socket(AF_INET, SOCK_DGRAM) failed: %m"); - exit(1); +#ifdef HAVE_IPV6 + else if (isc_if->af == AF_INET6) { + itf->sin.ss_family = (u_short) isc_if->af; + strcpy(itf->name, isc_if->name); + memcpy(&(((struct sockaddr_in6 *)&itf->sin)->sin6_addr), + &(isc_if->address.type.in6), + sizeof(struct in6_addr)); + ((struct sockaddr_in6 *)&itf->sin)->sin6_port = port; + + itf->mask.ss_family = itf->sin.ss_family; + memcpy(&(((struct sockaddr_in6 *)&itf->mask)->sin6_addr), + &(isc_if->netmask.type.in6), + sizeof(struct in6_addr)); + ((struct sockaddr_in6 *)&itf->mask)->sin6_port = port; + + if (((isc_if->flags & INTERFACE_F_LOOPBACK) != 0) && (loopback6_interface == NULL)) + { + loopback6_interface = itf; + } } -# endif /* not USE_STREAMS_DEVICE_FOR_IF_CONFIG */ +#endif /* HAVE_IPV6 */ - i = 1; -# if !defined(SYS_WINNT) - ifc.ifc_len = sizeof(buf); -# endif -# ifdef STREAMS_TLI - ioc.ic_cmd = SIOCGIFCONF; - ioc.ic_timout = 0; - ioc.ic_dp = (caddr_t)buf; - ioc.ic_len = sizeof(buf); - if(ioctl(vs, I_STR, &ioc) < 0 || - ioc.ic_len < sizeof(struct ifreq)) - { - msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFCONF) failed: %m - exiting"); - exit(1); - } -# ifdef SIZE_RETURNED_IN_BUFFER - ifc.ifc_len = ioc.ic_len - sizeof(int); - ifc.ifc_buf = buf + sizeof(int); -# else /* not SIZE_RETURNED_IN_BUFFER */ - ifc.ifc_len = ioc.ic_len; - ifc.ifc_buf = buf; -# endif /* not SIZE_RETURNED_IN_BUFFER */ - -# else /* not STREAMS_TLI */ - ifc.ifc_len = sizeof(buf); - ifc.ifc_buf = buf; -# ifndef SYS_WINNT - if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) -# else - if (WSAIoctl(vs, SIO_GET_INTERFACE_LIST, 0, 0, ifc.ifc_buf, ifc.ifc_len, &ifc.ifc_len, 0, 0) == SOCKET_ERROR) -# endif /* SYS_WINNT */ -{ - msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFCONF) failed: %m - exiting"); - exit(1); + /* Process the rest of the flags */ + + if((isc_if->flags & INTERFACE_F_UP) != 0) + itf->flags |= INT_UP; + if((isc_if->flags & INTERFACE_F_LOOPBACK) != 0) + itf->flags |= INT_LOOPBACK; + if((isc_if->flags & INTERFACE_F_POINTTOPOINT) != 0) + itf->flags |= INT_PPP; } +/* + * create_sockets - create a socket for each interface plus a default + * socket for when we don't know where to send + */ +static int +create_sockets( + u_short port + ) +{ + struct sockaddr_storage resmask; + int i; + isc_mem_t *mctx = NULL; + isc_interfaceiter_t *iter = NULL; + isc_boolean_t scan_ipv4 = ISC_FALSE; + isc_boolean_t scan_ipv6 = ISC_FALSE; + isc_result_t result; + int idx = 0; -# endif /* not STREAMS_TLI */ +#ifdef DEBUG + if (debug) + printf("create_sockets(%d)\n", ntohs( (u_short) port)); +#endif + + if (isc_net_probeipv6() == ISC_R_SUCCESS) + scan_ipv6 = ISC_TRUE; +#ifdef HAVE_IPV6 + else + netsyslog(LOG_ERR, "no IPv6 interfaces found"); +#endif - for(n = ifc.ifc_len, ifr = ifc.ifc_req; n > 0; - ifr = (struct ifreq *)((char *)ifr + size)) + if (isc_net_probeipv4() == ISC_R_SUCCESS) + scan_ipv4 = ISC_TRUE; + else + netsyslog(LOG_ERR, "no IPv4 interfaces found"); + + nwilds = create_wildcards(port); + idx = nwilds; + + result = isc_interfaceiter_create(mctx, &iter); + if (result != ISC_R_SUCCESS) + return (result); + + for (result = isc_interfaceiter_first(iter); + result == ISC_R_SUCCESS; + result = isc_interfaceiter_next(iter)) { - size = sizeof(*ifr); + isc_interface_t isc_if; + unsigned int family; -# ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr)) - size += ifr->ifr_addr.sa_len - sizeof(struct sockaddr); -# endif - n -= size; + result = isc_interfaceiter_current(iter, &isc_if); + if (result != ISC_R_SUCCESS) + break; -# if !defined(SYS_WINNT) - /* Exclude logical interfaces (indicated by ':' in the interface name) */ - if (debug) - printf("interface <%s> ", ifr->ifr_name); - if ((listen_to_virtual_ips == 0) - && (strchr(ifr->ifr_name, (int)':') != NULL)) { - if (debug) - printf("ignored\n"); + /* See if we have a valid family to use */ + family = isc_if.address.family; + if (family != AF_INET && family != AF_INET6) continue; - } - if (debug) - printf("OK\n"); - - if ( -# ifdef VMS /* VMS+UCX */ - (((struct sockaddr *)&(ifr->ifr_addr))->sa_family != AF_INET) -# else - (ifr->ifr_addr.sa_family != AF_INET) -# endif /* VMS+UCX */ - ) { - if (debug) - printf("ignoring %s - not AF_INET\n", - ifr->ifr_name); + if (scan_ipv4 == ISC_FALSE && family == AF_INET) continue; - } -# endif /* SYS_WINNT */ - ifreq = *ifr; - inter_list[i].flags = 0; - /* is it broadcast capable? */ -# ifndef SYS_WINNT -# ifdef STREAMS_TLI - ioc.ic_cmd = SIOCGIFFLAGS; - ioc.ic_timout = 0; - ioc.ic_dp = (caddr_t)&ifreq; - ioc.ic_len = sizeof(struct ifreq); - if(ioctl(vs, I_STR, &ioc)) { - msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFFLAGS) failed: %m"); - continue; - } -# else /* not STREAMS_TLI */ - if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) { - if (errno != ENXIO) - msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFFLAGS) failed: %m"); + if (scan_ipv6 == ISC_FALSE && family == AF_INET6) continue; - } -# endif /* not STREAMS_TLI */ - if ((ifreq.ifr_flags & IFF_UP) == 0) { - if (debug) - printf("ignoring %s - interface not UP\n", - ifr->ifr_name); - continue; - } - inter_list[i].flags = 0; - if (ifreq.ifr_flags & IFF_BROADCAST) - inter_list[i].flags |= INT_BROADCAST; -# endif /* not SYS_WINNT */ -# if !defined(SUN_3_3_STINKS) - if ( -# if defined(IFF_LOCAL_LOOPBACK) /* defined(SYS_HPUX) && (SYS_HPUX < 8) */ - (ifreq.ifr_flags & IFF_LOCAL_LOOPBACK) -# elif defined(IFF_LOOPBACK) - (ifreq.ifr_flags & IFF_LOOPBACK) -# else /* not IFF_LOCAL_LOOPBACK and not IFF_LOOPBACK */ - /* test against 127.0.0.1 (yuck!!) */ - ((*(struct sockaddr_in *)&ifr->ifr_addr).sin_addr.s_addr == inet_addr("127.0.0.1")) -# endif /* not IFF_LOCAL_LOOPBACK and not IFF_LOOPBACK */ - ) - { -# ifndef SYS_WINNT - inter_list[i].flags |= INT_LOOPBACK; -# endif /* not SYS_WINNT */ - if (loopback_interface == 0) - { - loopback_interface = &inter_list[i]; - } - } -# endif /* not SUN_3_3_STINKS */ -#if 0 -# ifndef SYS_WINNT -# ifdef STREAMS_TLI - ioc.ic_cmd = SIOCGIFADDR; - ioc.ic_timout = 0; - ioc.ic_dp = (caddr_t)&ifreq; - ioc.ic_len = sizeof(struct ifreq); - if (ioctl(vs, I_STR, &ioc)) - { - msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFADDR) failed: %m"); - continue; + /* Check to see if we are going to use the interface */ + if (address_okay(&isc_if) == ISC_TRUE) { + convert_isc_if(&isc_if, &inter_list[idx], port); + inter_list[idx].fd = INVALID_SOCKET; + inter_list[idx].bfd = INVALID_SOCKET; + inter_list[idx].num_mcast = 0; + inter_list[idx].received = 0; + inter_list[idx].sent = 0; + inter_list[idx].notsent = 0; + idx++; } -# else /* not STREAMS_TLI */ - if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) - { - if (errno != ENXIO) - msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFADDR) failed: %m"); - continue; - } -# endif /* not STREAMS_TLI */ -# endif /* not SYS_WINNT */ -#endif /* 0 */ -# if defined(SYS_WINNT) - {int TODO_FillInTheNameWithSomeThingReasonble;} -# else - (void)strncpy(inter_list[i].name, ifreq.ifr_name, - sizeof(inter_list[i].name)); -# endif - inter_list[i].sin = *(struct sockaddr_in *)&ifr->ifr_addr; - inter_list[i].sin.sin_family = AF_INET; - inter_list[i].sin.sin_port = port; - -# if defined(SUN_3_3_STINKS) - /* - * Oh, barf! I'm too disgusted to even explain this - */ - if (SRCADR(&inter_list[i].sin) == 0x7f000001) - { - inter_list[i].flags |= INT_LOOPBACK; - if (loopback_interface == 0) - loopback_interface = &inter_list[i]; - } -# endif /* SUN_3_3_STINKS */ -# if !defined SYS_WINNT && !defined SYS_CYGWIN32 /* no interface flags on NT */ - if (inter_list[i].flags & INT_BROADCAST) { -# ifdef STREAMS_TLI - ioc.ic_cmd = SIOCGIFBRDADDR; - ioc.ic_timout = 0; - ioc.ic_dp = (caddr_t)&ifreq; - ioc.ic_len = sizeof(struct ifreq); - if(ioctl(vs, I_STR, &ioc)) { - msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFBRDADDR) failed: %m"); - exit(1); - } -# else /* not STREAMS_TLI */ - if (ioctl(vs, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { - msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFBRDADDR) failed: %m"); - exit(1); - } -# endif /* not STREAMS_TLI */ - -# ifndef ifr_broadaddr - inter_list[i].bcast = - *(struct sockaddr_in *)&ifreq.ifr_addr; -# else - inter_list[i].bcast = - *(struct sockaddr_in *)&ifreq.ifr_broadaddr; -# endif /* ifr_broadaddr */ - inter_list[i].bcast.sin_family = AF_INET; - inter_list[i].bcast.sin_port = port; - } - -# ifdef STREAMS_TLI - ioc.ic_cmd = SIOCGIFNETMASK; - ioc.ic_timout = 0; - ioc.ic_dp = (caddr_t)&ifreq; - ioc.ic_len = sizeof(struct ifreq); - if(ioctl(vs, I_STR, &ioc)) { - msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFNETMASK) failed: %m"); - exit(1); - } -# else /* not STREAMS_TLI */ - if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) { - msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFNETMASK) failed: %m"); - exit(1); - } -# endif /* not STREAMS_TLI */ - inter_list[i].mask = *(struct sockaddr_in *)&ifreq.ifr_addr; -# else - /* winnt here */ - inter_list[i].bcast = ifreq.ifr_broadaddr; - inter_list[i].bcast.sin_family = AF_INET; - inter_list[i].bcast.sin_port = port; - inter_list[i].mask = ifreq.ifr_mask; -# endif /* not SYS_WINNT */ - - /* - * look for an already existing source interface address. If - * the machine has multiple point to point interfaces, then - * the local address may appear more than once. - */ - for (j=0; j < i; j++) - if (inter_list[j].sin.sin_addr.s_addr == - inter_list[i].sin.sin_addr.s_addr) { - break; - } - if (j == i) - i++; - if (i > MAXINTERFACES) - break; } - closesocket(vs); -#endif /* _BSDI_VERSION >= 199510 */ + isc_interfaceiter_destroy(&iter); - ninterfaces = i; + ninterfaces = idx; + /* + * I/O Completion Ports don't care about the select and FD_SET + */ +#ifndef HAVE_IO_COMPLETION_PORT maxactivefd = 0; FD_ZERO(&activefds); +#endif for (i = 0; i < ninterfaces; i++) { inter_list[i].fd = open_socket(&inter_list[i].sin, inter_list[i].flags & INT_BROADCAST, 0); - } - - /* - * Now that we have opened all the sockets, turn off the reuse flag for - * security. - */ - for (i = 0; i < ninterfaces; i++) { - int off = 0; - - /* - * if inter_list[ n ].fd is -1, we might have a adapter - * configured but not present - */ - if ( inter_list[ i ].fd != -1 ) { - if (setsockopt(inter_list[i].fd, SOL_SOCKET, - SO_REUSEADDR, (char *)&off, - sizeof(off))) { - msyslog(LOG_ERR, "create_sockets: setsockopt(SO_REUSEADDR,off) failed: %m"); - } + if (inter_list[i].bfd != INVALID_SOCKET) + msyslog(LOG_INFO, "Listening on interface %s, %s#%d", + inter_list[i].name, + stoa((&inter_list[i].sin)), + NTP_PORT); + if ((inter_list[i].flags & INT_BROADCAST) && + inter_list[i].bfd != INVALID_SOCKET) + msyslog(LOG_INFO, "Listening on broadcast address %s#%d", + stoa((&inter_list[i].bcast)), + NTP_PORT); +#if defined (HAVE_IO_COMPLETION_PORT) + if (inter_list[i].fd != INVALID_SOCKET) { + io_completion_port_add_socket(inter_list[i].fd, &inter_list[i]); } +#endif } -#if defined(MCAST) /* - * enable possible multicast reception on the broadcast socket + * Now that we have opened all the sockets, turn off the reuse + * flag for security. */ - inter_list[0].bcast.sin_addr.s_addr = htonl(INADDR_ANY); - inter_list[0].bcast.sin_family = AF_INET; - inter_list[0].bcast.sin_port = port; -#endif /* MCAST */ + set_reuseaddr(0); /* * Blacklist all bound interface addresses + * Wildcard interfaces are ignored. */ - resmask.sin_addr.s_addr = ~ (u_int32)0; - for (i = 1; i < ninterfaces; i++) + + for (i = nwilds; i < ninterfaces; i++) { + SET_HOSTMASK(&resmask, inter_list[i].sin.ss_family); hack_restrict(RESTRICT_FLAGS, &inter_list[i].sin, &resmask, RESM_NTPONLY|RESM_INTERFACE, RES_IGNORE); + } + + /* + * Calculate the address hash for each interface address. + */ + for (i = 0; i < ninterfaces; i++) { + inter_list[i].addr_refid = addr2refid(&inter_list[i].sin); + } + + #ifdef DEBUG if (debug > 1) { printf("create_sockets: ninterfaces=%d\n", ninterfaces); @@ -659,20 +545,15 @@ create_sockets( inter_list[i].flags); /* Leave these as three printf calls. */ printf(" sin=%s", - inet_ntoa((inter_list[i].sin.sin_addr))); + stoa((&inter_list[i].sin))); if (inter_list[i].flags & INT_BROADCAST) printf(" bcast=%s,", - inet_ntoa((inter_list[i].bcast.sin_addr))); + stoa((&inter_list[i].bcast))); printf(" mask=%s\n", - inet_ntoa((inter_list[i].mask.sin_addr))); + stoa((&inter_list[i].mask))); } } #endif -#if defined (HAVE_IO_COMPLETION_PORT) - for (i = 0; i < ninterfaces; i++) { - io_completion_port_add_socket(&inter_list[i]); - } -#endif return ninterfaces; } @@ -684,10 +565,19 @@ io_setbclient(void) { int i; - for (i = 1; i < ninterfaces; i++) { +#ifdef OPEN_BCAST_SOCKET + set_reuseaddr(1); +#endif + for (i = nwilds; i < ninterfaces; i++) { + /* Only IPv4 addresses are valid for broadcast */ + if (inter_list[i].bcast.ss_family != AF_INET) + continue; + + /* Is this a broadcast address? */ if (!(inter_list[i].flags & INT_BROADCAST)) continue; + /* Do we already have the broadcast address open? */ if (inter_list[i].flags & INT_BCASTOPEN) continue; @@ -697,8 +587,54 @@ io_setbclient(void) #ifdef OPEN_BCAST_SOCKET /* Was: !SYS_DOMAINOS && !SYS_LINUX */ inter_list[i].bfd = open_socket(&inter_list[i].bcast, INT_BROADCAST, 1); - inter_list[i].flags |= INT_BCASTOPEN; + if (inter_list[i].bfd != INVALID_SOCKET) { + inter_list[i].flags |= INT_BCASTOPEN; +#if defined (HAVE_IO_COMPLETION_PORT) + io_completion_port_add_socket(inter_list[i].bfd, &inter_list[i]); +#endif + } +#ifdef DEBUG + if (debug) { + if (inter_list[i].bfd != INVALID_SOCKET) + printf("io_setbclient: Opened broadcast client on interface %d, socket: %d\n", + i, inter_list[i].bfd); + else + printf("io_setbclient: Unable to Open broadcast client on interface %d\n", + i); + } +#endif +#endif + } +#ifdef OPEN_BCAST_SOCKET + set_reuseaddr(0); +#endif +#ifdef DEBUG + if (debug) + printf("io_setbclient: Opened broadcast clients\n"); #endif +} + +/* + * set_reuseaddr() - set/clear REUSEADDR on all sockets + * NB possible hole - should we be doing this on broadcast + * fd's also? + */ +static void +set_reuseaddr(int flag) { + int i; + + for (i=0; i < ninterfaces; i++) { + /* + * if inter_list[ n ].fd is -1, we might have a adapter + * configured but not present + */ + if (inter_list[i].fd != INVALID_SOCKET) { + if (setsockopt(inter_list[i].fd, SOL_SOCKET, + SO_REUSEADDR, (char *)&flag, + sizeof(flag))) { + netsyslog(LOG_ERR, "set_reuseaddr: setsockopt(SO_REUSEADDR, %s) failed: %m", flag ? "on" : "off"); + } + } } } @@ -708,83 +644,196 @@ io_setbclient(void) */ void io_multicast_add( - u_int32 addr + struct sockaddr_storage addr ) { #ifdef MCAST struct ip_mreq mreq; int i = ninterfaces; /* Use the next interface */ - u_int32 haddr = ntohl(addr); + u_int32 haddr = ntohl(((struct sockaddr_in*)&addr)->sin_addr.s_addr); struct in_addr iaddr; - int s; + SOCKET s; struct sockaddr_in *sinp; - iaddr.s_addr = addr; - if (!IN_CLASSD(haddr)) { - msyslog(LOG_ERR, - "multicast address %s not class D", - inet_ntoa(iaddr)); - return; - } - for (i = 0; i < ninterfaces; i++) { - /* Already have this address */ - if (inter_list[i].sin.sin_addr.s_addr == addr) +#ifdef HAVE_IPV6 + struct ipv6_mreq mreq6; + struct in6_addr iaddr6; + struct sockaddr_in6 *sin6p; +#endif /* HAVE_IPV6 */ + + switch (addr.ss_family) + { + case AF_INET : + iaddr = (((struct sockaddr_in*)&addr)->sin_addr); + if (!IN_CLASSD(haddr)) { + netsyslog(LOG_ERR, + "multicast address %s not class D", + inet_ntoa(iaddr)); return; - /* found a free slot */ - if (inter_list[i].sin.sin_addr.s_addr == 0 && - inter_list[i].fd <= 0 && inter_list[i].bfd <= 0 && - inter_list[i].flags == 0) + } + for (i = nwilds; i < ninterfaces; i++) { + /* Be sure it's the correct family */ + if (inter_list[i].sin.ss_family != AF_INET) + continue; + /* Already have this address */ + if (SOCKCMP(&inter_list[i].sin, &addr)) + return; + /* found a free slot */ + if (SOCKNUL(&inter_list[i].sin) && + inter_list[i].fd <= 0 && inter_list[i].bfd <= 0 && + inter_list[i].flags == 0) + break; + } + sinp = (struct sockaddr_in*)&(inter_list[i].sin); + memset((char *)&mreq, 0, sizeof(mreq)); + memset((char *)&inter_list[i], 0, sizeof(struct interface)); + sinp->sin_family = AF_INET; + sinp->sin_addr = iaddr; + sinp->sin_port = htons(NTP_PORT); + + /* + * Try opening a socket for the specified class D address. This + * works under SunOS 4.x, but not OSF1 .. :-( + */ + set_reuseaddr(1); + s = open_socket((struct sockaddr_storage*)sinp, 0, 1); + set_reuseaddr(0); + if (s == INVALID_SOCKET) { + memset((char *)&inter_list[i], 0, sizeof(struct interface)); + if (wildipv4 >= 0) { + i = wildipv4; + /* HACK ! -- stuff in an address */ + inter_list[i].bcast = addr; + netsyslog(LOG_ERR, + "...multicast address %s using wildcard socket", + inet_ntoa(iaddr)); + } else { + netsyslog(LOG_ERR, + "No wildcard socket available to use for address %s", + inet_ntoa(iaddr)); + return; + } + } else { + inter_list[i].fd = s; + inter_list[i].bfd = INVALID_SOCKET; + (void) strncpy(inter_list[i].name, "multicast", + sizeof(inter_list[i].name)); + ((struct sockaddr_in*)&inter_list[i].mask)->sin_addr.s_addr = htonl(~(u_int32)0); +#if defined (HAVE_IO_COMPLETION_PORT) + io_completion_port_add_socket(inter_list[i].fd, &inter_list[i]); +#endif + } + + /* + * enable reception of multicast packets + */ + mreq.imr_multiaddr = iaddr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *)&mreq, sizeof(mreq)) == -1) + netsyslog(LOG_ERR, + "setsockopt IP_ADD_MEMBERSHIP fails: %m for %x / %x (%s)", + mreq.imr_multiaddr.s_addr, + mreq.imr_interface.s_addr, inet_ntoa(iaddr)); + inter_list[i].flags |= INT_MULTICAST; + inter_list[i].num_mcast++; + if (i >= ninterfaces) + ninterfaces = i+1; + + add_addr_to_list(&addr, i); break; - } - sinp = &(inter_list[i].sin); - memset((char *)&mreq, 0, sizeof(mreq)); - memset((char *)&inter_list[i], 0, sizeof inter_list[0]); - sinp->sin_family = AF_INET; - sinp->sin_addr = iaddr; - sinp->sin_port = htons(123); - /* - * Try opening a socket for the specified class D address. This - * works under SunOS 4.x, but not OSF1 .. :-( - */ - s = open_socket(sinp, 0, 1); - if (s < 0) { - memset((char *)&inter_list[i], 0, sizeof inter_list[0]); - i = 0; - /* HACK ! -- stuff in an address */ - inter_list[i].bcast.sin_addr.s_addr = addr; - msyslog(LOG_ERR, - "...multicast address %s using wildcard socket", - inet_ntoa(iaddr)); - } else { - inter_list[i].fd = s; - inter_list[i].bfd = -1; - (void) strncpy(inter_list[i].name, "multicast", - sizeof(inter_list[i].name)); - inter_list[i].mask.sin_addr.s_addr = htonl(~(u_int32)0); +#ifdef HAVE_IPV6 + case AF_INET6 : + + iaddr6 = ((struct sockaddr_in6*)&addr)->sin6_addr; + if (!IN6_IS_ADDR_MULTICAST(&iaddr6)) { + netsyslog(LOG_ERR, + "address %s not IPv6 multicast address", + stoa(&addr)); + return; + } + for (i = nwilds; i < ninterfaces; i++) { + /* Be sure it's the correct family */ + if(inter_list[i].sin.ss_family != AF_INET6) + continue; + /* Already have this address */ + if (SOCKCMP(&inter_list[i].sin, &addr)) + return; + /* found a free slot */ + if (SOCKNUL(&inter_list[i].sin) && + inter_list[i].fd <= 0 && inter_list[i].bfd <= 0 && + inter_list[i].flags == 0) + break; + } + sin6p = (struct sockaddr_in6*)&inter_list[i].sin; + memset((char *)&mreq6, 0, sizeof(mreq6)); + memset((char *)&inter_list[i], 0, sizeof(struct interface)); + sin6p->sin6_family = AF_INET6; + sin6p->sin6_addr = iaddr6; + sin6p->sin6_port = htons(NTP_PORT); + + /* + * Try opening a socket for the specified class D address. This + * works under SunOS 4.x, but not OSF1 .. :-( + */ + set_reuseaddr(1); + s = open_socket((struct sockaddr_storage*)sin6p, 0, 1); + set_reuseaddr(0); + if(s == INVALID_SOCKET){ + memset((char *)&inter_list[i], 0, sizeof(struct interface)); + if (wildipv6 >= 0) { + i = wildipv6; + /* HACK ! -- stuff in an address */ + inter_list[i].bcast = addr; + netsyslog(LOG_ERR, + "...multicast address %s using wildcard socket", + stoa(&addr)); + } else { + netsyslog(LOG_ERR, + "No wildcard socket available to use for address %s", + stoa(&addr)); + return; + } + } else { + inter_list[i].fd = s; + inter_list[i].bfd = INVALID_SOCKET; + (void)strncpy(inter_list[i].name, "multicast", + sizeof(inter_list[i].name)); + memset(&(((struct sockaddr_in6*)&inter_list[i].mask)->sin6_addr), 1, sizeof(struct in6_addr)); +#if defined (HAVE_IO_COMPLETION_PORT) + io_completion_port_add_socket(inter_list[i].fd, &inter_list[i]); +#endif + } + + /* + * enable reception of multicast packets + */ + mreq6.ipv6mr_multiaddr = iaddr6; + mreq6.ipv6mr_interface = 0; + if(setsockopt(inter_list[i].fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + (char *)&mreq6, sizeof(mreq6)) == -1) + netsyslog(LOG_ERR, + "setsockopt IPV6_JOIN_GROUP fails: %m on interface %d(%s)", + mreq6.ipv6mr_interface, stoa(&addr)); + inter_list[i].flags |= INT_MULTICAST; + inter_list[i].num_mcast++; + if(i >= ninterfaces) + ninterfaces = i+1; + + add_addr_to_list(&addr, i); + break; +#endif /* HAVE_IPV6 */ } - /* - * enable reception of multicast packets - */ - mreq.imr_multiaddr = iaddr; - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (char *)&mreq, sizeof(mreq)) == -1) - msyslog(LOG_ERR, - "setsockopt IP_ADD_MEMBERSHIP fails: %m for %x / %x (%s)", - mreq.imr_multiaddr.s_addr, - mreq.imr_interface.s_addr, inet_ntoa(iaddr)); - inter_list[i].flags |= INT_MULTICAST; - if (i >= ninterfaces) - ninterfaces = i+1; +#ifdef DEBUG + if (debug) + printf("io_multicast_add %s\n", stoa(&addr)); +#endif #else /* MCAST */ - struct in_addr iaddr; - - iaddr.s_addr = addr; - msyslog(LOG_ERR, + netsyslog(LOG_ERR, "cannot add multicast address %s as no MCAST support", - inet_ntoa(iaddr)); + stoa(&addr)); #endif /* MCAST */ } @@ -796,12 +845,12 @@ io_unsetbclient(void) { int i; - for (i = 1; i < ninterfaces; i++) + for (i = nwilds; i < ninterfaces; i++) { if (!(inter_list[i].flags & INT_BCASTOPEN)) continue; close_socket(inter_list[i].bfd); - inter_list[i].bfd = -1; + inter_list[i].bfd = INVALID_SOCKET; inter_list[i].flags &= ~INT_BCASTOPEN; } } @@ -812,57 +861,125 @@ io_unsetbclient(void) */ void io_multicast_del( - u_int32 addr + struct sockaddr_storage addr ) { #ifdef MCAST int i; struct ip_mreq mreq; - u_int32 haddr = ntohl(addr); - struct sockaddr_in sinaddr; + u_int32 haddr; - if (!IN_CLASSD(haddr)) - { - sinaddr.sin_addr.s_addr = addr; - msyslog(LOG_ERR, - "invalid multicast address %s", ntoa(&sinaddr)); - return; - } +#ifdef HAVE_IPV6 + struct ipv6_mreq mreq6; + struct in6_addr haddr6; +#endif /* HAVE_IPV6 */ - /* - * Disable reception of multicast packets - */ - mreq.imr_multiaddr.s_addr = addr; - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - for (i = 0; i < ninterfaces; i++) + switch (addr.ss_family) { - if (!(inter_list[i].flags & INT_MULTICAST)) - continue; - if (!(inter_list[i].fd < 0)) - continue; - if (addr != inter_list[i].sin.sin_addr.s_addr) - continue; - if (i != 0) + case AF_INET : + + haddr = ntohl(((struct sockaddr_in*)&addr)->sin_addr.s_addr); + + if (!IN_CLASSD(haddr)) { - /* we have an explicit fd, so we can close it */ - close_socket(inter_list[i].fd); - memset((char *)&inter_list[i], 0, sizeof inter_list[0]); - inter_list[i].fd = -1; - inter_list[i].bfd = -1; + netsyslog(LOG_ERR, + "invalid multicast address %s", stoa(&addr)); + return; } - else + + /* + * Disable reception of multicast packets + */ + mreq.imr_multiaddr = ((struct sockaddr_in*)&addr)->sin_addr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + for (i = 0; i < ninterfaces; i++) { - /* We are sharing "any address" port :-( Don't close it! */ - if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, - (char *)&mreq, sizeof(mreq)) == -1) - msyslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails: %m"); - /* This is **WRONG** -- there may be others ! */ - /* There should be a count of users ... */ - inter_list[i].flags &= ~INT_MULTICAST; + /* Be sure it's the correct family */ + if (inter_list[i].sin.ss_family != AF_INET) + continue; + if (!(inter_list[i].flags & INT_MULTICAST)) + continue; + if (!(inter_list[i].fd < 0)) + continue; + if (!SOCKCMP(&addr, &inter_list[i].sin)) + continue; + if (i != wildipv4) + { + /* we have an explicit fd, so we can close it */ + close_socket(inter_list[i].fd); + memset((char *)&inter_list[i], 0, sizeof(struct interface)); + inter_list[i].fd = INVALID_SOCKET; + inter_list[i].bfd = INVALID_SOCKET; + } + else + { + /* We are sharing "any address" port :-( Don't close it! */ + if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, + (char *)&mreq, sizeof(mreq)) == -1) + netsyslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails on address: %s %m", + stoa(&addr)); + inter_list[i].num_mcast--; + /* If there are none left negate the Multicast flag */ + if(inter_list[i].num_mcast == 0) + inter_list[i].flags &= ~INT_MULTICAST; + } } - } + break; + +#ifdef HAVE_IPV6 + case AF_INET6 : + haddr6 = ((struct sockaddr_in6*)&addr)->sin6_addr; + + if (!IN6_IS_ADDR_MULTICAST(&haddr6)) + { + netsyslog(LOG_ERR, + "invalid multicast address %s", stoa(&addr)); + return; + } + + /* + * Disable reception of multicast packets + */ + mreq6.ipv6mr_multiaddr = ((struct sockaddr_in6*)&addr)->sin6_addr; + mreq6.ipv6mr_interface = 0; + for (i = 0; i < ninterfaces; i++) + { + /* Be sure it's the correct family */ + if (inter_list[i].sin.ss_family != AF_INET6) + continue; + if (!(inter_list[i].flags & INT_MULTICAST)) + continue; + if (!(inter_list[i].fd < 0)) + continue; + if (!SOCKCMP(&addr, &inter_list[i].sin)) + continue; + if (i != wildipv6) + { + /* we have an explicit fd, so we can close it */ + close_socket(inter_list[i].fd); + memset((char *)&inter_list[i], 0, sizeof(struct interface)); + inter_list[i].fd = INVALID_SOCKET; + inter_list[i].bfd = INVALID_SOCKET; + } + else + { + /* We are sharing "any address" port :-( Don't close it! */ + if (setsockopt(inter_list[i].fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + (char *)&mreq6, sizeof(mreq6)) == -1) + netsyslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails on address %s: %m", + stoa(&addr)); + /* If there are none left negate the Multicast flag */ + if(inter_list[i].num_mcast == 0) + inter_list[i].flags &= ~INT_MULTICAST; + } + } + break; +#endif /* HAVE_IPV6 */ + }/* switch */ + delete_addr_from_list(&addr); + #else /* not MCAST */ - msyslog(LOG_ERR, "this function requires multicast kernel"); + netsyslog(LOG_ERR, "this function requires multicast kernel"); #endif /* not MCAST */ } @@ -870,87 +987,163 @@ io_multicast_del( /* * open_socket - open a socket, returning the file descriptor */ -static int + +static SOCKET open_socket( - struct sockaddr_in *addr, + struct sockaddr_storage *addr, int flags, int turn_off_reuse ) { - int fd; + int errval; + SOCKET fd; int on = 1, off = 0; #if defined(IPTOS_LOWDELAY) && defined(IPPROTO_IP) && defined(IP_TOS) int tos; #endif /* IPTOS_LOWDELAY && IPPROTO_IP && IP_TOS */ + if ((addr->ss_family == AF_INET6) && (isc_net_probeipv6() != ISC_R_SUCCESS)) + return (INVALID_SOCKET); + /* create a datagram (UDP) socket */ - if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) #ifndef SYS_WINNT - < 0 + if ( (fd = socket(addr->ss_family, SOCK_DGRAM, 0)) < 0) { + errval = errno; + 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)); + if (errval == EPROTONOSUPPORT || errval == EAFNOSUPPORT || + errval == EPFNOSUPPORT) + return (INVALID_SOCKET); + exit(1); + /*NOTREACHED*/ + } #else - == INVALID_SOCKET -#endif /* SYS_WINNT */ - ) - { - msyslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed: %m"); + if ( (fd = socket(addr->ss_family, SOCK_DGRAM, 0)) == INVALID_SOCKET) { + errval = WSAGetLastError(); + 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)); + if (errval == WSAEPROTONOSUPPORT || errval == WSAEAFNOSUPPORT || + errval == WSAEPFNOSUPPORT) + return (INVALID_SOCKET); exit(1); /*NOTREACHED*/ } + 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 */ /* set SO_REUSEADDR since we will be binding the same port number on each interface */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) { - msyslog(LOG_ERR, "setsockopt SO_REUSEADDR on fails: %m"); + netsyslog(LOG_ERR, "setsockopt SO_REUSEADDR on fails on address %s: %m", + stoa(addr)); } #if defined(IPTOS_LOWDELAY) && defined(IPPROTO_IP) && defined(IP_TOS) /* set IP_TOS to minimize packet delay */ tos = IPTOS_LOWDELAY; - if (setsockopt(fd, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(tos)) < 0) - { - msyslog(LOG_ERR, "setsockopt IPTOS_LOWDELAY on fails: %m"); - } + if (addr->ss_family == AF_INET) + if (setsockopt(fd, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(tos)) < 0) + { + netsyslog(LOG_ERR, "setsockopt IPTOS_LOWDELAY on fails on address %s: %m", + stoa(addr)); + } + +#if defined(IPV6_V6ONLY) + if (addr->ss_family == AF_INET6) + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, + (char*)&on, sizeof(on))) + { + netsyslog(LOG_ERR, "setsockopt IPV6_V6ONLY on fails on address %s: %m", + stoa(addr)); + } +#else /* IPV6_V6ONLY */ +#if defined(IPV6_BINDV6ONLY) + if (addr->ss_family == AF_INET6) + if (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDV6ONLY, + (char*)&on, sizeof(on))) + { + netsyslog(LOG_ERR, + "setsockopt IPV6_BINDV6ONLY on fails on address %s: %m", + stoa(addr)); + } +#endif /* IPV6_BINDV6ONLY */ +#endif /* IPV6_V6ONLY */ + #endif /* IPTOS_LOWDELAY && IPPROTO_IP && IP_TOS */ /* * bind the local address. */ - if (bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) { + if (bind(fd, (struct sockaddr *)addr, SOCKLEN(addr)) < 0) { char buff[160]; - sprintf(buff, - "bind() fd %d, family %d, port %d, addr %s, in_classd=%d flags=%d fails: %%m", - fd, addr->sin_family, (int)ntohs(addr->sin_port), - ntoa(addr), - IN_CLASSD(ntohl(addr->sin_addr.s_addr)), flags); - msyslog(LOG_ERR, buff); + + if(addr->ss_family == AF_INET) + sprintf(buff, + "bind() fd %d, family %d, port %d, addr %s, in_classd=%d flags=%d fails: %%m", + fd, addr->ss_family, (int)ntohs(((struct sockaddr_in*)addr)->sin_port), + stoa(addr), + IN_CLASSD(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr)), flags); + else if(addr->ss_family == AF_INET6) + sprintf(buff, + "bind() fd %d, family %d, port %d, addr %s, in6_is_addr_multicast=%d flags=%d fails: %%m", + fd, addr->ss_family, (int)ntohs(((struct sockaddr_in6*)addr)->sin6_port), + stoa(addr), + IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr), flags); + else return INVALID_SOCKET; + + netsyslog(LOG_ERR, buff); closesocket(fd); /* - * soft fail if opening a class D address + * soft fail if opening a multicast address */ - if (IN_CLASSD(ntohl(addr->sin_addr.s_addr))) - return -1; + if(addr->ss_family == AF_INET){ + if(IN_CLASSD(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr))) + return (INVALID_SOCKET); + } + else { + if(IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr)) + return (INVALID_SOCKET); + } #if 0 exit(1); #else - return -1; + return INVALID_SOCKET; #endif } #ifdef DEBUG if (debug) printf("bind() fd %d, family %d, port %d, addr %s, flags=%d\n", fd, - addr->sin_family, - (int)ntohs(addr->sin_port), - ntoa(addr), + addr->ss_family, + (int)ntohs(((struct sockaddr_in*)addr)->sin_port), + stoa(addr), flags); #endif + + /* + * I/O Completion Ports don't care about the select and FD_SET + */ +#ifndef HAVE_IO_COMPLETION_PORT if (fd > maxactivefd) maxactivefd = fd; FD_SET(fd, &activefds); - +#endif + add_socket_to_list(fd); /* * set non-blocking, */ @@ -967,43 +1160,46 @@ open_socket( #if defined(O_NONBLOCK) /* POSIX */ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { - msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m"); + netsyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails on address %s: %m", + stoa(addr)); exit(1); /*NOTREACHED*/ } #elif defined(FNDELAY) if (fcntl(fd, F_SETFL, FNDELAY) < 0) { - msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m"); + netsyslog(LOG_ERR, "fcntl(FNDELAY) fails on address %s: %m", + stoa(addr)); exit(1); /*NOTREACHED*/ } #elif defined(O_NDELAY) /* generally the same as FNDELAY */ if (fcntl(fd, F_SETFL, O_NDELAY) < 0) { - msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m"); + netsyslog(LOG_ERR, "fcntl(O_NDELAY) fails on address %s: %m", + stoa(addr)); exit(1); /*NOTREACHED*/ } #elif defined(FIONBIO) - if ( # if defined(VMS) - (ioctl(fd,FIONBIO,&1) < 0) + if (ioctl(fd,FIONBIO,&on) < 0) # elif defined(SYS_WINNT) - (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) + if (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) # else - (ioctl(fd,FIONBIO,&on) < 0) + if (ioctl(fd,FIONBIO,&on) < 0) # endif - ) { - msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m"); + netsyslog(LOG_ERR, "ioctl(FIONBIO) fails on address %s: %m", + stoa(addr)); exit(1); /*NOTREACHED*/ } #elif defined(FIOSNBIO) if (ioctl(fd,FIOSNBIO,&on) < 0) { - msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m"); + netsyslog(LOG_ERR, "ioctl(FIOSNBIO) fails on address %s: %m", + stoa(addr)); exit(1); /*NOTREACHED*/ } @@ -1025,7 +1221,8 @@ open_socket( if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&off, sizeof(off))) { - msyslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails: %m"); + netsyslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails on address %s: %m", + stoa(addr)); } #ifdef SO_BROADCAST @@ -1035,7 +1232,8 @@ open_socket( if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on))) { - msyslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m"); + netsyslog(LOG_ERR, "setsockopt(SO_BROADCAST) on address %s: %m", + stoa(addr)); } } #endif /* SO_BROADCAST */ @@ -1057,21 +1255,29 @@ open_socket( */ static void close_socket( - int fd + SOCKET fd ) { - int i, newmax; + SOCKET i, newmax; (void) closesocket(fd); + + /* + * I/O Completion Ports don't care about select and fd_set + */ +#ifndef HAVE_IO_COMPLETION_PORT FD_CLR( (u_int) fd, &activefds); - if (fd >= maxactivefd) { + if (fd == maxactivefd) { newmax = 0; for (i = 0; i < maxactivefd; i++) if (FD_ISSET(i, &activefds)) newmax = i; maxactivefd = newmax; } +#endif + delete_socket_from_list(fd); + } @@ -1079,24 +1285,33 @@ close_socket( * close_file - close a file and remove from the activefd list * added 1/31/1997 Greg Schueman for Windows NT portability */ +#ifdef REFCLOCK static void close_file( - int fd + SOCKET fd ) { int i, newmax; (void) close(fd); + /* + * I/O Completion Ports don't care about select and fd_set + */ +#ifndef HAVE_IO_COMPLETION_PORT FD_CLR( (u_int) fd, &activefds); - if (fd >= maxactivefd) { + if (fd == maxactivefd) { newmax = 0; for (i = 0; i < maxactivefd; i++) if (FD_ISSET(i, &activefds)) newmax = i; maxactivefd = newmax; } +#endif + delete_socket_from_list(fd); + } +#endif /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ @@ -1107,7 +1322,7 @@ close_file( */ void sendpkt( - struct sockaddr_in *dest, + struct sockaddr_storage *dest, struct interface *inter, int ttl, struct pkt *pkt, @@ -1120,7 +1335,7 @@ sendpkt( #endif /* SYS_WINNT */ /* - * Send error cache. Empty slots have port == 0 + * Send error caches. Empty slots have port == 0 * Set ERRORCACHESIZE to 0 to disable */ struct cache { @@ -1128,57 +1343,121 @@ sendpkt( struct in_addr addr; }; +#ifdef HAVE_IPV6 + struct cache6 { + u_short port; + struct in6_addr addr; + }; +#endif /* HAVE_IPV6 */ + #ifndef ERRORCACHESIZE #define ERRORCACHESIZE 8 #endif #if ERRORCACHESIZE > 0 static struct cache badaddrs[ERRORCACHESIZE]; +#ifdef HAVE_IPV6 + static struct cache6 badaddrs6[ERRORCACHESIZE]; +#endif /* HAVE_IPV6 */ #else #define badaddrs ((struct cache *)0) /* Only used in empty loops! */ +#ifdef HAVE_IPV6 +#define badaddrs6 ((struct cache6 *)0) /* Only used in empty loops! */ +#endif /* HAVE_IPV6 */ #endif #ifdef DEBUG if (debug > 1) printf("%ssendpkt(fd=%d dst=%s, src=%s, ttl=%d, len=%d)\n", (ttl >= 0) ? "\tMCAST\t*****" : "", - inter->fd, ntoa(dest), - ntoa(&inter->sin), ttl, len); + inter->fd, stoa(dest), + stoa(&inter->sin), ttl, len); #endif #ifdef MCAST - /* - * for the moment we use the bcast option to set multicast ttl - */ - if (ttl > 0 && ttl != inter->last_ttl) { - char mttl = ttl; + + switch (inter->sin.ss_family) { + + case AF_INET : /* - * set the multicast ttl for outgoing packets + * for the moment we use the bcast option to set multicast ttl + */ + if (ttl > 0 && ttl != inter->last_ttl) { + + /* + * set the multicast ttl for outgoing packets + */ + if (setsockopt(inter->fd, IPPROTO_IP, IP_MULTICAST_TTL, + (char *) &ttl, sizeof(ttl)) != 0) { + netsyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails on address %s: %m", + stoa(&inter->sin)); + } + else + inter->last_ttl = ttl; + } + break; + +#ifdef HAVE_IPV6 + case AF_INET6 : + + /* + * for the moment we use the bcast option to set + * multicast max hops */ - if (setsockopt(inter->fd, IPPROTO_IP, IP_MULTICAST_TTL, - &mttl, sizeof(mttl)) == -1) - msyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails: %m"); - else - inter->last_ttl = ttl; + if (ttl > 0 && ttl != inter->last_ttl) { + + /* + * set the multicast ttl for outgoing packets + */ + if (setsockopt(inter->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &ttl, sizeof(ttl)) == -1) + netsyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails on address %s: %m", + stoa(&inter->sin)); + else + inter->last_ttl = ttl; + } + break; +#endif /* HAVE_IPV6 */ + + default : + exit(1); + } + + #endif /* MCAST */ for (slot = ERRORCACHESIZE; --slot >= 0; ) - if (badaddrs[slot].port == dest->sin_port && - badaddrs[slot].addr.s_addr == dest->sin_addr.s_addr) - break; + if(dest->ss_family == AF_INET) { + if (badaddrs[slot].port == ((struct sockaddr_in*)dest)->sin_port && + badaddrs[slot].addr.s_addr == ((struct sockaddr_in*)dest)->sin_addr.s_addr) + break; + } +#ifdef HAVE_IPV6 + else if (dest->ss_family == AF_INET6) { + if (badaddrs6[slot].port == ((struct sockaddr_in6*)dest)->sin6_port && + badaddrs6[slot].addr.s6_addr == ((struct sockaddr_in6*)dest)->sin6_addr.s6_addr) + break; + } +#endif /* HAVE_IPV6 */ + else exit(1); /* address family not supported yet */ #if defined(HAVE_IO_COMPLETION_PORT) err = io_completion_port_sendto(inter, pkt, len, dest); if (err != ERROR_SUCCESS) #else - cc = sendto(inter->fd, (char *)pkt, (size_t)len, 0, (struct sockaddr *)dest, - sizeof(struct sockaddr_in)); +#ifdef SIM + cc = srvr_rply(&ntp_node, dest, inter, pkt); +#else /* SIM */ + cc = sendto(inter->fd, (char *)pkt, (unsigned int)len, 0, (struct sockaddr *)dest, + SOCKLEN(dest)); +#endif /* SIM */ if (cc == -1) #endif { inter->notsent++; packets_notsent++; #if defined(HAVE_IO_COMPLETION_PORT) + err = WSAGetLastError(); if (err != WSAEWOULDBLOCK && err != WSAENOBUFS && slot < 0) #else if (errno != EWOULDBLOCK && errno != ENOBUFS && slot < 0) @@ -1187,14 +1466,37 @@ sendpkt( /* * Remember this, if there's an empty slot */ - for (slot = ERRORCACHESIZE; --slot >= 0; ) - if (badaddrs[slot].port == 0) - { - badaddrs[slot].port = dest->sin_port; - badaddrs[slot].addr = dest->sin_addr; - break; - } - msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest)); + switch (dest->ss_family) { + + case AF_INET : + + for (slot = ERRORCACHESIZE; --slot >= 0; ) + if (badaddrs[slot].port == 0) + { + badaddrs[slot].port = SRCPORT(dest); + badaddrs[slot].addr = ((struct sockaddr_in*)dest)->sin_addr; + break; + } + break; + +#ifdef HAVE_IPV6 + 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; +#endif /* HAVE_IPV6 */ + + default : + exit(1); + } + + netsyslog(LOG_ERR, "sendto(%s): %m", stoa(dest)); } } else @@ -1206,8 +1508,17 @@ sendpkt( */ if (slot >= 0) { - msyslog(LOG_INFO, "Connection re-established to %s", ntoa(dest)); - badaddrs[slot].port = 0; + netsyslog(LOG_INFO, "Connection re-established to %s", stoa(dest)); + switch (dest->ss_family) { + case AF_INET : + badaddrs[slot].port = 0; + break; +#ifdef HAVE_IPV6 + case AF_INET6 : + badaddrs6[slot].port = 0; + break; +#endif /* HAVE_IPV6 */ + } } } } @@ -1249,7 +1560,7 @@ input_handler( register int i, n; register struct recvbuf *rb; register int doing; - register int fd; + register SOCKET fd; struct timeval tvzero; int fromlen; l_fp ts; /* Timestamp at BOselect() gob */ @@ -1315,14 +1626,17 @@ input_handler( if (rb->recv_length == -1) { - msyslog(LOG_ERR, "clock read fd %d: %m", fd); + netsyslog(LOG_ERR, "clock read fd %d: %m", fd); freerecvbuf(rb); goto select_again; } /* - * Got one. Mark how and when it got here, - * put it on the full list and do bookkeeping. + * Got one. Mark how + * and when it got here, + * put it on the full + * list and do + * bookkeeping. */ rb->recv_srcclock = rp->srcclock; rb->dstadr = 0; @@ -1333,13 +1647,25 @@ input_handler( if (rp->io_input) { /* - * have direct input routine for refclocks + * have direct + * input routine + * for refclocks */ if (rp->io_input(rb) == 0) { /* - * data was consumed - nothing to pass up - * into block input machine + * data + * was + * consumed + * - + * nothing + * to + * pass + * up + * into + * block + * input + * machine */ freerecvbuf(rb); #if 1 @@ -1360,7 +1686,8 @@ input_handler( #endif /* REFCLOCK */ /* - * Loop through the interfaces looking for data to read. + * Loop through the interfaces looking for data + * to read. */ for (i = ninterfaces - 1; (i >= 0) && (n > 0); i--) { @@ -1382,9 +1709,12 @@ input_handler( n--; /* - * Get a buffer and read the frame. If we - * haven't got a buffer, or this is received - * on the wild card socket, just dump the + * Get a buffer and read + * the frame. If we + * haven't got a buffer, + * or this is received + * on the wild card + * socket, just dump the * packet. */ if ( @@ -1395,23 +1725,24 @@ input_handler( */ (free_recvbuffs() == 0) #else - ((i == 0) || (free_recvbuffs() == 0)) + ((i == wildipv4) || (i == wildipv6)|| + (free_recvbuffs() == 0)) #endif ) { char buf[RX_BUFF_SIZE]; - struct sockaddr from; + struct sockaddr_storage from; fromlen = sizeof from; - (void) recvfrom(fd, buf, sizeof(buf), 0, &from, &fromlen); + (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr*)&from, &fromlen); #ifdef DEBUG if (debug) printf("%s on %d(%lu) fd=%d from %s\n", (i) ? "drop" : "ignore", i, free_recvbuffs(), fd, - inet_ntoa(((struct sockaddr_in *) &from)->sin_addr)); + stoa(&from)); #endif - if (i == 0) + if (i == wildipv4 || i == wildipv6) packets_ignored++; else packets_dropped++; @@ -1420,7 +1751,7 @@ input_handler( rb = get_free_recv_buffer(); - fromlen = sizeof(struct sockaddr_in); + fromlen = sizeof(struct sockaddr_storage); rb->recv_length = recvfrom(fd, (char *)&rb->recv_space, sizeof(rb->recv_space), 0, @@ -1439,8 +1770,8 @@ input_handler( } else if (rb->recv_length < 0) { - msyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m", - inet_ntoa(rb->recv_srcadr.sin_addr), fd); + netsyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m", + stoa(&rb->recv_srcadr), fd); #ifdef DEBUG if (debug) printf("input_handler: fd=%d dropped (bad recvfrom)\n", fd); @@ -1449,12 +1780,18 @@ input_handler( continue; } #ifdef DEBUG - if (debug > 2) - printf("input_handler: if=%d fd=%d length %d from %08lx %s\n", - i, fd, rb->recv_length, - (u_long)ntohl(rb->recv_srcadr.sin_addr.s_addr) & - 0x00000000ffffffff, - inet_ntoa(rb->recv_srcadr.sin_addr)); + if (debug > 2) { + if(rb->recv_srcadr.ss_family == AF_INET) + printf("input_handler: if=%d fd=%d length %d from %08lx %s\n", + i, fd, rb->recv_length, + (u_long)ntohl(((struct sockaddr_in*)&rb->recv_srcadr)->sin_addr.s_addr) & + 0x00000000ffffffff, + stoa(&rb->recv_srcadr)); + else + printf("input_handler: if=%d fd=%d length %d from %s\n", + i, fd, rb->recv_length, + stoa(&rb->recv_srcadr)); + } #endif /* @@ -1467,7 +1804,7 @@ input_handler( rb->receiver = receive; add_full_recv_buffer(rb); - + inter_list[i].received++; packets_received++; goto select_again; @@ -1491,19 +1828,20 @@ input_handler( if (select_count == 0) /* We really had nothing to do */ { if (debug) - msyslog(LOG_DEBUG, "input_handler: select() returned 0"); + netsyslog(LOG_DEBUG, "input_handler: select() returned 0"); --handler_count; return; } /* We've done our work */ get_systime(&ts_e); /* - * (ts_e - ts) is the amount of time we spent processing - * this gob of file descriptors. Log it. + * (ts_e - ts) is the amount of time we spent + * processing this gob of file descriptors. Log + * it. */ L_SUB(&ts_e, &ts); if (debug > 3) - msyslog(LOG_INFO, "input_handler: Processed a gob of fd's in %s msec", lfptoms(&ts_e, 6)); + netsyslog(LOG_INFO, "input_handler: Processed a gob of fd's in %s msec", lfptoms(&ts_e, 6)); /* just bail. */ --handler_count; @@ -1516,8 +1854,11 @@ input_handler( /* * extended FAU debugging output */ - msyslog(LOG_ERR, "select(%d, %s, 0L, 0L, &0.000000) error: %m", - maxactivefd+1, fdbits(maxactivefd, &activefds)); + if (err != EINTR) + netsyslog(LOG_ERR, + "select(%d, %s, 0L, 0L, &0.0) error: %m", + maxactivefd+1, + fdbits(maxactivefd, &activefds)); if (err == EBADF) { int j, b; @@ -1526,7 +1867,7 @@ input_handler( if ( (FD_ISSET(j, &fds) && (read(j, &b, 0) == -1)) ) - msyslog(LOG_ERR, "Bad file descriptor %d", j); + netsyslog(LOG_ERR, "Bad file descriptor %d", j); } --handler_count; return; @@ -1538,70 +1879,91 @@ input_handler( } #endif - /* * findinterface - find interface corresponding to address */ struct interface * findinterface( - struct sockaddr_in *addr + struct sockaddr_storage *addr ) { - int s, rtn, i; - struct sockaddr_in saddr; - int saddrlen = sizeof(saddr); - u_int32 xaddr; - + SOCKET s; + int rtn, i; + struct sockaddr_storage saddr; + int saddrlen = SOCKLEN(addr); /* * This is considerably hoke. We open a socket, connect to it * and slap a getsockname() on it. If anything breaks, as it * probably will in some j-random knockoff, we just return the * wildcard interface. */ - saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr = addr->sin_addr.s_addr; - saddr.sin_port = htons(2000); - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) - return (any_interface); - - rtn = connect(s, (struct sockaddr *)&saddr, sizeof(saddr)); + memset(&saddr, 0, sizeof(saddr)); + saddr.ss_family = addr->ss_family; + if(addr->ss_family == AF_INET) + memcpy(&((struct sockaddr_in*)&saddr)->sin_addr, &((struct sockaddr_in*)addr)->sin_addr, sizeof(struct in_addr)); + else if(addr->ss_family == AF_INET6) + memcpy(&((struct sockaddr_in6*)&saddr)->sin6_addr, &((struct sockaddr_in6*)addr)->sin6_addr, sizeof(struct in6_addr)); + ((struct sockaddr_in*)&saddr)->sin_port = htons(2000); + s = socket(addr->ss_family, SOCK_DGRAM, 0); + if (s == INVALID_SOCKET) + return ANY_INTERFACE_CHOOSE(addr); + + rtn = connect(s, (struct sockaddr *)&saddr, SOCKLEN(&saddr)); +#ifndef SYS_WINNT if (rtn < 0) - return (any_interface); +#else + if (rtn == SOCKET_ERROR) +#endif + { + closesocket(s); + return ANY_INTERFACE_CHOOSE(addr); + } rtn = getsockname(s, (struct sockaddr *)&saddr, &saddrlen); + closesocket(s); +#ifndef SYS_WINNT if (rtn < 0) - return (any_interface); - - close(s); - xaddr = NSRCADR(&saddr); - for (i = 1; i < ninterfaces; i++) { +#else + if (rtn == SOCKET_ERROR) +#endif + return ANY_INTERFACE_CHOOSE(addr); + for (i = 0; i < ninterfaces; i++) { + /* + * First look if is the the correct family + */ + if(inter_list[i].sin.ss_family != saddr.ss_family) + continue; /* * We match the unicast address only. */ - if (NSRCADR(&inter_list[i].sin) == xaddr) + if (SOCKCMP(&inter_list[i].sin, &saddr)) return (&inter_list[i]); } - return (any_interface); + return ANY_INTERFACE_CHOOSE(addr); } - /* * findbcastinter - find broadcast interface corresponding to address */ struct interface * findbcastinter( - struct sockaddr_in *addr + struct sockaddr_storage *addr ) { #if !defined(MPE) && (defined(SIOCGIFCONF) || defined(SYS_WINNT)) register int i; - register u_int32 xaddr; - - xaddr = NSRCADR(addr); - for (i = 1; i < ninterfaces; i++) { + + i = find_addr_in_list(addr); + if(i >= 0) + return (&inter_list[i]); + for (i = 0; i < ninterfaces; i++) { + /* + * First look if this is the correct family + */ + if(inter_list[i].sin.ss_family != addr->ss_family) + continue; /* * We match only those interfaces marked as * broadcastable and either the explicit broadcast @@ -1610,15 +1972,23 @@ findbcastinter( */ if (!(inter_list[i].flags & INT_BROADCAST)) continue; - if (NSRCADR(&inter_list[i].bcast) == xaddr) - return (&inter_list[i]); - if ((NSRCADR(&inter_list[i].sin) & - NSRCADR(&inter_list[i].mask)) == (xaddr & - NSRCADR(&inter_list[i].mask))) - return (&inter_list[i]); + if(addr->ss_family == AF_INET) { + if (SOCKCMP(&inter_list[i].bcast, addr)) + return (&inter_list[i]); + if ((NSRCADR(&inter_list[i].sin) & + NSRCADR(&inter_list[i].mask)) == (NSRCADR(addr) & + NSRCADR(&inter_list[i].mask))) + return (&inter_list[i]); + } + else if(addr->ss_family == AF_INET6) { + if (SOCKCMP(&inter_list[i].bcast, addr)) + return (&inter_list[i]); + if (SOCKCMP(netof(&inter_list[i].sin), netof(addr))) + return (&inter_list[i]); + } } #endif /* SIOCGIFCONF */ - return (any_interface); + return ANY_INTERFACE_CHOOSE(addr); } @@ -1659,9 +2029,14 @@ io_addclock_simple( rio->next = refio; refio = rio; + /* + * I/O Completion Ports don't care about select and fd_set + */ +#ifndef HAVE_IO_COMPLETION_PORT if (rio->fd > maxactivefd) maxactivefd = rio->fd; FD_SET(rio->fd, &activefds); +#endif UNBLOCKIO(); return 1; } @@ -1693,16 +2068,21 @@ io_addclock( # elif defined(HAVE_IO_COMPLETION_PORT) if (io_completion_port_add_clock_io(rio)) { + add_socket_to_list(rio->fd); refio = rio->next; UNBLOCKIO(); return 0; } # endif + /* + * I/O Completion Ports don't care about select and fd_set + */ +#ifndef HAVE_IO_COMPLETION_PORT if (rio->fd > maxactivefd) maxactivefd = rio->fd; FD_SET(rio->fd, &activefds); - +#endif UNBLOCKIO(); return 1; } @@ -1751,12 +2131,127 @@ io_closeclock( } #endif /* REFCLOCK */ + /* + * I/O Completion Ports don't care about select and fd_set + */ +#ifndef HAVE_IO_COMPLETION_PORT void -kill_asyncio(void) +kill_asyncio( + int startfd + ) { - int i; + SOCKET i; BLOCKIO(); - for (i = 0; i <= maxactivefd; i++) + for (i = startfd; i <= maxactivefd; i++) (void)close_socket(i); } +#else +/* + * On NT a SOCKET is an unsigned int so we cannot possibly keep it in + * an array. So we use one of the ISC_LIST functions to hold the + * socket value and use that when we want to enumerate it. + */ +void +kill_asyncio(int startfd) +{ + vsock_t *lsock; + vsock_t *next; + + BLOCKIO(); + + lsock = ISC_LIST_HEAD(sockets_list); + while (lsock != NULL) { + next = ISC_LIST_NEXT(lsock, link); + close_socket(lsock->fd); + lsock = next; + } + +} +#endif +/* + * Add and delete functions for the list of open sockets + */ +void +add_socket_to_list(SOCKET fd){ + vsock_t *lsock = malloc(sizeof(vsock_t)); + lsock->fd = fd; + + ISC_LIST_APPEND(sockets_list, lsock, link); +} +void +delete_socket_from_list(SOCKET fd) { + + vsock_t *next; + vsock_t *lsock = ISC_LIST_HEAD(sockets_list); + + while(lsock != NULL) { + next = ISC_LIST_NEXT(lsock, link); + if(lsock->fd == fd) { + ISC_LIST_DEQUEUE(sockets_list, lsock, link); + free(lsock); + break; + } + else + lsock = next; + } +} +void +add_addr_to_list(struct sockaddr_storage *addr, int if_index){ + remaddr_t *laddr = malloc(sizeof(remaddr_t)); + memcpy(&laddr->addr, addr, sizeof(addr)); + laddr->if_index = if_index; + + ISC_LIST_APPEND(remoteaddr_list, laddr, link); +#ifdef DEBUG + if (debug) + printf("Added addr %s to list of addresses\n", + stoa(addr)); +#endif + + +} +void +delete_addr_from_list(struct sockaddr_storage *addr) { + + remaddr_t *next; + remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list); + + while(laddr != NULL) { + next = ISC_LIST_NEXT(laddr, link); + if(SOCKCMP(&laddr->addr, addr)) { + ISC_LIST_DEQUEUE(remoteaddr_list, laddr, link); + free(laddr); + break; + } + else + laddr = next; + } +#ifdef DEBUG + if (debug) + printf("Deleted addr %s from list of addresses\n", + stoa(addr)); +#endif +} +int +find_addr_in_list(struct sockaddr_storage *addr) { + + remaddr_t *next; + remaddr_t *laddr = ISC_LIST_HEAD(remoteaddr_list); +#ifdef DEBUG + if (debug) + printf("Finding addr %s in list of addresses\n", + stoa(addr)); +#endif + + while(laddr != NULL) { + next = ISC_LIST_NEXT(laddr, link); + if(SOCKCMP(&laddr->addr, addr)) { + return (laddr->if_index); + break; + } + else + laddr = next; + } + return (-1); /* Not found */ +} |