📄 ntp_io.c
字号:
/* * ntp_io.c - input/output routines for ntpd. The socket-opening code * was shamelessly stolen from ntpd. */#ifdef HAVE_CONFIG_H# include <config.h>#endif#include "ntp_machine.h"#include "ntpd.h"#include "ntp_io.h"#include "iosignal.h"#include "ntp_refclock.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>#ifdef HAVE_SYS_PARAM_H# include <sys/param.h>#endif /* HAVE_SYS_PARAM_H */#ifdef HAVE_SYS_IOCTL_H# include <sys/ioctl.h>#endif#ifdef HAVE_SYS_SOCKIO_H /* UXPV: SIOC* #defines (Frank Vance <fvance@waii.com>) */# include <sys/sockio.h>#endif/* * Set up some macros to look for IPv6 and IPv6 multicast */#if defined(ISC_PLATFORM_HAVEIPV6) && !defined(DISABLE_IPV6)#define INCLUDE_IPV6_SUPPORT#if defined(INCLUDE_IPV6_SUPPORT) && defined(IPV6_JOIN_GROUP) && defined(IPV6_LEAVE_GROUP)#define INCLUDE_IPV6_MULTICAST_SUPPORT#endif /* IPV6 Multicast Support */#endif /* IPv6 Support */extern int listen_to_virtual_ips;extern const char *specific_interface;#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#endif/* * We do asynchronous input using the SIGIO facility. A number of * recvbuf buffers are preallocated for input. In the signal * handler we poll to see which sockets are ready and read the * packets from them into the recvbuf's along with a time stamp and * an indication of the source host and the interface it was received * through. This allows us to get as accurate receive time stamps * as possible independent of other processing going on. * * We watch the number of recvbufs available to the signal handler * and allocate more when this number drops below the low water * mark. If the signal handler should run out of buffers in the * interim it will drop incoming frames, the idea being that it is * better to drop a packet than to be inaccurate. *//* * Other statistics of possible interest */volatile u_long packets_dropped; /* total number of packets dropped on reception */volatile u_long packets_ignored; /* packets received on wild card interface */volatile u_long packets_received; /* total number of packets received */u_long packets_sent; /* total number of packets sent */u_long packets_notsent; /* total number of packets which couldn't be sent */volatile u_long handler_calls; /* number of calls to interrupt handler */volatile u_long handler_pkts; /* number of pkts received by handler */u_long io_timereset; /* time counters were reset *//* * Interface stuff */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/* * Refclock stuff. We keep a chain of structures with data concerning * the guys we are doing I/O for. */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_short));static SOCKET open_socket P((struct sockaddr_storage *, int, int, struct interface *, int));static void close_socket P((SOCKET));#ifdef REFCLOCKstatic void close_file P((SOCKET));#endifstatic char * fdbits P((int, fd_set *));static void set_reuseaddr P((int));static isc_boolean_t socket_broadcast_enable P((struct interface *, SOCKET, struct sockaddr_storage *));static isc_boolean_t socket_broadcast_disable P((struct interface *, int, struct sockaddr_storage *));/* * Multicast functions */static isc_boolean_t addr_ismulticast P((struct sockaddr_storage *));/* * Not all platforms support multicast */#ifdef MCASTstatic isc_boolean_t socket_multicast_enable P((struct interface *, int, int, struct sockaddr_storage *));static isc_boolean_t socket_multicast_disable P((struct interface *, int, struct sockaddr_storage *));#endif#ifdef DEBUGstatic void print_interface P((int));#endiftypedef 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; int flags; 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, int));int modify_addr_in_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 find_flagged_addr_in_list P((struct sockaddr_storage *, int));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));int findlocalinterface P((struct sockaddr_storage *));int findlocalcastinterface P((struct sockaddr_storage *, int));/* * Routines to read the ntp packets */#if !defined(HAVE_IO_COMPLETION_PORT)static inline int read_network_packet P((SOCKET, struct interface *, l_fp));static inline int read_refclock_packet P((SOCKET, struct refclockio *, l_fp));#endif#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_tconnection_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 */voidinit_io(void){#ifdef SYS_WINNT if (!Win32InitSockets()) { netsyslog(LOG_ERR, "No useable winsock.dll: %m"); exit(1); } init_transmitbuff();#endif /* SYS_WINNT */ /* * Init buffer free list and stat counters */ init_recvbuff(RECV_INIT); packets_dropped = packets_received = 0; packets_ignored = 0; packets_sent = packets_notsent = 0; handler_calls = handler_pkts = 0; io_timereset = 0; loopback_interface = NULL; loopback6_interface = NULL; any_interface = NULL; any6_interface = NULL;#ifdef REFCLOCK refio = 0;#endif#if defined(HAVE_SIGNALED_IO) (void) set_signal();#endif ISC_LIST_INIT(sockets_list); ISC_LIST_INIT(remoteaddr_list); /* * Create the sockets */ BLOCKIO(); (void) create_sockets(htons(NTP_PORT)); UNBLOCKIO();#ifdef DEBUG if (debug) printf("init_io: maxactivefd %d\n", maxactivefd);#endif}/* * Function to dump the contents of the interface structure * For debugging use only. */#ifdef DEBUGvoidinterface_dump(struct interface *itf){ u_char* cp; int i; /* Limit the size of the sockaddr_storage hex dump */ int maxsize = min(32, sizeof(struct sockaddr_storage)); printf("Dumping interface: %p\n", itf); printf("fd = %d\n", itf->fd); printf("bfd = %d\n", itf->bfd); printf("sin = %s,\n", stoa(&(itf->sin))); cp = (u_char*) &(itf->sin); for(i = 0; i < maxsize; i++) { printf("%02x", *cp++); if((i+1)%4 == 0) printf(" "); } printf("\n"); printf("bcast = %s,\n", stoa(&(itf->bcast))); cp = (u_char*) &(itf->bcast); for(i = 0; i < maxsize; i++) { printf("%02x", *cp++); if((i+1)%4 == 0) printf(" "); } printf("\n"); printf("mask = %s,\n", stoa(&(itf->mask))); cp = (u_char*) &(itf->mask); for(i = 0; i < maxsize; i++) { printf("%02x", *cp++); if((i+1)%4 == 0) printf(" "); } printf("\n"); printf("name = %s\n", itf->name); printf("flags = 0x%08x\n", itf->flags); printf("last_ttl = %d\n", itf->last_ttl); printf("addr_refid = %08x\n", itf->addr_refid); printf("num_mcast = %d\n", itf->num_mcast); printf("received = %ld\n", itf->received); printf("sent = %ld\n", itf->sent); printf("notsent = %ld\n", itf->notsent); printf("ifindex = %u\n", itf->ifindex); printf("scopeid = %u\n", itf->scopeid);}static voidprint_interface(int ind) { printf("interface %d: fd=%d, bfd=%d, name=%s, flags=0x%x, scope=%d\n", ind, inter_list[ind].fd, inter_list[ind].bfd, inter_list[ind].name, inter_list[ind].flags, inter_list[ind].scopeid); /* Leave these as three printf calls. */ printf(" sin=%s", stoa((&inter_list[ind].sin))); if (inter_list[ind].flags & INT_BROADCAST) printf(" bcast=%s", stoa((&inter_list[ind].bcast))); /* Only IPv4 has a network mask */ if(inter_list[ind].family == AF_INET) printf(", mask=%s", stoa((&inter_list[ind].mask))); printf(" %s\n", inter_list[ind].ignore_packets == ISC_FALSE ? "Enabled": "Disabled"); if (debug > 4) /* in-depth debugging only */ interface_dump(&inter_list[ind]);}#endifintcreate_wildcards(u_short port) { int idx = 0; isc_boolean_t okipv4 = ISC_TRUE; /* * create pseudo-interface with wildcard IPv4 address */#ifdef IPV6_V6ONLY if(isc_net_probeipv4() != ISC_R_SUCCESS) okipv4 = ISC_FALSE;#endif if(okipv4 == ISC_TRUE) { inter_list[idx].family = AF_INET; 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 | INT_UP; inter_list[idx].ignore_packets = ISC_TRUE;#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 */ any_interface = &inter_list[idx]; wildipv4 = idx; idx++; }#ifdef INCLUDE_IPV6_SUPPORT /* * create pseudo-interface with wildcard IPv6 address */ if (isc_net_probeipv6() == ISC_R_SUCCESS) { inter_list[idx].family = AF_INET6; 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;# ifdef ISC_PLATFORM_HAVESCOPEID ((struct sockaddr_in6*)&inter_list[idx].sin)->sin6_scope_id = 0;# endif (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 = INT_UP; inter_list[idx].ignore_packets = ISC_TRUE; any6_interface = &inter_list[idx]; wildipv6 = idx; idx++; }#endif return (idx);}isc_boolean_taddress_okay(isc_interface_t *isc_if) {#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 /* * Always allow the loopback */ if((isc_if->flags & INTERFACE_F_LOOPBACK) != 0) return (ISC_TRUE); /* * Check if the interface is specified */ if (specific_interface != NULL) { if (strcasecmp(isc_if->name, specific_interface) == 0) return (ISC_TRUE); else return (ISC_FALSE); } else { if (listen_to_virtual_ips == 0 && (strchr(isc_if->name, (int)':') != NULL)) return (ISC_FALSE); } /* 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);}voidconvert_isc_if(isc_interface_t *isc_if, struct interface *itf, u_short port) { itf->scopeid = 0; itf->family = (short) isc_if->af; 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; } 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 (((isc_if->flags & INTERFACE_F_LOOPBACK) != 0) && (loopback_interface == NULL)) { loopback_interface = itf; } }#ifdef INCLUDE_IPV6_SUPPORT 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),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -