1*eabc0478Schristos /* $NetBSD: ntp_io.c,v 1.33 2024/08/18 20:47:17 christos Exp $ */ 2abb0f93cSkardel 3abb0f93cSkardel /* 4abb0f93cSkardel * ntp_io.c - input/output routines for ntpd. The socket-opening code 5abb0f93cSkardel * was shamelessly stolen from ntpd. 6abb0f93cSkardel */ 7abb0f93cSkardel 8abb0f93cSkardel #ifdef HAVE_CONFIG_H 9abb0f93cSkardel # include <config.h> 10abb0f93cSkardel #endif 11abb0f93cSkardel 12abb0f93cSkardel #include <stdio.h> 13abb0f93cSkardel #include <signal.h> 14ea66d795Schristos #ifdef HAVE_FNMATCH_H 15ea66d795Schristos # include <fnmatch.h> 16ea66d795Schristos # if !defined(FNM_CASEFOLD) && defined(FNM_IGNORECASE) 17ea66d795Schristos # define FNM_CASEFOLD FNM_IGNORECASE 18ea66d795Schristos # endif 19ea66d795Schristos #endif 20abb0f93cSkardel #ifdef HAVE_SYS_PARAM_H 21abb0f93cSkardel # include <sys/param.h> 22abb0f93cSkardel #endif 23abb0f93cSkardel #ifdef HAVE_SYS_IOCTL_H 24abb0f93cSkardel # include <sys/ioctl.h> 25abb0f93cSkardel #endif 26abb0f93cSkardel #ifdef HAVE_SYS_SOCKIO_H /* UXPV: SIOC* #defines (Frank Vance <fvance@waii.com>) */ 27abb0f93cSkardel # include <sys/sockio.h> 28abb0f93cSkardel #endif 29abb0f93cSkardel #ifdef HAVE_SYS_UIO_H 30abb0f93cSkardel # include <sys/uio.h> 31abb0f93cSkardel #endif 32abb0f93cSkardel 33abb0f93cSkardel #include "ntp_machine.h" 34abb0f93cSkardel #include "ntpd.h" 35abb0f93cSkardel #include "ntp_io.h" 36abb0f93cSkardel #include "iosignal.h" 37abb0f93cSkardel #include "ntp_lists.h" 38abb0f93cSkardel #include "ntp_refclock.h" 39abb0f93cSkardel #include "ntp_stdlib.h" 402950cc38Schristos #include "ntp_worker.h" 41abb0f93cSkardel #include "ntp_request.h" 42abb0f93cSkardel #include "ntp_assert.h" 432950cc38Schristos #include "timevalops.h" 442950cc38Schristos #include "timespecops.h" 45abb0f93cSkardel #include "ntpd-opts.h" 468b8da087Schristos #include "safecast.h" 47abb0f93cSkardel 48abb0f93cSkardel /* Don't include ISC's version of IPv6 variables and structures */ 49abb0f93cSkardel #define ISC_IPV6_H 1 50abb0f93cSkardel #include <isc/mem.h> 51abb0f93cSkardel #include <isc/interfaceiter.h> 52abb0f93cSkardel #include <isc/netaddr.h> 53abb0f93cSkardel #include <isc/result.h> 54abb0f93cSkardel #include <isc/sockaddr.h> 55abb0f93cSkardel 56abb0f93cSkardel #ifdef SIM 57abb0f93cSkardel #include "ntpsim.h" 58abb0f93cSkardel #endif 59abb0f93cSkardel 60abb0f93cSkardel #ifdef HAS_ROUTING_SOCKET 61abb0f93cSkardel # include <net/route.h> 62abb0f93cSkardel # ifdef HAVE_RTNETLINK 63abb0f93cSkardel # include <linux/rtnetlink.h> 64abb0f93cSkardel # endif 65abb0f93cSkardel #endif 66abb0f93cSkardel 67abb0f93cSkardel /* 68abb0f93cSkardel * setsockopt does not always have the same arg declaration 69abb0f93cSkardel * across all platforms. If it's not defined we make it empty 70abb0f93cSkardel */ 71abb0f93cSkardel 72abb0f93cSkardel #ifndef SETSOCKOPT_ARG_CAST 73abb0f93cSkardel #define SETSOCKOPT_ARG_CAST 74abb0f93cSkardel #endif 75abb0f93cSkardel 76abb0f93cSkardel extern int listen_to_virtual_ips; 77abb0f93cSkardel 785d681e99Schristos #ifndef IPTOS_DSCP_EF 795d681e99Schristos #define IPTOS_DSCP_EF 0xb8 805d681e99Schristos #endif 815d681e99Schristos int qos = IPTOS_DSCP_EF; /* QoS RFC3246 */ 825d681e99Schristos 835d681e99Schristos #ifdef LEAP_SMEAR 845d681e99Schristos /* TODO burnicki: This should be moved to ntp_timer.c, but if we do so 855d681e99Schristos * we get a linker error. Since we're running out of time before the leap 865d681e99Schristos * second occurs, we let it here where it just works. 875d681e99Schristos */ 885d681e99Schristos int leap_smear_intv; 895d681e99Schristos #endif 905d681e99Schristos 91abb0f93cSkardel /* 92abb0f93cSkardel * NIC rule entry 93abb0f93cSkardel */ 94abb0f93cSkardel typedef struct nic_rule_tag nic_rule; 95abb0f93cSkardel 96abb0f93cSkardel struct nic_rule_tag { 97abb0f93cSkardel nic_rule * next; 98abb0f93cSkardel nic_rule_action action; 99abb0f93cSkardel nic_rule_match match_type; 100abb0f93cSkardel char * if_name; 1013123f114Skardel sockaddr_u addr; 102abb0f93cSkardel int prefixlen; 103abb0f93cSkardel }; 104abb0f93cSkardel 105abb0f93cSkardel /* 106abb0f93cSkardel * NIC rule listhead. Entries are added at the head so that the first 107abb0f93cSkardel * match in the list is the last matching rule specified. 108abb0f93cSkardel */ 109abb0f93cSkardel nic_rule *nic_rule_list; 110abb0f93cSkardel 111abb0f93cSkardel 1122950cc38Schristos #if defined(SO_BINTIME) && defined(SCM_BINTIME) && defined(CMSG_FIRSTHDR) 1132950cc38Schristos # define HAVE_PACKET_TIMESTAMP 1142950cc38Schristos # define HAVE_BINTIME 1152950cc38Schristos # ifdef BINTIME_CTLMSGBUF_SIZE 1162950cc38Schristos # define CMSG_BUFSIZE BINTIME_CTLMSGBUF_SIZE 1172950cc38Schristos # else 1182950cc38Schristos # define CMSG_BUFSIZE 1536 /* moderate default */ 1192950cc38Schristos # endif 1202950cc38Schristos #elif defined(SO_TIMESTAMPNS) && defined(SCM_TIMESTAMPNS) && defined(CMSG_FIRSTHDR) 1212950cc38Schristos # define HAVE_PACKET_TIMESTAMP 1222950cc38Schristos # define HAVE_TIMESTAMPNS 1232950cc38Schristos # ifdef TIMESTAMPNS_CTLMSGBUF_SIZE 1242950cc38Schristos # define CMSG_BUFSIZE TIMESTAMPNS_CTLMSGBUF_SIZE 1252950cc38Schristos # else 1262950cc38Schristos # define CMSG_BUFSIZE 1536 /* moderate default */ 1272950cc38Schristos # endif 1282950cc38Schristos #elif defined(SO_TIMESTAMP) && defined(SCM_TIMESTAMP) && defined(CMSG_FIRSTHDR) 1292950cc38Schristos # define HAVE_PACKET_TIMESTAMP 130abb0f93cSkardel # define HAVE_TIMESTAMP 1312950cc38Schristos # ifdef TIMESTAMP_CTLMSGBUF_SIZE 1322950cc38Schristos # define CMSG_BUFSIZE TIMESTAMP_CTLMSGBUF_SIZE 1332950cc38Schristos # else 1342950cc38Schristos # define CMSG_BUFSIZE 1536 /* moderate default */ 135abb0f93cSkardel # endif 136abb0f93cSkardel #else 137abb0f93cSkardel /* fill in for old/other timestamp interfaces */ 138abb0f93cSkardel #endif 139abb0f93cSkardel 140abb0f93cSkardel #if defined(SYS_WINNT) 1412950cc38Schristos #include "win32_io.h" 142abb0f93cSkardel #include <isc/win32os.h> 1432950cc38Schristos #endif 144abb0f93cSkardel 145abb0f93cSkardel /* 146abb0f93cSkardel * We do asynchronous input using the SIGIO facility. A number of 147abb0f93cSkardel * recvbuf buffers are preallocated for input. In the signal 148abb0f93cSkardel * handler we poll to see which sockets are ready and read the 149abb0f93cSkardel * packets from them into the recvbuf's along with a time stamp and 150abb0f93cSkardel * an indication of the source host and the interface it was received 151abb0f93cSkardel * through. This allows us to get as accurate receive time stamps 152abb0f93cSkardel * as possible independent of other processing going on. 153abb0f93cSkardel * 154abb0f93cSkardel * We watch the number of recvbufs available to the signal handler 155abb0f93cSkardel * and allocate more when this number drops below the low water 156abb0f93cSkardel * mark. If the signal handler should run out of buffers in the 157abb0f93cSkardel * interim it will drop incoming frames, the idea being that it is 158abb0f93cSkardel * better to drop a packet than to be inaccurate. 159abb0f93cSkardel */ 160abb0f93cSkardel 161abb0f93cSkardel 162abb0f93cSkardel /* 163abb0f93cSkardel * Other statistics of possible interest 164abb0f93cSkardel */ 165abb0f93cSkardel volatile u_long packets_dropped; /* total number of packets dropped on reception */ 166abb0f93cSkardel volatile u_long packets_ignored; /* packets received on wild card interface */ 167abb0f93cSkardel volatile u_long packets_received; /* total number of packets received */ 168abb0f93cSkardel u_long packets_sent; /* total number of packets sent */ 169abb0f93cSkardel u_long packets_notsent; /* total number of packets which couldn't be sent */ 170abb0f93cSkardel 171abb0f93cSkardel volatile u_long handler_calls; /* number of calls to interrupt handler */ 172abb0f93cSkardel volatile u_long handler_pkts; /* number of pkts received by handler */ 173abb0f93cSkardel u_long io_timereset; /* time counters were reset */ 174abb0f93cSkardel 175abb0f93cSkardel /* 176abb0f93cSkardel * Interface stuff 177abb0f93cSkardel */ 1783123f114Skardel endpt * any_interface; /* wildcard ipv4 interface */ 1793123f114Skardel endpt * any6_interface; /* wildcard ipv6 interface */ 1803123f114Skardel endpt * loopback_interface; /* loopback ipv4 interface */ 181abb0f93cSkardel 182*eabc0478Schristos static isc_boolean_t broadcast_client_enabled; 1832950cc38Schristos u_int sys_ifnum; /* next .ifnum to assign */ 184abb0f93cSkardel int ninterfaces; /* Total number of interfaces */ 185abb0f93cSkardel 186*eabc0478Schristos int no_periodic_scan; /* network endpoint scans */ 187*eabc0478Schristos int scan_addrs_once; /* because dropped privs */ 188*eabc0478Schristos int nonlocal_v4_addr_up; /* should we try IPv4 pool? */ 189*eabc0478Schristos int nonlocal_v6_addr_up; /* should we try IPv6 pool? */ 190abb0f93cSkardel 191abb0f93cSkardel #ifdef REFCLOCK 192abb0f93cSkardel /* 193abb0f93cSkardel * Refclock stuff. We keep a chain of structures with data concerning 194abb0f93cSkardel * the guys we are doing I/O for. 195abb0f93cSkardel */ 196abb0f93cSkardel static struct refclockio *refio; 197abb0f93cSkardel #endif /* REFCLOCK */ 198abb0f93cSkardel 199abb0f93cSkardel /* 200abb0f93cSkardel * File descriptor masks etc. for call to select 2012950cc38Schristos * Not needed for I/O Completion Ports or anything outside this file 202abb0f93cSkardel */ 2032950cc38Schristos static fd_set activefds; 2042950cc38Schristos static int maxactivefd; 2052950cc38Schristos 206abb0f93cSkardel /* 207abb0f93cSkardel * bit alternating value to detect verified interfaces during an update cycle 208abb0f93cSkardel */ 209abb0f93cSkardel static u_short sys_interphase = 0; 210abb0f93cSkardel 2113123f114Skardel static endpt * new_interface(endpt *); 2123123f114Skardel static void add_interface(endpt *); 2133123f114Skardel static int update_interfaces(u_short, interface_receiver_t, 2143123f114Skardel void *); 2153123f114Skardel static void remove_interface(endpt *); 2163123f114Skardel static endpt * create_interface(u_short, endpt *); 217abb0f93cSkardel 218*eabc0478Schristos static inline int is_wildcard_addr(const sockaddr_u *psau); 219abb0f93cSkardel 220abb0f93cSkardel /* 221abb0f93cSkardel * Multicast functions 222abb0f93cSkardel */ 223abb0f93cSkardel static isc_boolean_t addr_ismulticast (sockaddr_u *); 2243123f114Skardel static isc_boolean_t is_anycast (sockaddr_u *, 2253123f114Skardel const char *); 2263123f114Skardel 227abb0f93cSkardel /* 228abb0f93cSkardel * Not all platforms support multicast 229abb0f93cSkardel */ 230abb0f93cSkardel #ifdef MCAST 2313123f114Skardel static isc_boolean_t socket_multicast_enable (endpt *, sockaddr_u *); 2323123f114Skardel static isc_boolean_t socket_multicast_disable(endpt *, sockaddr_u *); 233abb0f93cSkardel #endif 234abb0f93cSkardel 235abb0f93cSkardel #ifdef DEBUG 2363123f114Skardel static void interface_dump (const endpt *); 237a2545411Skardel static void print_interface (const endpt *, const char *, const char *); 238abb0f93cSkardel #define DPRINT_INTERFACE(level, args) do { if (debug >= (level)) { print_interface args; } } while (0) 239abb0f93cSkardel #else 240abb0f93cSkardel #define DPRINT_INTERFACE(level, args) do {} while (0) 241abb0f93cSkardel #endif 242abb0f93cSkardel 243abb0f93cSkardel typedef struct vsock vsock_t; 244abb0f93cSkardel enum desc_type { FD_TYPE_SOCKET, FD_TYPE_FILE }; 245abb0f93cSkardel 246abb0f93cSkardel struct vsock { 247abb0f93cSkardel vsock_t * link; 248abb0f93cSkardel SOCKET fd; 249abb0f93cSkardel enum desc_type type; 250abb0f93cSkardel }; 251abb0f93cSkardel 252abb0f93cSkardel vsock_t *fd_list; 253abb0f93cSkardel 254abb0f93cSkardel #if !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) 255abb0f93cSkardel /* 256abb0f93cSkardel * async notification processing (e. g. routing sockets) 257abb0f93cSkardel */ 258abb0f93cSkardel /* 259abb0f93cSkardel * support for receiving data on fd that is not a refclock or a socket 260abb0f93cSkardel * like e. g. routing sockets 261abb0f93cSkardel */ 262abb0f93cSkardel struct asyncio_reader { 263abb0f93cSkardel struct asyncio_reader *link; /* the list this is being kept in */ 264abb0f93cSkardel SOCKET fd; /* fd to be read */ 265abb0f93cSkardel void *data; /* possibly local data */ 266abb0f93cSkardel void (*receiver)(struct asyncio_reader *); /* input handler */ 267abb0f93cSkardel }; 268abb0f93cSkardel 269abb0f93cSkardel struct asyncio_reader *asyncio_reader_list; 270abb0f93cSkardel 271abb0f93cSkardel static void delete_asyncio_reader (struct asyncio_reader *); 272abb0f93cSkardel static struct asyncio_reader *new_asyncio_reader (void); 273abb0f93cSkardel static void add_asyncio_reader (struct asyncio_reader *, enum desc_type); 274abb0f93cSkardel static void remove_asyncio_reader (struct asyncio_reader *); 275abb0f93cSkardel 276abb0f93cSkardel #endif /* !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) */ 277abb0f93cSkardel 278abb0f93cSkardel static void init_async_notifications (void); 279abb0f93cSkardel 2803123f114Skardel static int addr_eqprefix (const sockaddr_u *, const sockaddr_u *, 2813123f114Skardel int); 2823123f114Skardel static int addr_samesubnet (const sockaddr_u *, const sockaddr_u *, 2833123f114Skardel const sockaddr_u *, const sockaddr_u *); 284abb0f93cSkardel static int create_sockets (u_short); 2853123f114Skardel static SOCKET open_socket (sockaddr_u *, int, int, endpt *); 286abb0f93cSkardel static void set_reuseaddr (int); 287*eabc0478Schristos static isc_boolean_t socket_broadcast_enable (endpt *, SOCKET, sockaddr_u *); 28868dbbb44Schristos 28968dbbb44Schristos #if !defined(HAVE_IO_COMPLETION_PORT) && !defined(HAVE_SIGNALED_IO) 29068dbbb44Schristos static char * fdbits (int, const fd_set *); 29168dbbb44Schristos #endif 292ea66d795Schristos #ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES 293*eabc0478Schristos static isc_boolean_t socket_broadcast_disable (endpt *, sockaddr_u *); 294ea66d795Schristos #endif 295abb0f93cSkardel 296abb0f93cSkardel typedef struct remaddr remaddr_t; 297abb0f93cSkardel 298abb0f93cSkardel struct remaddr { 299abb0f93cSkardel remaddr_t * link; 300abb0f93cSkardel sockaddr_u addr; 3013123f114Skardel endpt * ep; 302abb0f93cSkardel }; 303abb0f93cSkardel 304abb0f93cSkardel remaddr_t * remoteaddr_list; 3053123f114Skardel endpt * ep_list; /* complete endpt list */ 3063123f114Skardel endpt * mc4_list; /* IPv4 mcast-capable unicast endpts */ 3073123f114Skardel endpt * mc6_list; /* IPv6 mcast-capable unicast endpts */ 308abb0f93cSkardel 3093123f114Skardel static endpt * wildipv4; 3103123f114Skardel static endpt * wildipv6; 311abb0f93cSkardel 312*eabc0478Schristos #define RFC3927_ADDR 0xa9fe0000 /* 169.254. */ 313*eabc0478Schristos #define RFC3927_MASK 0xffff0000 314*eabc0478Schristos #define IS_AUTOCONF(addr4) \ 315*eabc0478Schristos ((SRCADR(addr4) & RFC3927_MASK) == RFC3927_ADDR) 316*eabc0478Schristos 3172950cc38Schristos #ifdef SYS_WINNT 3182950cc38Schristos int accept_wildcard_if_for_winnt; 3192950cc38Schristos #else 3202950cc38Schristos const int accept_wildcard_if_for_winnt = FALSE; 321*eabc0478Schristos #define init_io_completion_port() do {} while (FALSE) 3222950cc38Schristos #endif 3232950cc38Schristos 3243123f114Skardel static void add_fd_to_list (SOCKET, enum desc_type); 3253123f114Skardel static endpt * find_addr_in_list (sockaddr_u *); 3263123f114Skardel static endpt * find_flagged_addr_in_list(sockaddr_u *, u_int32); 327abb0f93cSkardel static void delete_addr_from_list (sockaddr_u *); 3283123f114Skardel static void delete_interface_from_list(endpt *); 329*eabc0478Schristos static void close_and_delete_fd_from_list(SOCKET, endpt *); 3303123f114Skardel static void add_addr_to_list (sockaddr_u *, endpt *); 331abb0f93cSkardel static void create_wildcards (u_short); 3323123f114Skardel static endpt * findlocalinterface (sockaddr_u *, int, int); 3333123f114Skardel static endpt * findclosestinterface (sockaddr_u *, int); 334abb0f93cSkardel #ifdef DEBUG 335abb0f93cSkardel static const char * action_text (nic_rule_action); 336abb0f93cSkardel #endif 3373123f114Skardel static nic_rule_action interface_action(char *, sockaddr_u *, u_int32); 338abb0f93cSkardel static void convert_isc_if (isc_interface_t *, 3393123f114Skardel endpt *, u_short); 3403123f114Skardel static void calc_addr_distance(sockaddr_u *, 3413123f114Skardel const sockaddr_u *, 3423123f114Skardel const sockaddr_u *); 3433123f114Skardel static int cmp_addr_distance(const sockaddr_u *, 3443123f114Skardel const sockaddr_u *); 345abb0f93cSkardel 346abb0f93cSkardel /* 347abb0f93cSkardel * Routines to read the ntp packets 348abb0f93cSkardel */ 349abb0f93cSkardel #if !defined(HAVE_IO_COMPLETION_PORT) 350*eabc0478Schristos static inline int read_network_packet (SOCKET, endpt *, l_fp); 3512950cc38Schristos static void ntpd_addremove_io_fd (int, int, int); 35268dbbb44Schristos static void input_handler_scan (const l_fp*, const fd_set*); 35368dbbb44Schristos static int/*BOOL*/ sanitize_fdset (int errc); 3542950cc38Schristos #ifdef REFCLOCK 355abb0f93cSkardel static inline int read_refclock_packet (SOCKET, struct refclockio *, l_fp); 356abb0f93cSkardel #endif 35768dbbb44Schristos #ifdef HAVE_SIGNALED_IO 35868dbbb44Schristos static void input_handler (l_fp*); 3592950cc38Schristos #endif 36068dbbb44Schristos #endif 361abb0f93cSkardel 3622950cc38Schristos 3632950cc38Schristos #ifndef HAVE_IO_COMPLETION_PORT 364abb0f93cSkardel void 3652950cc38Schristos maintain_activefds( 3662950cc38Schristos int fd, 3672950cc38Schristos int closing 368abb0f93cSkardel ) 369abb0f93cSkardel { 3702950cc38Schristos int i; 371abb0f93cSkardel 3722950cc38Schristos if (fd < 0 || fd >= FD_SETSIZE) { 373abb0f93cSkardel msyslog(LOG_ERR, 3742950cc38Schristos "Too many sockets in use, FD_SETSIZE %d exceeded by fd %d", 3752950cc38Schristos FD_SETSIZE, fd); 3762950cc38Schristos exit(1); 377abb0f93cSkardel } 378abb0f93cSkardel 3792950cc38Schristos if (!closing) { 3802950cc38Schristos FD_SET(fd, &activefds); 3812950cc38Schristos maxactivefd = max(fd, maxactivefd); 382abb0f93cSkardel } else { 3832950cc38Schristos FD_CLR(fd, &activefds); 3842950cc38Schristos if (maxactivefd && fd == maxactivefd) { 3852950cc38Schristos for (i = maxactivefd - 1; i >= 0; i--) 3862950cc38Schristos if (FD_ISSET(i, &activefds)) { 3872950cc38Schristos maxactivefd = i; 3882950cc38Schristos break; 389abb0f93cSkardel } 390af12ab5eSchristos INSIST(fd != maxactivefd); 391abb0f93cSkardel } 3922950cc38Schristos } 3932950cc38Schristos } 3942950cc38Schristos #endif /* !HAVE_IO_COMPLETION_PORT */ 3952950cc38Schristos 396abb0f93cSkardel 397abb0f93cSkardel #ifdef DEBUG_TIMING 398abb0f93cSkardel /* 399abb0f93cSkardel * collect timing information for various processing 4002950cc38Schristos * paths. currently we only pass them on to the file 401abb0f93cSkardel * for later processing. this could also do histogram 402abb0f93cSkardel * based analysis in other to reduce the load (and skew) 403abb0f93cSkardel * dur to the file output 404abb0f93cSkardel */ 405abb0f93cSkardel void 406abb0f93cSkardel collect_timing(struct recvbuf *rb, const char *tag, int count, l_fp *dts) 407abb0f93cSkardel { 408abb0f93cSkardel char buf[256]; 409abb0f93cSkardel 410abb0f93cSkardel snprintf(buf, sizeof(buf), "%s %d %s %s", 411abb0f93cSkardel (rb != NULL) 412abb0f93cSkardel ? ((rb->dstadr != NULL) 413abb0f93cSkardel ? stoa(&rb->recv_srcadr) 414abb0f93cSkardel : "-REFCLOCK-") 415abb0f93cSkardel : "-", 416abb0f93cSkardel count, lfptoa(dts, 9), tag); 417abb0f93cSkardel record_timing_stats(buf); 418abb0f93cSkardel } 419abb0f93cSkardel #endif 420abb0f93cSkardel 421abb0f93cSkardel /* 422abb0f93cSkardel * About dynamic interfaces, sockets, reception and more... 423abb0f93cSkardel * 424abb0f93cSkardel * the code solves following tasks: 425abb0f93cSkardel * 426abb0f93cSkardel * - keep a current list of active interfaces in order 427abb0f93cSkardel * to bind to to the interface address on NTP_PORT so that 428abb0f93cSkardel * all wild and specific bindings for NTP_PORT are taken by ntpd 429abb0f93cSkardel * to avoid other daemons messing with the time or sockets. 430abb0f93cSkardel * - all interfaces keep a list of peers that are referencing 431abb0f93cSkardel * the interface in order to quickly re-assign the peers to 432abb0f93cSkardel * new interface in case an interface is deleted (=> gone from system or 433abb0f93cSkardel * down) 434abb0f93cSkardel * - have a preconfigured socket ready with the right local address 435abb0f93cSkardel * for transmission and reception 436abb0f93cSkardel * - have an address list for all destination addresses used within ntpd 437abb0f93cSkardel * to find the "right" preconfigured socket. 438abb0f93cSkardel * - facilitate updating the internal interface list with respect to 439abb0f93cSkardel * the current kernel state 440abb0f93cSkardel * 441abb0f93cSkardel * special issues: 442abb0f93cSkardel * 443abb0f93cSkardel * - mapping of multicast addresses to the interface affected is not always 444abb0f93cSkardel * one to one - especially on hosts with multiple interfaces 445abb0f93cSkardel * the code here currently allocates a separate interface entry for those 446abb0f93cSkardel * multicast addresses 447abb0f93cSkardel * iff it is able to bind to a *new* socket with the multicast address (flags |= MCASTIF) 448abb0f93cSkardel * in case of failure the multicast address is bound to an existing interface. 449abb0f93cSkardel * - on some systems it is perfectly legal to assign the same address to 450abb0f93cSkardel * multiple interfaces. Therefore this code does not keep a list of interfaces 451abb0f93cSkardel * but a list of interfaces that represent a unique address as determined by the kernel 452abb0f93cSkardel * by the procedure in findlocalinterface. Thus it is perfectly legal to see only 453abb0f93cSkardel * one representative of a group of real interfaces if they share the same address. 454abb0f93cSkardel * 455abb0f93cSkardel * Frank Kardel 20050910 456abb0f93cSkardel */ 457abb0f93cSkardel 458abb0f93cSkardel /* 4592950cc38Schristos * init_io - initialize I/O module. 460abb0f93cSkardel */ 461abb0f93cSkardel void 462abb0f93cSkardel init_io(void) 463abb0f93cSkardel { 4642950cc38Schristos /* Init buffer free list and stat counters */ 465abb0f93cSkardel init_recvbuff(RECV_INIT); 466*eabc0478Schristos endpt_scan_period = 301; 4672950cc38Schristos 4682950cc38Schristos #ifdef WORK_PIPE 4692950cc38Schristos addremove_io_fd = &ntpd_addremove_io_fd; 4702950cc38Schristos #endif 471abb0f93cSkardel 472abb0f93cSkardel init_io_completion_port(); 473*eabc0478Schristos #if defined(HAVE_SIGNALED_IO) 4742950cc38Schristos (void) set_signal(input_handler); 475abb0f93cSkardel #endif 476abb0f93cSkardel } 477abb0f93cSkardel 478abb0f93cSkardel 4792950cc38Schristos static void 4802950cc38Schristos ntpd_addremove_io_fd( 4812950cc38Schristos int fd, 4822950cc38Schristos int is_pipe, 4832950cc38Schristos int remove_it 4842950cc38Schristos ) 4852950cc38Schristos { 4862950cc38Schristos UNUSED_ARG(is_pipe); 4872950cc38Schristos 4882950cc38Schristos #ifdef HAVE_SIGNALED_IO 48968dbbb44Schristos if (!remove_it) 4902950cc38Schristos init_socket_sig(fd); 4912950cc38Schristos #endif /* not HAVE_SIGNALED_IO */ 4922950cc38Schristos 4932950cc38Schristos maintain_activefds(fd, remove_it); 4942950cc38Schristos } 4952950cc38Schristos 4962950cc38Schristos 497abb0f93cSkardel /* 498abb0f93cSkardel * io_open_sockets - call socket creation routine 499abb0f93cSkardel */ 500abb0f93cSkardel void 501abb0f93cSkardel io_open_sockets(void) 502abb0f93cSkardel { 503abb0f93cSkardel static int already_opened; 504abb0f93cSkardel 505abb0f93cSkardel if (already_opened || HAVE_OPT( SAVECONFIGQUIT )) 506abb0f93cSkardel return; 507abb0f93cSkardel 508abb0f93cSkardel already_opened = 1; 509abb0f93cSkardel 510abb0f93cSkardel /* 511abb0f93cSkardel * Create the sockets 512abb0f93cSkardel */ 513abb0f93cSkardel BLOCKIO(); 514abb0f93cSkardel create_sockets(NTP_PORT); 515abb0f93cSkardel UNBLOCKIO(); 516abb0f93cSkardel 517abb0f93cSkardel init_async_notifications(); 518abb0f93cSkardel 519abb0f93cSkardel DPRINTF(3, ("io_open_sockets: maxactivefd %d\n", maxactivefd)); 520abb0f93cSkardel } 521abb0f93cSkardel 522abb0f93cSkardel 523abb0f93cSkardel #ifdef DEBUG 524abb0f93cSkardel /* 525abb0f93cSkardel * function to dump the contents of the interface structure 526abb0f93cSkardel * for debugging use only. 527ccc794f0Schristos * We face a dilemma here -- sockets are FDs under POSIX and 528ccc794f0Schristos * actually HANDLES under Windows. So we use '%lld' as format 529ccc794f0Schristos * and cast the value to 'long long'; this should not hurt 530ccc794f0Schristos * with UNIX-like systems and does not truncate values on Win64. 531abb0f93cSkardel */ 532abb0f93cSkardel void 5333123f114Skardel interface_dump(const endpt *itf) 534abb0f93cSkardel { 535abb0f93cSkardel printf("Dumping interface: %p\n", itf); 536ccc794f0Schristos printf("fd = %lld\n", (long long)itf->fd); 537ccc794f0Schristos printf("bfd = %lld\n", (long long)itf->bfd); 538abb0f93cSkardel printf("sin = %s,\n", stoa(&itf->sin)); 539abb0f93cSkardel printf("bcast = %s,\n", stoa(&itf->bcast)); 540abb0f93cSkardel printf("mask = %s,\n", stoa(&itf->mask)); 541abb0f93cSkardel printf("name = %s\n", itf->name); 542abb0f93cSkardel printf("flags = 0x%08x\n", itf->flags); 543abb0f93cSkardel printf("last_ttl = %d\n", itf->last_ttl); 544abb0f93cSkardel printf("addr_refid = %08x\n", itf->addr_refid); 545abb0f93cSkardel printf("num_mcast = %d\n", itf->num_mcast); 546abb0f93cSkardel printf("received = %ld\n", itf->received); 547abb0f93cSkardel printf("sent = %ld\n", itf->sent); 548abb0f93cSkardel printf("notsent = %ld\n", itf->notsent); 5493123f114Skardel printf("ifindex = %u\n", itf->ifindex); 550abb0f93cSkardel printf("peercnt = %u\n", itf->peercnt); 551abb0f93cSkardel printf("phase = %u\n", itf->phase); 552abb0f93cSkardel } 553abb0f93cSkardel 554abb0f93cSkardel 555abb0f93cSkardel /* 556abb0f93cSkardel * print_interface - helper to output debug information 557abb0f93cSkardel */ 558abb0f93cSkardel static void 559a2545411Skardel print_interface(const endpt *iface, const char *pfx, const char *sfx) 560abb0f93cSkardel { 561ccc794f0Schristos printf("%sinterface #%d: fd=%lld, bfd=%lld, name=%s, flags=0x%x, ifindex=%u, sin=%s", 562abb0f93cSkardel pfx, 563abb0f93cSkardel iface->ifnum, 564ccc794f0Schristos (long long)iface->fd, 565ccc794f0Schristos (long long)iface->bfd, 566abb0f93cSkardel iface->name, 567abb0f93cSkardel iface->flags, 5683123f114Skardel iface->ifindex, 569abb0f93cSkardel stoa(&iface->sin)); 570abb0f93cSkardel if (AF_INET == iface->family) { 571abb0f93cSkardel if (iface->flags & INT_BROADCAST) 572abb0f93cSkardel printf(", bcast=%s", stoa(&iface->bcast)); 573abb0f93cSkardel printf(", mask=%s", stoa(&iface->mask)); 574abb0f93cSkardel } 575abb0f93cSkardel printf(", %s:%s", 576abb0f93cSkardel (iface->ignore_packets) 577abb0f93cSkardel ? "Disabled" 578abb0f93cSkardel : "Enabled", 579abb0f93cSkardel sfx); 580abb0f93cSkardel if (debug > 4) /* in-depth debugging only */ 581abb0f93cSkardel interface_dump(iface); 582abb0f93cSkardel } 583abb0f93cSkardel #endif 584abb0f93cSkardel 585abb0f93cSkardel #if !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) 586abb0f93cSkardel /* 587abb0f93cSkardel * create an asyncio_reader structure 588abb0f93cSkardel */ 589abb0f93cSkardel static struct asyncio_reader * 590abb0f93cSkardel new_asyncio_reader(void) 591abb0f93cSkardel { 592abb0f93cSkardel struct asyncio_reader *reader; 593abb0f93cSkardel 5942950cc38Schristos reader = emalloc_zero(sizeof(*reader)); 595abb0f93cSkardel reader->fd = INVALID_SOCKET; 5962950cc38Schristos 597abb0f93cSkardel return reader; 598abb0f93cSkardel } 599abb0f93cSkardel 600abb0f93cSkardel /* 601abb0f93cSkardel * delete a reader 602abb0f93cSkardel */ 603abb0f93cSkardel static void 604abb0f93cSkardel delete_asyncio_reader( 605abb0f93cSkardel struct asyncio_reader *reader 606abb0f93cSkardel ) 607abb0f93cSkardel { 608abb0f93cSkardel free(reader); 609abb0f93cSkardel } 610abb0f93cSkardel 611abb0f93cSkardel /* 612abb0f93cSkardel * add asynchio_reader 613abb0f93cSkardel */ 614abb0f93cSkardel static void 615abb0f93cSkardel add_asyncio_reader( 616abb0f93cSkardel struct asyncio_reader * reader, 617abb0f93cSkardel enum desc_type type) 618abb0f93cSkardel { 619abb0f93cSkardel LINK_SLIST(asyncio_reader_list, reader, link); 620abb0f93cSkardel add_fd_to_list(reader->fd, type); 621abb0f93cSkardel } 622abb0f93cSkardel 623abb0f93cSkardel /* 624*eabc0478Schristos * remove asyncio_reader 625abb0f93cSkardel */ 626abb0f93cSkardel static void 627abb0f93cSkardel remove_asyncio_reader( 628abb0f93cSkardel struct asyncio_reader *reader 629abb0f93cSkardel ) 630abb0f93cSkardel { 631abb0f93cSkardel struct asyncio_reader *unlinked; 632abb0f93cSkardel 633abb0f93cSkardel UNLINK_SLIST(unlinked, asyncio_reader_list, reader, link, 634abb0f93cSkardel struct asyncio_reader); 635abb0f93cSkardel 636*eabc0478Schristos if (reader->fd != INVALID_SOCKET) { 637*eabc0478Schristos close_and_delete_fd_from_list(reader->fd, NULL); 638*eabc0478Schristos } 639abb0f93cSkardel reader->fd = INVALID_SOCKET; 640abb0f93cSkardel } 641abb0f93cSkardel #endif /* !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) */ 642abb0f93cSkardel 6433123f114Skardel 6443123f114Skardel /* compare two sockaddr prefixes */ 6453123f114Skardel static int 6463123f114Skardel addr_eqprefix( 6473123f114Skardel const sockaddr_u * a, 6483123f114Skardel const sockaddr_u * b, 6493123f114Skardel int prefixlen 6503123f114Skardel ) 6513123f114Skardel { 6523123f114Skardel isc_netaddr_t isc_a; 6533123f114Skardel isc_netaddr_t isc_b; 6543123f114Skardel isc_sockaddr_t isc_sa; 6553123f114Skardel 6562950cc38Schristos ZERO(isc_sa); 6572950cc38Schristos memcpy(&isc_sa.type, a, min(sizeof(isc_sa.type), sizeof(*a))); 6583123f114Skardel isc_netaddr_fromsockaddr(&isc_a, &isc_sa); 6593123f114Skardel 6602950cc38Schristos ZERO(isc_sa); 6612950cc38Schristos memcpy(&isc_sa.type, b, min(sizeof(isc_sa.type), sizeof(*b))); 6623123f114Skardel isc_netaddr_fromsockaddr(&isc_b, &isc_sa); 6633123f114Skardel 6643123f114Skardel return (int)isc_netaddr_eqprefix(&isc_a, &isc_b, 6653123f114Skardel (u_int)prefixlen); 6663123f114Skardel } 6673123f114Skardel 6683123f114Skardel 6693123f114Skardel static int 6703123f114Skardel addr_samesubnet( 6713123f114Skardel const sockaddr_u * a, 6723123f114Skardel const sockaddr_u * a_mask, 6733123f114Skardel const sockaddr_u * b, 6743123f114Skardel const sockaddr_u * b_mask 6753123f114Skardel ) 6763123f114Skardel { 6773123f114Skardel const u_int32 * pa; 6783123f114Skardel const u_int32 * pa_limit; 6793123f114Skardel const u_int32 * pb; 6803123f114Skardel const u_int32 * pm; 6813123f114Skardel size_t loops; 6823123f114Skardel 683af12ab5eSchristos REQUIRE(AF(a) == AF(a_mask)); 684af12ab5eSchristos REQUIRE(AF(b) == AF(b_mask)); 6853123f114Skardel /* 6863123f114Skardel * With address and mask families verified to match, comparing 6873123f114Skardel * the masks also validates the address's families match. 6883123f114Skardel */ 6893123f114Skardel if (!SOCK_EQ(a_mask, b_mask)) 6903123f114Skardel return FALSE; 6913123f114Skardel 6923123f114Skardel if (IS_IPV6(a)) { 6933123f114Skardel loops = sizeof(NSRCADR6(a)) / sizeof(*pa); 6943123f114Skardel pa = (const void *)&NSRCADR6(a); 6953123f114Skardel pb = (const void *)&NSRCADR6(b); 6963123f114Skardel pm = (const void *)&NSRCADR6(a_mask); 6973123f114Skardel } else { 6983123f114Skardel loops = sizeof(NSRCADR(a)) / sizeof(*pa); 6993123f114Skardel pa = (const void *)&NSRCADR(a); 7003123f114Skardel pb = (const void *)&NSRCADR(b); 7013123f114Skardel pm = (const void *)&NSRCADR(a_mask); 7023123f114Skardel } 7033123f114Skardel for (pa_limit = pa + loops; pa < pa_limit; pa++, pb++, pm++) 7043123f114Skardel if ((*pa & *pm) != (*pb & *pm)) 7053123f114Skardel return FALSE; 7063123f114Skardel 7073123f114Skardel return TRUE; 7083123f114Skardel } 7093123f114Skardel 7103123f114Skardel 711abb0f93cSkardel /* 712abb0f93cSkardel * interface list enumerator - visitor pattern 713abb0f93cSkardel */ 714abb0f93cSkardel void 715abb0f93cSkardel interface_enumerate( 716abb0f93cSkardel interface_receiver_t receiver, 717abb0f93cSkardel void * data 718abb0f93cSkardel ) 719abb0f93cSkardel { 720abb0f93cSkardel interface_info_t ifi; 721abb0f93cSkardel 722abb0f93cSkardel ifi.action = IFS_EXISTS; 7233123f114Skardel for (ifi.ep = ep_list; ifi.ep != NULL; ifi.ep = ifi.ep->elink) 724abb0f93cSkardel (*receiver)(data, &ifi); 725abb0f93cSkardel } 726abb0f93cSkardel 727abb0f93cSkardel /* 728abb0f93cSkardel * do standard initialization of interface structure 729abb0f93cSkardel */ 730*eabc0478Schristos static inline void 731abb0f93cSkardel init_interface( 7323123f114Skardel endpt *ep 733abb0f93cSkardel ) 734abb0f93cSkardel { 7352950cc38Schristos ZERO(*ep); 7363123f114Skardel ep->fd = INVALID_SOCKET; 7373123f114Skardel ep->bfd = INVALID_SOCKET; 7383123f114Skardel ep->phase = sys_interphase; 739abb0f93cSkardel } 740abb0f93cSkardel 741abb0f93cSkardel 742abb0f93cSkardel /* 743abb0f93cSkardel * create new interface structure initialize from 744abb0f93cSkardel * template structure or via standard initialization 745abb0f93cSkardel * function 746abb0f93cSkardel */ 747*eabc0478Schristos static endpt * 748abb0f93cSkardel new_interface( 749*eabc0478Schristos endpt *protot 750abb0f93cSkardel ) 751abb0f93cSkardel { 752*eabc0478Schristos endpt * iface; 753abb0f93cSkardel 754abb0f93cSkardel iface = emalloc(sizeof(*iface)); 755*eabc0478Schristos if (NULL == protot) { 756*eabc0478Schristos ZERO(*iface); 757*eabc0478Schristos } else { 758*eabc0478Schristos memcpy(iface, protot, sizeof(*iface)); 759*eabc0478Schristos } 760abb0f93cSkardel /* count every new instance of an interface in the system */ 761abb0f93cSkardel iface->ifnum = sys_ifnum++; 762abb0f93cSkardel iface->starttime = current_time; 763abb0f93cSkardel 76468dbbb44Schristos # ifdef HAVE_IO_COMPLETION_PORT 76568dbbb44Schristos if (!io_completion_port_add_interface(iface)) { 76668dbbb44Schristos msyslog(LOG_EMERG, "cannot register interface with IO engine -- will exit now"); 76768dbbb44Schristos exit(1); 76868dbbb44Schristos } 76968dbbb44Schristos # endif 770abb0f93cSkardel return iface; 771abb0f93cSkardel } 772abb0f93cSkardel 773abb0f93cSkardel 774abb0f93cSkardel /* 775abb0f93cSkardel * return interface storage into free memory pool 776abb0f93cSkardel */ 77768dbbb44Schristos static void 778abb0f93cSkardel delete_interface( 7793123f114Skardel endpt *ep 780abb0f93cSkardel ) 781abb0f93cSkardel { 78268dbbb44Schristos # ifdef HAVE_IO_COMPLETION_PORT 78368dbbb44Schristos io_completion_port_remove_interface(ep); 78468dbbb44Schristos # endif 7853123f114Skardel free(ep); 786abb0f93cSkardel } 787abb0f93cSkardel 788abb0f93cSkardel 789abb0f93cSkardel /* 790abb0f93cSkardel * link interface into list of known interfaces 791abb0f93cSkardel */ 792abb0f93cSkardel static void 793abb0f93cSkardel add_interface( 7943123f114Skardel endpt * ep 795abb0f93cSkardel ) 796abb0f93cSkardel { 7973123f114Skardel endpt ** pmclisthead; 7983123f114Skardel endpt * scan; 7993123f114Skardel endpt * scan_next; 8003123f114Skardel int same_subnet; 8013123f114Skardel int rc; 8023123f114Skardel 8032950cc38Schristos /* Calculate the refid */ 8043123f114Skardel ep->addr_refid = addr2refid(&ep->sin); 805*eabc0478Schristos # ifdef WORDS_BIGENDIAN 806*eabc0478Schristos if (IS_IPV6(&ep->sin)) { 807*eabc0478Schristos ep->old_refid = BYTESWAP32(ep->addr_refid); 808*eabc0478Schristos } 809*eabc0478Schristos # endif 8102950cc38Schristos /* link at tail so ntpdc -c ifstats index increases each row */ 8112950cc38Schristos LINK_TAIL_SLIST(ep_list, ep, elink, endpt); 812abb0f93cSkardel ninterfaces++; 8133123f114Skardel #ifdef MCAST 8143123f114Skardel /* the rest is for enabled multicast-capable addresses only */ 8153123f114Skardel if (ep->ignore_packets || !(INT_MULTICAST & ep->flags) || 8163123f114Skardel INT_LOOPBACK & ep->flags) 8173123f114Skardel return; 8183123f114Skardel # ifndef INCLUDE_IPV6_MULTICAST_SUPPORT 8193123f114Skardel if (AF_INET6 == ep->family) 8203123f114Skardel return; 8213123f114Skardel # endif 8223123f114Skardel pmclisthead = (AF_INET == ep->family) 8233123f114Skardel ? &mc4_list 8243123f114Skardel : &mc6_list; 8253123f114Skardel 8263123f114Skardel /* 827*eabc0478Schristos * If we have multiple global addresses from the same prefix 828*eabc0478Schristos * on the same network interface, multicast from one. 8293123f114Skardel */ 8303123f114Skardel for (scan = *pmclisthead; scan != NULL; scan = scan_next) { 8313123f114Skardel scan_next = scan->mclink; 832*eabc0478Schristos if ( ep->family != scan->family 833*eabc0478Schristos || ep->ifindex != scan->ifindex) { 8343123f114Skardel continue; 835*eabc0478Schristos } 8363123f114Skardel same_subnet = addr_samesubnet(&ep->sin, &ep->mask, 8373123f114Skardel &scan->sin, &scan->mask); 838*eabc0478Schristos if (same_subnet) { 839*eabc0478Schristos DPRINTF(4, ("did not add %s to multicast-capable list" 840*eabc0478Schristos "which already has %s\n", 841*eabc0478Schristos stoa(&ep->sin), stoa(&scan->sin))); 8423123f114Skardel return; 8433123f114Skardel } 8443123f114Skardel } 8453123f114Skardel LINK_SLIST(*pmclisthead, ep, mclink); 8462950cc38Schristos if (INVALID_SOCKET == ep->fd) 8472950cc38Schristos return; 8482950cc38Schristos 8493123f114Skardel /* 8503123f114Skardel * select the local address from which to send to multicast. 8513123f114Skardel */ 8523123f114Skardel switch (AF(&ep->sin)) { 8532950cc38Schristos 8543123f114Skardel case AF_INET : 8553123f114Skardel rc = setsockopt(ep->fd, IPPROTO_IP, 8563123f114Skardel IP_MULTICAST_IF, 8573123f114Skardel (void *)&NSRCADR(&ep->sin), 8583123f114Skardel sizeof(NSRCADR(&ep->sin))); 8593123f114Skardel if (rc) 8603123f114Skardel msyslog(LOG_ERR, 8613123f114Skardel "setsockopt IP_MULTICAST_IF %s fails: %m", 8623123f114Skardel stoa(&ep->sin)); 8633123f114Skardel break; 8642950cc38Schristos 8653123f114Skardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT 8663123f114Skardel case AF_INET6 : 8673123f114Skardel rc = setsockopt(ep->fd, IPPROTO_IPV6, 8683123f114Skardel IPV6_MULTICAST_IF, 8693123f114Skardel (void *)&ep->ifindex, 8703123f114Skardel sizeof(ep->ifindex)); 8712950cc38Schristos /* do not complain if bound addr scope is ifindex */ 8722950cc38Schristos if (rc && ep->ifindex != SCOPE(&ep->sin)) 8733123f114Skardel msyslog(LOG_ERR, 8743123f114Skardel "setsockopt IPV6_MULTICAST_IF %u for %s fails: %m", 8753123f114Skardel ep->ifindex, stoa(&ep->sin)); 8763123f114Skardel break; 8773123f114Skardel # endif 8783123f114Skardel } 8793123f114Skardel #endif /* MCAST */ 880abb0f93cSkardel } 881abb0f93cSkardel 882abb0f93cSkardel 883abb0f93cSkardel /* 884abb0f93cSkardel * remove interface from known interface list and clean up 885abb0f93cSkardel * associated resources 886abb0f93cSkardel */ 887abb0f93cSkardel static void 888abb0f93cSkardel remove_interface( 8893123f114Skardel endpt * ep 890abb0f93cSkardel ) 891abb0f93cSkardel { 8923123f114Skardel endpt * unlinked; 8933123f114Skardel endpt ** pmclisthead; 894abb0f93cSkardel sockaddr_u resmask; 895*eabc0478Schristos int/*BOOL*/ success; 896abb0f93cSkardel 8973123f114Skardel UNLINK_SLIST(unlinked, ep_list, ep, elink, endpt); 8983123f114Skardel if (!ep->ignore_packets && INT_MULTICAST & ep->flags) { 8993123f114Skardel pmclisthead = (AF_INET == ep->family) 9003123f114Skardel ? &mc4_list 9013123f114Skardel : &mc6_list; 9023123f114Skardel UNLINK_SLIST(unlinked, *pmclisthead, ep, mclink, endpt); 9033123f114Skardel DPRINTF(4, ("%s %s IPv%s multicast-capable unicast local address list\n", 9043123f114Skardel stoa(&ep->sin), 9053123f114Skardel (unlinked != NULL) 9063123f114Skardel ? "removed from" 9073123f114Skardel : "not found on", 9083123f114Skardel (AF_INET == ep->family) 9093123f114Skardel ? "4" 9103123f114Skardel : "6")); 9113123f114Skardel } 9123123f114Skardel delete_interface_from_list(ep); 913abb0f93cSkardel 9143123f114Skardel if (ep->fd != INVALID_SOCKET) { 915abb0f93cSkardel msyslog(LOG_INFO, 916*eabc0478Schristos "Deleting %d %s, [%s]:%hd, stats:" 917*eabc0478Schristos " received=%ld, sent=%ld, dropped=%ld," 918*eabc0478Schristos " active_time=%ld secs", 9193123f114Skardel ep->ifnum, 9203123f114Skardel ep->name, 9213123f114Skardel stoa(&ep->sin), 9223123f114Skardel SRCPORT(&ep->sin), 9233123f114Skardel ep->received, 9243123f114Skardel ep->sent, 9253123f114Skardel ep->notsent, 9263123f114Skardel current_time - ep->starttime); 927*eabc0478Schristos close_and_delete_fd_from_list(ep->fd, ep); 9282950cc38Schristos ep->fd = INVALID_SOCKET; 929abb0f93cSkardel } 930abb0f93cSkardel 9313123f114Skardel if (ep->bfd != INVALID_SOCKET) { 932abb0f93cSkardel msyslog(LOG_INFO, 9332950cc38Schristos "stop listening for broadcasts to %s on interface #%d %s", 9342950cc38Schristos stoa(&ep->bcast), ep->ifnum, ep->name); 935*eabc0478Schristos close_and_delete_fd_from_list(ep->bfd, ep); 9362950cc38Schristos ep->bfd = INVALID_SOCKET; 937abb0f93cSkardel } 93868dbbb44Schristos # ifdef HAVE_IO_COMPLETION_PORT 93968dbbb44Schristos io_completion_port_remove_interface(ep); 94068dbbb44Schristos # endif 941abb0f93cSkardel 942abb0f93cSkardel ninterfaces--; 9432950cc38Schristos mon_clearinterface(ep); 944abb0f93cSkardel 945abb0f93cSkardel /* remove restrict interface entry */ 9463123f114Skardel SET_HOSTMASK(&resmask, AF(&ep->sin)); 947*eabc0478Schristos success = hack_restrict(RESTRICT_REMOVEIF, &ep->sin, &resmask, 0, 948*eabc0478Schristos RESM_NTPONLY | RESM_INTERFACE, 0, 0); 949*eabc0478Schristos if (!success) { 950*eabc0478Schristos msyslog(LOG_ERR, 951*eabc0478Schristos "unable to remove self-restriction for %s", 952*eabc0478Schristos stoa(&ep->sin)); 953*eabc0478Schristos } 954*eabc0478Schristos 955abb0f93cSkardel } 956abb0f93cSkardel 957abb0f93cSkardel 958abb0f93cSkardel static void 9593123f114Skardel log_listen_address( 9603123f114Skardel endpt * ep 961abb0f93cSkardel ) 962abb0f93cSkardel { 9632950cc38Schristos msyslog(LOG_INFO, "%s on %d %s %s", 9643123f114Skardel (ep->ignore_packets) 965abb0f93cSkardel ? "Listen and drop" 966abb0f93cSkardel : "Listen normally", 9673123f114Skardel ep->ifnum, 9683123f114Skardel ep->name, 9692950cc38Schristos sptoa(&ep->sin)); 970abb0f93cSkardel } 971abb0f93cSkardel 972abb0f93cSkardel 973abb0f93cSkardel static void 974abb0f93cSkardel create_wildcards( 975abb0f93cSkardel u_short port 976abb0f93cSkardel ) 977abb0f93cSkardel { 9784ba751f5Skardel int v4wild; 9794ba751f5Skardel #ifdef INCLUDE_IPV6_SUPPORT 9804ba751f5Skardel int v6wild; 9814ba751f5Skardel #endif 982abb0f93cSkardel sockaddr_u wildaddr; 983abb0f93cSkardel nic_rule_action action; 984*eabc0478Schristos endpt * wildif; 985abb0f93cSkardel 986abb0f93cSkardel /* 987abb0f93cSkardel * silence "potentially uninitialized" warnings from VC9 988abb0f93cSkardel * failing to follow the logic. Ideally action could remain 989abb0f93cSkardel * uninitialized, and the memset be the first statement under 990abb0f93cSkardel * the first if (v4wild). 991abb0f93cSkardel */ 992abb0f93cSkardel action = ACTION_LISTEN; 9932950cc38Schristos ZERO(wildaddr); 994abb0f93cSkardel 995abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT 996abb0f93cSkardel /* 997abb0f93cSkardel * create pseudo-interface with wildcard IPv6 address 998abb0f93cSkardel */ 999abb0f93cSkardel v6wild = ipv6_works; 1000abb0f93cSkardel if (v6wild) { 1001abb0f93cSkardel /* set wildaddr to the v6 wildcard address :: */ 10022950cc38Schristos ZERO(wildaddr); 1003abb0f93cSkardel AF(&wildaddr) = AF_INET6; 1004abb0f93cSkardel SET_ADDR6N(&wildaddr, in6addr_any); 1005abb0f93cSkardel SET_PORT(&wildaddr, port); 1006abb0f93cSkardel SET_SCOPE(&wildaddr, 0); 1007abb0f93cSkardel 1008abb0f93cSkardel /* check for interface/nic rules affecting the wildcard */ 10093123f114Skardel action = interface_action(NULL, &wildaddr, 0); 1010abb0f93cSkardel v6wild = (ACTION_IGNORE != action); 1011abb0f93cSkardel } 1012abb0f93cSkardel if (v6wild) { 1013abb0f93cSkardel wildif = new_interface(NULL); 1014abb0f93cSkardel 10152950cc38Schristos strlcpy(wildif->name, "v6wildcard", sizeof(wildif->name)); 1016abb0f93cSkardel memcpy(&wildif->sin, &wildaddr, sizeof(wildif->sin)); 1017abb0f93cSkardel wildif->family = AF_INET6; 1018abb0f93cSkardel AF(&wildif->mask) = AF_INET6; 1019abb0f93cSkardel SET_ONESMASK(&wildif->mask); 1020abb0f93cSkardel 1021abb0f93cSkardel wildif->flags = INT_UP | INT_WILDCARD; 1022abb0f93cSkardel wildif->ignore_packets = (ACTION_DROP == action); 1023abb0f93cSkardel 1024abb0f93cSkardel wildif->fd = open_socket(&wildif->sin, 0, 1, wildif); 1025abb0f93cSkardel 1026abb0f93cSkardel if (wildif->fd != INVALID_SOCKET) { 1027abb0f93cSkardel wildipv6 = wildif; 1028abb0f93cSkardel any6_interface = wildif; 1029abb0f93cSkardel add_addr_to_list(&wildif->sin, wildif); 1030abb0f93cSkardel add_interface(wildif); 10313123f114Skardel log_listen_address(wildif); 1032abb0f93cSkardel } else { 1033abb0f93cSkardel msyslog(LOG_ERR, 1034abb0f93cSkardel "unable to bind to wildcard address %s - another process may be running - EXITING", 1035abb0f93cSkardel stoa(&wildif->sin)); 1036abb0f93cSkardel exit(1); 1037abb0f93cSkardel } 1038abb0f93cSkardel DPRINT_INTERFACE(2, (wildif, "created ", "\n")); 1039abb0f93cSkardel } 1040abb0f93cSkardel #endif 10412950cc38Schristos 10422950cc38Schristos /* 10432950cc38Schristos * create pseudo-interface with wildcard IPv4 address 10442950cc38Schristos */ 10452950cc38Schristos v4wild = ipv4_works; 10462950cc38Schristos if (v4wild) { 10472950cc38Schristos /* set wildaddr to the v4 wildcard address 0.0.0.0 */ 10482950cc38Schristos AF(&wildaddr) = AF_INET; 10492950cc38Schristos SET_ADDR4N(&wildaddr, INADDR_ANY); 10502950cc38Schristos SET_PORT(&wildaddr, port); 10512950cc38Schristos 10522950cc38Schristos /* check for interface/nic rules affecting the wildcard */ 10532950cc38Schristos action = interface_action(NULL, &wildaddr, 0); 10542950cc38Schristos v4wild = (ACTION_IGNORE != action); 10552950cc38Schristos } 10562950cc38Schristos if (v4wild) { 10572950cc38Schristos wildif = new_interface(NULL); 10582950cc38Schristos 10592950cc38Schristos strlcpy(wildif->name, "v4wildcard", sizeof(wildif->name)); 10602950cc38Schristos memcpy(&wildif->sin, &wildaddr, sizeof(wildif->sin)); 10612950cc38Schristos wildif->family = AF_INET; 10622950cc38Schristos AF(&wildif->mask) = AF_INET; 10632950cc38Schristos SET_ONESMASK(&wildif->mask); 10642950cc38Schristos 10652950cc38Schristos wildif->flags = INT_BROADCAST | INT_UP | INT_WILDCARD; 10662950cc38Schristos wildif->ignore_packets = (ACTION_DROP == action); 10672950cc38Schristos #if defined(MCAST) 10682950cc38Schristos /* 10692950cc38Schristos * enable multicast reception on the broadcast socket 10702950cc38Schristos */ 10712950cc38Schristos AF(&wildif->bcast) = AF_INET; 10722950cc38Schristos SET_ADDR4N(&wildif->bcast, INADDR_ANY); 10732950cc38Schristos SET_PORT(&wildif->bcast, port); 10742950cc38Schristos #endif /* MCAST */ 10752950cc38Schristos wildif->fd = open_socket(&wildif->sin, 0, 1, wildif); 10762950cc38Schristos 10772950cc38Schristos if (wildif->fd != INVALID_SOCKET) { 10782950cc38Schristos wildipv4 = wildif; 10792950cc38Schristos any_interface = wildif; 10802950cc38Schristos 10812950cc38Schristos add_addr_to_list(&wildif->sin, wildif); 10822950cc38Schristos add_interface(wildif); 10832950cc38Schristos log_listen_address(wildif); 10842950cc38Schristos } else { 10852950cc38Schristos msyslog(LOG_ERR, 10862950cc38Schristos "unable to bind to wildcard address %s - another process may be running - EXITING", 10872950cc38Schristos stoa(&wildif->sin)); 10882950cc38Schristos exit(1); 10892950cc38Schristos } 10902950cc38Schristos DPRINT_INTERFACE(2, (wildif, "created ", "\n")); 10912950cc38Schristos } 1092abb0f93cSkardel } 1093abb0f93cSkardel 1094abb0f93cSkardel 1095abb0f93cSkardel /* 1096abb0f93cSkardel * add_nic_rule() -- insert a rule entry at the head of nic_rule_list. 1097abb0f93cSkardel */ 1098abb0f93cSkardel void 1099abb0f93cSkardel add_nic_rule( 1100abb0f93cSkardel nic_rule_match match_type, 1101abb0f93cSkardel const char * if_name, /* interface name or numeric address */ 1102abb0f93cSkardel int prefixlen, 1103abb0f93cSkardel nic_rule_action action 1104abb0f93cSkardel ) 1105abb0f93cSkardel { 1106abb0f93cSkardel nic_rule * rule; 1107abb0f93cSkardel isc_boolean_t is_ip; 1108abb0f93cSkardel 11092950cc38Schristos rule = emalloc_zero(sizeof(*rule)); 1110abb0f93cSkardel rule->match_type = match_type; 1111abb0f93cSkardel rule->prefixlen = prefixlen; 1112abb0f93cSkardel rule->action = action; 1113abb0f93cSkardel 1114abb0f93cSkardel if (MATCH_IFNAME == match_type) { 1115af12ab5eSchristos REQUIRE(NULL != if_name); 1116abb0f93cSkardel rule->if_name = estrdup(if_name); 1117abb0f93cSkardel } else if (MATCH_IFADDR == match_type) { 1118af12ab5eSchristos REQUIRE(NULL != if_name); 11193123f114Skardel /* set rule->addr */ 11202950cc38Schristos is_ip = is_ip_address(if_name, AF_UNSPEC, &rule->addr); 1121af12ab5eSchristos REQUIRE(is_ip); 1122abb0f93cSkardel } else 1123af12ab5eSchristos REQUIRE(NULL == if_name); 1124abb0f93cSkardel 1125abb0f93cSkardel LINK_SLIST(nic_rule_list, rule, next); 1126abb0f93cSkardel } 1127abb0f93cSkardel 1128abb0f93cSkardel 1129abb0f93cSkardel #ifdef DEBUG 1130abb0f93cSkardel static const char * 1131abb0f93cSkardel action_text( 1132abb0f93cSkardel nic_rule_action action 1133abb0f93cSkardel ) 1134abb0f93cSkardel { 1135abb0f93cSkardel const char *t; 1136abb0f93cSkardel 1137abb0f93cSkardel switch (action) { 1138abb0f93cSkardel 1139abb0f93cSkardel default: 1140abb0f93cSkardel t = "ERROR"; /* quiet uninit warning */ 1141abb0f93cSkardel DPRINTF(1, ("fatal: unknown nic_rule_action %d\n", 1142abb0f93cSkardel action)); 1143af12ab5eSchristos ENSURE(0); 1144abb0f93cSkardel break; 1145abb0f93cSkardel 1146abb0f93cSkardel case ACTION_LISTEN: 1147abb0f93cSkardel t = "listen"; 1148abb0f93cSkardel break; 1149abb0f93cSkardel 1150abb0f93cSkardel case ACTION_IGNORE: 1151abb0f93cSkardel t = "ignore"; 1152abb0f93cSkardel break; 1153abb0f93cSkardel 1154abb0f93cSkardel case ACTION_DROP: 1155abb0f93cSkardel t = "drop"; 1156abb0f93cSkardel break; 1157abb0f93cSkardel } 1158abb0f93cSkardel 1159abb0f93cSkardel return t; 1160abb0f93cSkardel } 1161abb0f93cSkardel #endif /* DEBUG */ 1162abb0f93cSkardel 1163abb0f93cSkardel 1164abb0f93cSkardel static nic_rule_action 1165abb0f93cSkardel interface_action( 1166abb0f93cSkardel char * if_name, 11673123f114Skardel sockaddr_u * if_addr, 11683123f114Skardel u_int32 if_flags 1169abb0f93cSkardel ) 1170abb0f93cSkardel { 1171abb0f93cSkardel nic_rule * rule; 1172abb0f93cSkardel int isloopback; 1173abb0f93cSkardel int iswildcard; 1174abb0f93cSkardel 11752950cc38Schristos DPRINTF(4, ("interface_action: interface %s ", 11762950cc38Schristos (if_name != NULL) ? if_name : "wildcard")); 1177abb0f93cSkardel 11783123f114Skardel iswildcard = is_wildcard_addr(if_addr); 11792950cc38Schristos isloopback = !!(INT_LOOPBACK & if_flags); 1180abb0f93cSkardel 1181abb0f93cSkardel /* 1182abb0f93cSkardel * Find any matching NIC rule from --interface / -I or ntp.conf 1183abb0f93cSkardel * interface/nic rules. 1184abb0f93cSkardel */ 1185abb0f93cSkardel for (rule = nic_rule_list; rule != NULL; rule = rule->next) { 1186abb0f93cSkardel 1187abb0f93cSkardel switch (rule->match_type) { 1188abb0f93cSkardel 1189abb0f93cSkardel case MATCH_ALL: 1190abb0f93cSkardel /* loopback and wildcard excluded from "all" */ 1191abb0f93cSkardel if (isloopback || iswildcard) 1192abb0f93cSkardel break; 1193abb0f93cSkardel DPRINTF(4, ("nic all %s\n", 1194abb0f93cSkardel action_text(rule->action))); 1195abb0f93cSkardel return rule->action; 1196abb0f93cSkardel 1197abb0f93cSkardel case MATCH_IPV4: 11983123f114Skardel if (IS_IPV4(if_addr)) { 1199abb0f93cSkardel DPRINTF(4, ("nic ipv4 %s\n", 1200abb0f93cSkardel action_text(rule->action))); 1201abb0f93cSkardel return rule->action; 1202abb0f93cSkardel } 1203abb0f93cSkardel break; 1204abb0f93cSkardel 1205abb0f93cSkardel case MATCH_IPV6: 12063123f114Skardel if (IS_IPV6(if_addr)) { 1207abb0f93cSkardel DPRINTF(4, ("nic ipv6 %s\n", 1208abb0f93cSkardel action_text(rule->action))); 1209abb0f93cSkardel return rule->action; 1210abb0f93cSkardel } 1211abb0f93cSkardel break; 1212abb0f93cSkardel 1213abb0f93cSkardel case MATCH_WILDCARD: 1214abb0f93cSkardel if (iswildcard) { 1215abb0f93cSkardel DPRINTF(4, ("nic wildcard %s\n", 1216abb0f93cSkardel action_text(rule->action))); 1217abb0f93cSkardel return rule->action; 1218abb0f93cSkardel } 1219abb0f93cSkardel break; 1220abb0f93cSkardel 1221abb0f93cSkardel case MATCH_IFADDR: 1222abb0f93cSkardel if (rule->prefixlen != -1) { 12233123f114Skardel if (addr_eqprefix(if_addr, &rule->addr, 12243123f114Skardel rule->prefixlen)) { 1225abb0f93cSkardel 1226abb0f93cSkardel DPRINTF(4, ("subnet address match - %s\n", 1227abb0f93cSkardel action_text(rule->action))); 1228abb0f93cSkardel return rule->action; 1229abb0f93cSkardel } 1230abb0f93cSkardel } else 12313123f114Skardel if (SOCK_EQ(if_addr, &rule->addr)) { 1232abb0f93cSkardel 1233abb0f93cSkardel DPRINTF(4, ("address match - %s\n", 1234abb0f93cSkardel action_text(rule->action))); 1235abb0f93cSkardel return rule->action; 1236abb0f93cSkardel } 1237abb0f93cSkardel break; 1238abb0f93cSkardel 1239abb0f93cSkardel case MATCH_IFNAME: 1240abb0f93cSkardel if (if_name != NULL 1241ea66d795Schristos #if defined(HAVE_FNMATCH) && defined(FNM_CASEFOLD) 1242ea66d795Schristos && !fnmatch(rule->if_name, if_name, FNM_CASEFOLD) 1243ea66d795Schristos #else 1244ea66d795Schristos && !strcasecmp(if_name, rule->if_name) 1245ea66d795Schristos #endif 1246ea66d795Schristos ) { 1247abb0f93cSkardel 1248abb0f93cSkardel DPRINTF(4, ("interface name match - %s\n", 1249abb0f93cSkardel action_text(rule->action))); 1250abb0f93cSkardel return rule->action; 1251abb0f93cSkardel } 1252abb0f93cSkardel break; 1253abb0f93cSkardel } 1254abb0f93cSkardel } 1255abb0f93cSkardel 1256abb0f93cSkardel /* 1257abb0f93cSkardel * Unless explicitly disabled such as with "nic ignore ::1" 1258abb0f93cSkardel * listen on loopback addresses. Since ntpq and ntpdc query 1259abb0f93cSkardel * "localhost" by default, which typically resolves to ::1 and 1260abb0f93cSkardel * 127.0.0.1, it's useful to default to listening on both. 1261abb0f93cSkardel */ 1262abb0f93cSkardel if (isloopback) { 1263abb0f93cSkardel DPRINTF(4, ("default loopback listen\n")); 1264abb0f93cSkardel return ACTION_LISTEN; 1265abb0f93cSkardel } 1266abb0f93cSkardel 1267abb0f93cSkardel /* 1268abb0f93cSkardel * Treat wildcard addresses specially. If there is no explicit 1269abb0f93cSkardel * "nic ... wildcard" or "nic ... 0.0.0.0" or "nic ... ::" rule 1270abb0f93cSkardel * default to drop. 1271abb0f93cSkardel */ 1272abb0f93cSkardel if (iswildcard) { 1273abb0f93cSkardel DPRINTF(4, ("default wildcard drop\n")); 1274abb0f93cSkardel return ACTION_DROP; 1275abb0f93cSkardel } 1276abb0f93cSkardel 1277abb0f93cSkardel /* 1278abb0f93cSkardel * Check for "virtual IP" (colon in the interface name) after 1279abb0f93cSkardel * the rules so that "ntpd --interface eth0:1 -novirtualips" 1280abb0f93cSkardel * does indeed listen on eth0:1's addresses. 1281abb0f93cSkardel */ 1282abb0f93cSkardel if (!listen_to_virtual_ips && if_name != NULL 1283abb0f93cSkardel && (strchr(if_name, ':') != NULL)) { 1284abb0f93cSkardel 1285abb0f93cSkardel DPRINTF(4, ("virtual ip - ignore\n")); 1286abb0f93cSkardel return ACTION_IGNORE; 1287abb0f93cSkardel } 1288abb0f93cSkardel 1289abb0f93cSkardel /* 1290abb0f93cSkardel * If there are no --interface/-I command-line options and no 1291abb0f93cSkardel * interface/nic rules in ntp.conf, the default action is to 1292abb0f93cSkardel * listen. In the presence of rules from either, the default 1293abb0f93cSkardel * is to ignore. This implements ntpd's traditional listen- 1294abb0f93cSkardel * every default with no interface listen configuration, and 1295abb0f93cSkardel * ensures a single -I eth0 or "nic listen eth0" means do not 1296abb0f93cSkardel * listen on any other addresses. 1297abb0f93cSkardel */ 1298abb0f93cSkardel if (NULL == nic_rule_list) { 1299abb0f93cSkardel DPRINTF(4, ("default listen\n")); 1300abb0f93cSkardel return ACTION_LISTEN; 1301abb0f93cSkardel } 1302abb0f93cSkardel 1303abb0f93cSkardel DPRINTF(4, ("implicit ignore\n")); 1304abb0f93cSkardel return ACTION_IGNORE; 1305abb0f93cSkardel } 1306abb0f93cSkardel 1307abb0f93cSkardel 1308abb0f93cSkardel static void 1309abb0f93cSkardel convert_isc_if( 1310abb0f93cSkardel isc_interface_t *isc_if, 13113123f114Skardel endpt *itf, 1312abb0f93cSkardel u_short port 1313abb0f93cSkardel ) 1314abb0f93cSkardel { 13152950cc38Schristos strlcpy(itf->name, isc_if->name, sizeof(itf->name)); 13163123f114Skardel itf->ifindex = isc_if->ifindex; 1317abb0f93cSkardel itf->family = (u_short)isc_if->af; 1318abb0f93cSkardel AF(&itf->sin) = itf->family; 1319abb0f93cSkardel AF(&itf->mask) = itf->family; 1320abb0f93cSkardel AF(&itf->bcast) = itf->family; 1321abb0f93cSkardel SET_PORT(&itf->sin, port); 1322abb0f93cSkardel SET_PORT(&itf->mask, port); 1323abb0f93cSkardel SET_PORT(&itf->bcast, port); 1324abb0f93cSkardel 1325abb0f93cSkardel if (IS_IPV4(&itf->sin)) { 1326abb0f93cSkardel NSRCADR(&itf->sin) = isc_if->address.type.in.s_addr; 1327abb0f93cSkardel NSRCADR(&itf->mask) = isc_if->netmask.type.in.s_addr; 1328abb0f93cSkardel 1329abb0f93cSkardel if (isc_if->flags & INTERFACE_F_BROADCAST) { 1330abb0f93cSkardel itf->flags |= INT_BROADCAST; 1331abb0f93cSkardel NSRCADR(&itf->bcast) = 1332abb0f93cSkardel isc_if->broadcast.type.in.s_addr; 1333abb0f93cSkardel } 1334abb0f93cSkardel } 1335abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT 1336abb0f93cSkardel else if (IS_IPV6(&itf->sin)) { 1337abb0f93cSkardel SET_ADDR6N(&itf->sin, isc_if->address.type.in6); 1338abb0f93cSkardel SET_ADDR6N(&itf->mask, isc_if->netmask.type.in6); 1339abb0f93cSkardel 13403123f114Skardel SET_SCOPE(&itf->sin, isc_if->address.zone); 1341abb0f93cSkardel } 1342abb0f93cSkardel #endif /* INCLUDE_IPV6_SUPPORT */ 1343abb0f93cSkardel 1344abb0f93cSkardel 1345abb0f93cSkardel /* Process the rest of the flags */ 1346abb0f93cSkardel 1347abb0f93cSkardel itf->flags |= 1348abb0f93cSkardel ((INTERFACE_F_UP & isc_if->flags) 1349abb0f93cSkardel ? INT_UP : 0) 1350abb0f93cSkardel | ((INTERFACE_F_LOOPBACK & isc_if->flags) 1351abb0f93cSkardel ? INT_LOOPBACK : 0) 1352abb0f93cSkardel | ((INTERFACE_F_POINTTOPOINT & isc_if->flags) 1353abb0f93cSkardel ? INT_PPP : 0) 1354abb0f93cSkardel | ((INTERFACE_F_MULTICAST & isc_if->flags) 1355abb0f93cSkardel ? INT_MULTICAST : 0) 13563123f114Skardel | ((INTERFACE_F_PRIVACY & isc_if->flags) 13573123f114Skardel ? INT_PRIVACY : 0) 1358abb0f93cSkardel ; 13593123f114Skardel 13603123f114Skardel /* 13613123f114Skardel * Clear the loopback flag if the address is not localhost. 13623123f114Skardel * http://bugs.ntp.org/1683 13633123f114Skardel */ 1364*eabc0478Schristos if ((INT_LOOPBACK & itf->flags) && !IS_LOOPBACK_ADDR(&itf->sin)) { 13653123f114Skardel itf->flags &= ~INT_LOOPBACK; 13663123f114Skardel } 1367abb0f93cSkardel } 1368abb0f93cSkardel 1369abb0f93cSkardel 1370abb0f93cSkardel /* 1371abb0f93cSkardel * refresh_interface 1372abb0f93cSkardel * 1373abb0f93cSkardel * some OSes have been observed to keep 1374abb0f93cSkardel * cached routes even when more specific routes 1375abb0f93cSkardel * become available. 1376abb0f93cSkardel * this can be mitigated by re-binding 1377abb0f93cSkardel * the socket. 1378abb0f93cSkardel */ 1379abb0f93cSkardel static int 1380abb0f93cSkardel refresh_interface( 1381*eabc0478Schristos endpt * iface 1382abb0f93cSkardel ) 1383abb0f93cSkardel { 1384abb0f93cSkardel #ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES 1385*eabc0478Schristos if (iface->fd != INVALID_SOCKET) { 1386*eabc0478Schristos int bcast = (iface->flags & INT_BCASTXMIT) != 0; 13872950cc38Schristos /* as we forcibly close() the socket remove the 13882950cc38Schristos broadcast permission indication */ 13892950cc38Schristos if (bcast) 1390*eabc0478Schristos socket_broadcast_disable(iface, &iface->sin); 13912950cc38Schristos 1392*eabc0478Schristos close_and_delete_fd_from_list(iface->fd, iface); 13932950cc38Schristos 13942950cc38Schristos /* create new socket picking up a new first hop binding 13952950cc38Schristos at connect() time */ 1396*eabc0478Schristos iface->fd = open_socket(&iface->sin, 1397*eabc0478Schristos bcast, 0, iface); 1398abb0f93cSkardel /* 1399abb0f93cSkardel * reset TTL indication so TTL is is set again 1400abb0f93cSkardel * next time around 1401abb0f93cSkardel */ 1402*eabc0478Schristos iface->last_ttl = 0; 1403*eabc0478Schristos return (iface->fd != INVALID_SOCKET); 1404abb0f93cSkardel } else 1405abb0f93cSkardel return 0; /* invalid sockets are not refreshable */ 1406abb0f93cSkardel #else /* !OS_MISSES_SPECIFIC_ROUTE_UPDATES */ 1407*eabc0478Schristos return (iface->fd != INVALID_SOCKET); 1408abb0f93cSkardel #endif /* !OS_MISSES_SPECIFIC_ROUTE_UPDATES */ 1409abb0f93cSkardel } 1410abb0f93cSkardel 1411abb0f93cSkardel /* 1412abb0f93cSkardel * interface_update - externally callable update function 1413abb0f93cSkardel */ 1414abb0f93cSkardel void 1415abb0f93cSkardel interface_update( 1416abb0f93cSkardel interface_receiver_t receiver, 1417*eabc0478Schristos void * data 1418*eabc0478Schristos ) 1419abb0f93cSkardel { 1420abb0f93cSkardel int new_interface_found; 1421abb0f93cSkardel 1422*eabc0478Schristos if (scan_addrs_once) { 1423abb0f93cSkardel return; 1424*eabc0478Schristos } 1425abb0f93cSkardel BLOCKIO(); 1426abb0f93cSkardel new_interface_found = update_interfaces(NTP_PORT, receiver, data); 1427abb0f93cSkardel UNBLOCKIO(); 1428abb0f93cSkardel 1429*eabc0478Schristos if (!new_interface_found) { 1430abb0f93cSkardel return; 1431*eabc0478Schristos } 1432abb0f93cSkardel #ifdef DEBUG 1433abb0f93cSkardel msyslog(LOG_DEBUG, "new interface(s) found: waking up resolver"); 1434abb0f93cSkardel #endif 14352950cc38Schristos interrupt_worker_sleep(); 1436abb0f93cSkardel } 1437abb0f93cSkardel 1438abb0f93cSkardel 1439abb0f93cSkardel /* 1440abb0f93cSkardel * sau_from_netaddr() - convert network address on-wire formats. 1441abb0f93cSkardel * Convert from libisc's isc_netaddr_t to NTP's sockaddr_u 1442abb0f93cSkardel */ 1443abb0f93cSkardel void 1444abb0f93cSkardel sau_from_netaddr( 1445abb0f93cSkardel sockaddr_u *psau, 1446abb0f93cSkardel const isc_netaddr_t *pna 1447abb0f93cSkardel ) 1448abb0f93cSkardel { 14492950cc38Schristos ZERO_SOCK(psau); 1450abb0f93cSkardel AF(psau) = (u_short)pna->family; 1451abb0f93cSkardel switch (pna->family) { 1452abb0f93cSkardel 1453abb0f93cSkardel case AF_INET: 1454*eabc0478Schristos psau->sa4.sin_addr = pna->type.in; 1455abb0f93cSkardel break; 1456abb0f93cSkardel 1457abb0f93cSkardel case AF_INET6: 1458*eabc0478Schristos psau->sa6.sin6_addr = pna->type.in6; 1459abb0f93cSkardel break; 1460abb0f93cSkardel } 1461abb0f93cSkardel } 1462abb0f93cSkardel 1463abb0f93cSkardel 1464abb0f93cSkardel static int 1465abb0f93cSkardel is_wildcard_addr( 14663123f114Skardel const sockaddr_u *psau 1467abb0f93cSkardel ) 1468abb0f93cSkardel { 1469abb0f93cSkardel if (IS_IPV4(psau) && !NSRCADR(psau)) 1470abb0f93cSkardel return 1; 1471abb0f93cSkardel 1472abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT 1473abb0f93cSkardel if (IS_IPV6(psau) && S_ADDR6_EQ(psau, &in6addr_any)) 1474abb0f93cSkardel return 1; 1475abb0f93cSkardel #endif 1476abb0f93cSkardel 1477abb0f93cSkardel return 0; 1478abb0f93cSkardel } 1479abb0f93cSkardel 1480abb0f93cSkardel 1481*eabc0478Schristos isc_boolean_t 1482*eabc0478Schristos is_linklocal( 1483*eabc0478Schristos sockaddr_u * psau 1484*eabc0478Schristos ) 1485*eabc0478Schristos { 1486*eabc0478Schristos struct in6_addr * p6addr; 1487*eabc0478Schristos 1488*eabc0478Schristos if (IS_IPV6(psau)) { 1489*eabc0478Schristos p6addr = &psau->sa6.sin6_addr; 1490*eabc0478Schristos if ( IN6_IS_ADDR_LINKLOCAL(p6addr) 1491*eabc0478Schristos || IN6_IS_ADDR_SITELOCAL(p6addr)) { 1492*eabc0478Schristos 1493*eabc0478Schristos return TRUE; 1494*eabc0478Schristos } 1495*eabc0478Schristos } else if (IS_IPV4(psau)) { 1496*eabc0478Schristos /* autoconf are link-local 169.254.0.0/16 */ 1497*eabc0478Schristos if (IS_AUTOCONF(psau)) { 1498*eabc0478Schristos return TRUE; 1499*eabc0478Schristos } 1500*eabc0478Schristos } 1501*eabc0478Schristos return FALSE; 1502*eabc0478Schristos } 1503*eabc0478Schristos 1504*eabc0478Schristos 1505abb0f93cSkardel #ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND 1506abb0f93cSkardel /* 1507abb0f93cSkardel * enable/disable re-use of wildcard address socket 1508abb0f93cSkardel */ 1509abb0f93cSkardel static void 1510abb0f93cSkardel set_wildcard_reuse( 1511abb0f93cSkardel u_short family, 1512abb0f93cSkardel int on 1513abb0f93cSkardel ) 1514abb0f93cSkardel { 1515*eabc0478Schristos endpt *any; 1516abb0f93cSkardel SOCKET fd = INVALID_SOCKET; 1517abb0f93cSkardel 1518abb0f93cSkardel any = ANY_INTERFACE_BYFAM(family); 1519abb0f93cSkardel if (any != NULL) 1520abb0f93cSkardel fd = any->fd; 1521abb0f93cSkardel 1522abb0f93cSkardel if (fd != INVALID_SOCKET) { 1523abb0f93cSkardel if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 15244eea345dSchristos (void *)&on, sizeof(on))) 1525abb0f93cSkardel msyslog(LOG_ERR, 1526abb0f93cSkardel "set_wildcard_reuse: setsockopt(SO_REUSEADDR, %s) failed: %m", 1527abb0f93cSkardel on ? "on" : "off"); 1528abb0f93cSkardel 1529abb0f93cSkardel DPRINTF(4, ("set SO_REUSEADDR to %s on %s\n", 1530abb0f93cSkardel on ? "on" : "off", 1531abb0f93cSkardel stoa(&any->sin))); 1532abb0f93cSkardel } 1533abb0f93cSkardel } 1534abb0f93cSkardel #endif /* OS_NEEDS_REUSEADDR_FOR_IFADDRBIND */ 1535abb0f93cSkardel 1536fc8c6761Sroy static isc_boolean_t 1537fc8c6761Sroy check_flags( 1538fc8c6761Sroy sockaddr_u *psau, 1539fc8c6761Sroy const char *name, 1540fc8c6761Sroy u_int32 flags 1541fc8c6761Sroy ) 1542fc8c6761Sroy { 1543fc8c6761Sroy #if defined(SIOCGIFAFLAG_IN) 1544fc8c6761Sroy struct ifreq ifr; 1545fc8c6761Sroy int fd; 1546fc8c6761Sroy 1547fc8c6761Sroy if (psau->sa.sa_family != AF_INET) 1548fc8c6761Sroy return ISC_FALSE; 1549fc8c6761Sroy if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1550fc8c6761Sroy return ISC_FALSE; 1551fc8c6761Sroy ZERO(ifr); 1552fc8c6761Sroy memcpy(&ifr.ifr_addr, &psau->sa, sizeof(ifr.ifr_addr)); 1553fc8c6761Sroy strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1554fc8c6761Sroy if (ioctl(fd, SIOCGIFAFLAG_IN, &ifr) < 0) { 1555fc8c6761Sroy close(fd); 1556fc8c6761Sroy return ISC_FALSE; 1557fc8c6761Sroy } 1558fc8c6761Sroy close(fd); 1559fc8c6761Sroy if ((ifr.ifr_addrflags & flags) != 0) 1560fc8c6761Sroy return ISC_TRUE; 1561fc8c6761Sroy #endif /* SIOCGIFAFLAG_IN */ 1562fc8c6761Sroy return ISC_FALSE; 1563fc8c6761Sroy } 15643123f114Skardel 15653123f114Skardel static isc_boolean_t 15669a2df3ffSroy check_flags6( 15673123f114Skardel sockaddr_u *psau, 15689a2df3ffSroy const char *name, 15699a2df3ffSroy u_int32 flags6 15703123f114Skardel ) 15713123f114Skardel { 15729a2df3ffSroy #if defined(INCLUDE_IPV6_SUPPORT) && defined(SIOCGIFAFLAG_IN6) 15733123f114Skardel struct in6_ifreq ifr6; 15743123f114Skardel int fd; 15753123f114Skardel 15763123f114Skardel if (psau->sa.sa_family != AF_INET6) 15773123f114Skardel return ISC_FALSE; 15783123f114Skardel if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 15793123f114Skardel return ISC_FALSE; 15802950cc38Schristos ZERO(ifr6); 15813123f114Skardel memcpy(&ifr6.ifr_addr, &psau->sa6, sizeof(ifr6.ifr_addr)); 15822950cc38Schristos strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); 15833123f114Skardel if (ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) < 0) { 15843123f114Skardel close(fd); 15853123f114Skardel return ISC_FALSE; 15863123f114Skardel } 15873123f114Skardel close(fd); 15889a2df3ffSroy if ((ifr6.ifr_ifru.ifru_flags6 & flags6) != 0) 15893123f114Skardel return ISC_TRUE; 15909a2df3ffSroy #endif /* INCLUDE_IPV6_SUPPORT && SIOCGIFAFLAG_IN6 */ 15913123f114Skardel return ISC_FALSE; 15923123f114Skardel } 15933123f114Skardel 15949a2df3ffSroy static isc_boolean_t 15959a2df3ffSroy is_anycast( 15969a2df3ffSroy sockaddr_u *psau, 15979a2df3ffSroy const char *name 15989a2df3ffSroy ) 15999a2df3ffSroy { 16009a2df3ffSroy #ifdef IN6_IFF_ANYCAST 16019a2df3ffSroy return check_flags6(psau, name, IN6_IFF_ANYCAST); 16029a2df3ffSroy #else 16039a2df3ffSroy return ISC_FALSE; 16049a2df3ffSroy #endif 16059a2df3ffSroy } 16069a2df3ffSroy 16079a2df3ffSroy static isc_boolean_t 16089a2df3ffSroy is_valid( 16099a2df3ffSroy sockaddr_u *psau, 16109a2df3ffSroy const char *name 16119a2df3ffSroy ) 16129a2df3ffSroy { 1613fc8c6761Sroy u_int32 flags; 16149a2df3ffSroy 1615fc8c6761Sroy flags = 0; 1616fc8c6761Sroy switch (psau->sa.sa_family) { 1617fc8c6761Sroy case AF_INET: 1618fc8c6761Sroy #ifdef IN_IFF_DETACHED 1619fc8c6761Sroy flags |= IN_IFF_DETACHED; 1620fc8c6761Sroy #endif 1621fc8c6761Sroy #ifdef IN_IFF_TENTATIVE 1622fc8c6761Sroy flags |= IN_IFF_TENTATIVE; 1623fc8c6761Sroy #endif 1624fc8c6761Sroy return check_flags(psau, name, flags) ? ISC_FALSE : ISC_TRUE; 1625fc8c6761Sroy case AF_INET6: 16269a2df3ffSroy #ifdef IN6_IFF_DEPARTED 1627fc8c6761Sroy flags |= IN6_IFF_DEPARTED; 16289a2df3ffSroy #endif 16299a2df3ffSroy #ifdef IN6_IFF_DETACHED 1630fc8c6761Sroy flags |= IN6_IFF_DETACHED; 16319a2df3ffSroy #endif 16329a2df3ffSroy #ifdef IN6_IFF_TENTATIVE 1633fc8c6761Sroy flags |= IN6_IFF_TENTATIVE; 16349a2df3ffSroy #endif 1635fc8c6761Sroy return check_flags6(psau, name, flags) ? ISC_FALSE : ISC_TRUE; 1636fc8c6761Sroy default: 1637fc8c6761Sroy return ISC_FALSE; 1638fc8c6761Sroy } 16399a2df3ffSroy } 16403123f114Skardel 1641abb0f93cSkardel /* 1642abb0f93cSkardel * update_interface strategy 1643abb0f93cSkardel * 1644abb0f93cSkardel * toggle configuration phase 1645abb0f93cSkardel * 1646*eabc0478Schristos * Phase 1a: 1647abb0f93cSkardel * forall currently existing interfaces 1648abb0f93cSkardel * if address is known: 1649abb0f93cSkardel * drop socket - rebind again 1650abb0f93cSkardel * 1651abb0f93cSkardel * if address is NOT known: 1652*eabc0478Schristos * Add address to list of new addresses 1653*eabc0478Schristos * 1654*eabc0478Schristos * Phase 1b: 1655*eabc0478Schristos * Scan the list of new addresses marking IPv6 link-local addresses 1656*eabc0478Schristos * which also have a global v6 address using the same OS ifindex. 1657*eabc0478Schristos * Attempt to create a new interface entry 1658abb0f93cSkardel * 1659abb0f93cSkardel * Phase 2: 1660abb0f93cSkardel * forall currently known non MCAST and WILDCARD interfaces 1661abb0f93cSkardel * if interface does not match configuration phase (not seen in phase 1): 1662abb0f93cSkardel * remove interface from known interface list 1663abb0f93cSkardel * forall peers associated with this interface 1664abb0f93cSkardel * disconnect peer from this interface 1665abb0f93cSkardel * 1666abb0f93cSkardel * Phase 3: 1667abb0f93cSkardel * attempt to re-assign interfaces to peers 1668abb0f93cSkardel * 1669abb0f93cSkardel */ 1670abb0f93cSkardel 1671abb0f93cSkardel static int 1672abb0f93cSkardel update_interfaces( 1673abb0f93cSkardel u_short port, 1674abb0f93cSkardel interface_receiver_t receiver, 1675abb0f93cSkardel void * data 1676abb0f93cSkardel ) 1677abb0f93cSkardel { 1678abb0f93cSkardel isc_mem_t * mctx = (void *)-1; 1679abb0f93cSkardel interface_info_t ifi; 1680abb0f93cSkardel isc_interfaceiter_t * iter; 1681abb0f93cSkardel isc_result_t result; 1682abb0f93cSkardel isc_interface_t isc_if; 1683abb0f93cSkardel int new_interface_found; 1684abb0f93cSkardel unsigned int family; 16853123f114Skardel endpt enumep; 16863123f114Skardel endpt * ep; 16873123f114Skardel endpt * next_ep; 1688*eabc0478Schristos endpt * newaddrs; 1689*eabc0478Schristos endpt * newaddrs_tail; 1690*eabc0478Schristos endpt * ep2; 1691abb0f93cSkardel 1692abb0f93cSkardel DPRINTF(3, ("update_interfaces(%d)\n", port)); 1693abb0f93cSkardel 1694abb0f93cSkardel /* 1695*eabc0478Schristos * phase 1a - scan OS local addresses 1696*eabc0478Schristos * - update those that ntpd already knows 1697*eabc0478Schristos * - build a list of newly-discovered addresses. 1698abb0f93cSkardel */ 1699abb0f93cSkardel 17003123f114Skardel new_interface_found = FALSE; 1701*eabc0478Schristos nonlocal_v4_addr_up = nonlocal_v6_addr_up = FALSE; 1702abb0f93cSkardel iter = NULL; 1703*eabc0478Schristos newaddrs = newaddrs_tail = NULL; 1704abb0f93cSkardel result = isc_interfaceiter_create(mctx, &iter); 1705abb0f93cSkardel 1706abb0f93cSkardel if (result != ISC_R_SUCCESS) 1707abb0f93cSkardel return 0; 1708abb0f93cSkardel 1709abb0f93cSkardel /* 1710abb0f93cSkardel * Toggle system interface scan phase to find untouched 1711abb0f93cSkardel * interfaces to be deleted. 1712abb0f93cSkardel */ 1713abb0f93cSkardel sys_interphase ^= 0x1; 1714abb0f93cSkardel 1715abb0f93cSkardel for (result = isc_interfaceiter_first(iter); 1716abb0f93cSkardel ISC_R_SUCCESS == result; 1717abb0f93cSkardel result = isc_interfaceiter_next(iter)) { 1718abb0f93cSkardel 1719abb0f93cSkardel result = isc_interfaceiter_current(iter, &isc_if); 1720abb0f93cSkardel 1721*eabc0478Schristos if (result != ISC_R_SUCCESS) { 1722abb0f93cSkardel break; 1723*eabc0478Schristos } 1724abb0f93cSkardel /* See if we have a valid family to use */ 1725abb0f93cSkardel family = isc_if.address.family; 1726abb0f93cSkardel if (AF_INET != family && AF_INET6 != family) 1727abb0f93cSkardel continue; 1728abb0f93cSkardel if (AF_INET == family && !ipv4_works) 1729abb0f93cSkardel continue; 1730abb0f93cSkardel if (AF_INET6 == family && !ipv6_works) 1731abb0f93cSkardel continue; 1732abb0f93cSkardel 1733abb0f93cSkardel /* create prototype */ 17343123f114Skardel init_interface(&enumep); 1735abb0f93cSkardel 17363123f114Skardel convert_isc_if(&isc_if, &enumep, port); 1737abb0f93cSkardel 17382950cc38Schristos DPRINT_INTERFACE(4, (&enumep, "examining ", "\n")); 17392950cc38Schristos 1740abb0f93cSkardel /* 1741abb0f93cSkardel * Check if and how we are going to use the interface. 1742abb0f93cSkardel */ 17433123f114Skardel switch (interface_action(enumep.name, &enumep.sin, 17443123f114Skardel enumep.flags)) { 1745abb0f93cSkardel 1746abb0f93cSkardel case ACTION_IGNORE: 17472950cc38Schristos DPRINTF(4, ("ignoring interface %s (%s) - by nic rules\n", 17482950cc38Schristos enumep.name, stoa(&enumep.sin))); 1749abb0f93cSkardel continue; 1750abb0f93cSkardel 1751abb0f93cSkardel case ACTION_LISTEN: 17522950cc38Schristos DPRINTF(4, ("listen interface %s (%s) - by nic rules\n", 17532950cc38Schristos enumep.name, stoa(&enumep.sin))); 17543123f114Skardel enumep.ignore_packets = ISC_FALSE; 1755abb0f93cSkardel break; 1756abb0f93cSkardel 1757abb0f93cSkardel case ACTION_DROP: 17582950cc38Schristos DPRINTF(4, ("drop on interface %s (%s) - by nic rules\n", 17592950cc38Schristos enumep.name, stoa(&enumep.sin))); 17603123f114Skardel enumep.ignore_packets = ISC_TRUE; 1761abb0f93cSkardel break; 1762abb0f93cSkardel } 1763abb0f93cSkardel 1764abb0f93cSkardel /* interfaces must be UP to be usable */ 17653123f114Skardel if (!(enumep.flags & INT_UP)) { 1766abb0f93cSkardel DPRINTF(4, ("skipping interface %s (%s) - DOWN\n", 17673123f114Skardel enumep.name, stoa(&enumep.sin))); 1768abb0f93cSkardel continue; 1769abb0f93cSkardel } 1770abb0f93cSkardel 1771abb0f93cSkardel /* 1772abb0f93cSkardel * skip any interfaces UP and bound to a wildcard 1773abb0f93cSkardel * address - some dhcp clients produce that in the 1774abb0f93cSkardel * wild 1775abb0f93cSkardel */ 17763123f114Skardel if (is_wildcard_addr(&enumep.sin)) 17773123f114Skardel continue; 17783123f114Skardel 17793123f114Skardel if (is_anycast(&enumep.sin, isc_if.name)) 1780abb0f93cSkardel continue; 1781abb0f93cSkardel 1782abb0f93cSkardel /* 17839a2df3ffSroy * skip any address that is an invalid state to be used 17849a2df3ffSroy */ 17859a2df3ffSroy if (!is_valid(&enumep.sin, isc_if.name)) 17869a2df3ffSroy continue; 17879a2df3ffSroy 17889a2df3ffSroy /* 1789*eabc0478Schristos * Keep track of having non-linklocal connectivity 1790*eabc0478Schristos * for IPv4 and IPv6 so we don't solicit pool hosts 1791*eabc0478Schristos * when it can't work. 1792*eabc0478Schristos */ 1793*eabc0478Schristos if ( !(INT_LOOPBACK & enumep.flags) 1794*eabc0478Schristos && !is_linklocal(&enumep.sin)) { 1795*eabc0478Schristos if (IS_IPV6(&enumep.sin)) { 1796*eabc0478Schristos nonlocal_v6_addr_up = TRUE; 1797*eabc0478Schristos } else { 1798*eabc0478Schristos nonlocal_v4_addr_up = TRUE; 1799*eabc0478Schristos } 1800*eabc0478Schristos } 1801*eabc0478Schristos /* 1802abb0f93cSkardel * map to local *address* in order to map all duplicate 18033123f114Skardel * interfaces to an endpt structure with the appropriate 18043123f114Skardel * socket. Our name space is (ip-address), NOT 18053123f114Skardel * (interface name, ip-address). 1806abb0f93cSkardel */ 18073123f114Skardel ep = getinterface(&enumep.sin, INT_WILDCARD); 1808abb0f93cSkardel 1809*eabc0478Schristos if (NULL == ep) { 1810*eabc0478Schristos ep = emalloc(sizeof(*ep)); 1811*eabc0478Schristos memcpy(ep, &enumep, sizeof(*ep)); 1812*eabc0478Schristos if (NULL != newaddrs_tail) { 1813*eabc0478Schristos newaddrs_tail->elink = ep; 1814*eabc0478Schristos newaddrs_tail = ep; 1815*eabc0478Schristos } else { 1816*eabc0478Schristos newaddrs_tail = newaddrs = ep; 1817*eabc0478Schristos } 1818*eabc0478Schristos continue; 1819*eabc0478Schristos } 1820*eabc0478Schristos 1821*eabc0478Schristos if (!refresh_interface(ep)) { 1822*eabc0478Schristos /* 1823*eabc0478Schristos * Refreshing failed, we will delete the endpt 1824*eabc0478Schristos * in phase 2 because it was not marked current. 1825*eabc0478Schristos * We can bind to the address as the refresh 1826*eabc0478Schristos * code already closed the endpt's socket. 1827*eabc0478Schristos */ 1828*eabc0478Schristos continue; 1829*eabc0478Schristos } 1830abb0f93cSkardel /* 1831abb0f93cSkardel * found existing and up to date interface - 1832abb0f93cSkardel * mark present. 1833abb0f93cSkardel */ 18343123f114Skardel if (ep->phase != sys_interphase) { 1835abb0f93cSkardel /* 1836abb0f93cSkardel * On a new round we reset the name so 1837abb0f93cSkardel * the interface name shows up again if 1838abb0f93cSkardel * this address is no longer shared. 18393123f114Skardel * We reset ignore_packets from the 18403123f114Skardel * new prototype to respect any runtime 18413123f114Skardel * changes to the nic rules. 1842abb0f93cSkardel */ 1843*eabc0478Schristos strlcpy(ep->name, enumep.name, sizeof(ep->name)); 1844*eabc0478Schristos ep->ignore_packets = enumep.ignore_packets; 18453123f114Skardel } else { 1846*eabc0478Schristos /* 1847*eabc0478Schristos * DLH: else branch might be dead code from 1848*eabc0478Schristos * when both address and name were compared. 1849*eabc0478Schristos */ 1850*eabc0478Schristos msyslog(LOG_INFO, "%s on %u %s -> *multiple*", 1851*eabc0478Schristos stoa(&ep->sin), ep->ifnum, ep->name); 1852abb0f93cSkardel /* name collision - rename interface */ 1853*eabc0478Schristos strlcpy(ep->name, "*multiple*", sizeof(ep->name)); 18543123f114Skardel } 1855abb0f93cSkardel 1856*eabc0478Schristos DPRINT_INTERFACE(4, (ep, "updating ", " present\n")); 1857abb0f93cSkardel 1858*eabc0478Schristos if (ep->ignore_packets != enumep.ignore_packets) { 1859abb0f93cSkardel /* 1860*eabc0478Schristos * We have conflicting configurations for the 1861*eabc0478Schristos * address. This can happen with 1862*eabc0478Schristos * -I <interfacename> on the command line for an 1863*eabc0478Schristos * interface that shares its address with other 1864*eabc0478Schristos * interfaces. We cannot disambiguate incoming 1865*eabc0478Schristos * packets delivered to this socket without extra 1866*eabc0478Schristos * syscalls/features. Note this is an unusual 1867*eabc0478Schristos * configuration where several interfaces share 1868*eabc0478Schristos * an address but filtering via interface name is 1869*eabc0478Schristos * attempted. We resolve the config conflict by 1870*eabc0478Schristos * disabling the processing of received packets. 1871*eabc0478Schristos * This leads to no service on the address where 1872*eabc0478Schristos * the conflict occurs. 1873abb0f93cSkardel */ 1874*eabc0478Schristos msyslog(LOG_WARNING, 1875*eabc0478Schristos "conflicting listen configuration between" 1876*eabc0478Schristos " %s and %s for %s, disabled", 1877*eabc0478Schristos enumep.name, ep->name, stoa(&enumep.sin)); 1878abb0f93cSkardel 1879*eabc0478Schristos ep->ignore_packets = TRUE; 1880abb0f93cSkardel } 1881abb0f93cSkardel 18823123f114Skardel ep->phase = sys_interphase; 1883abb0f93cSkardel 1884abb0f93cSkardel ifi.action = IFS_EXISTS; 18853123f114Skardel ifi.ep = ep; 1886*eabc0478Schristos if (receiver != NULL) { 1887abb0f93cSkardel (*receiver)(data, &ifi); 1888abb0f93cSkardel } 1889abb0f93cSkardel } 1890abb0f93cSkardel 1891abb0f93cSkardel isc_interfaceiter_destroy(&iter); 1892abb0f93cSkardel 1893abb0f93cSkardel /* 1894*eabc0478Schristos * Phase 1b 1895*eabc0478Schristos */ 1896*eabc0478Schristos for (ep = newaddrs; ep != NULL; ep = ep->elink) { 1897*eabc0478Schristos if (IS_IPV6(&ep->sin) && is_linklocal(&ep->sin)) { 1898*eabc0478Schristos for (ep2 = newaddrs; ep2 != NULL; ep2 = ep2->elink) { 1899*eabc0478Schristos if ( IS_IPV6(&ep2->sin) 1900*eabc0478Schristos && ep != ep2 1901*eabc0478Schristos && !is_linklocal(&ep2->sin)) { 1902*eabc0478Schristos 1903*eabc0478Schristos ep->flags |= INT_LL_OF_GLOB; 1904*eabc0478Schristos break; 1905*eabc0478Schristos } 1906*eabc0478Schristos } 1907*eabc0478Schristos } 1908*eabc0478Schristos } 1909*eabc0478Schristos for (ep2 = newaddrs; ep2 != NULL; ep2 = next_ep) { 1910*eabc0478Schristos next_ep = ep2->elink; 1911*eabc0478Schristos ep2->elink = NULL; 1912*eabc0478Schristos ep = create_interface(port, ep2); 1913*eabc0478Schristos if (ep != NULL) { 1914*eabc0478Schristos ifi.action = IFS_CREATED; 1915*eabc0478Schristos ifi.ep = ep; 1916*eabc0478Schristos if (receiver != NULL) { 1917*eabc0478Schristos (*receiver)(data, &ifi); 1918*eabc0478Schristos } 1919*eabc0478Schristos new_interface_found = TRUE; 1920*eabc0478Schristos DPRINT_INTERFACE(3, 1921*eabc0478Schristos (ep, "updating ", " new - created\n")); 1922*eabc0478Schristos } 1923*eabc0478Schristos else { 1924*eabc0478Schristos DPRINT_INTERFACE(3, 1925*eabc0478Schristos (ep, "updating ", " new - FAILED")); 1926*eabc0478Schristos 1927*eabc0478Schristos msyslog(LOG_ERR, 1928*eabc0478Schristos "cannot bind address %s", 1929*eabc0478Schristos stoa(&ep->sin)); 1930*eabc0478Schristos } 1931*eabc0478Schristos free(ep2); 1932*eabc0478Schristos } 1933*eabc0478Schristos 1934*eabc0478Schristos /* 1935abb0f93cSkardel * phase 2 - delete gone interfaces - reassigning peers to 1936abb0f93cSkardel * other interfaces 1937abb0f93cSkardel */ 19383123f114Skardel for (ep = ep_list; ep != NULL; ep = next_ep) { 19393123f114Skardel next_ep = ep->elink; 1940abb0f93cSkardel 1941abb0f93cSkardel /* 19423123f114Skardel * if phase does not match sys_phase this interface was 19433123f114Skardel * not enumerated during the last interface scan - so it 19443123f114Skardel * is gone and will be deleted here unless it did not 19453123f114Skardel * originate from interface enumeration (INT_WILDCARD, 19463123f114Skardel * INT_MCASTIF). 1947abb0f93cSkardel */ 19483123f114Skardel if (((INT_WILDCARD | INT_MCASTIF) & ep->flags) || 19493123f114Skardel ep->phase == sys_interphase) 19503123f114Skardel continue; 19513123f114Skardel 19523123f114Skardel DPRINT_INTERFACE(3, (ep, "updating ", 1953abb0f93cSkardel "GONE - deleting\n")); 19543123f114Skardel remove_interface(ep); 1955abb0f93cSkardel 1956abb0f93cSkardel ifi.action = IFS_DELETED; 19573123f114Skardel ifi.ep = ep; 1958*eabc0478Schristos if (receiver != NULL) { 1959abb0f93cSkardel (*receiver)(data, &ifi); 1960*eabc0478Schristos } 19613123f114Skardel /* disconnect peers from deleted endpt. */ 1962*eabc0478Schristos while (ep->peers != NULL) { 19633123f114Skardel set_peerdstadr(ep->peers, NULL); 1964*eabc0478Schristos } 1965abb0f93cSkardel /* 1966abb0f93cSkardel * update globals in case we lose 1967abb0f93cSkardel * a loopback interface 1968abb0f93cSkardel */ 1969*eabc0478Schristos if (ep == loopback_interface) { 1970abb0f93cSkardel loopback_interface = NULL; 1971*eabc0478Schristos } 19723123f114Skardel delete_interface(ep); 1973abb0f93cSkardel } 1974abb0f93cSkardel 1975abb0f93cSkardel /* 19762950cc38Schristos * phase 3 - re-configure as the world has possibly changed 19772950cc38Schristos * 19782950cc38Schristos * never ever make this conditional again - it is needed to track 19792950cc38Schristos * routing updates. see bug #2506 1980abb0f93cSkardel */ 1981abb0f93cSkardel refresh_all_peerinterfaces(); 19822950cc38Schristos 1983*eabc0478Schristos if (sys_bclient) { 19846d448381Skardel io_setbclient(); 1985*eabc0478Schristos } 1986af12ab5eSchristos #ifdef MCAST 19875d681e99Schristos /* 19885d681e99Schristos * Check multicast interfaces and try to join multicast groups if 19895d681e99Schristos * not joined yet. 19905d681e99Schristos */ 19915d681e99Schristos for (ep = ep_list; ep != NULL; ep = ep->elink) { 19925d681e99Schristos remaddr_t *entry; 19935d681e99Schristos 1994*eabc0478Schristos if (!(INT_MCASTIF & ep->flags) || (INT_MCASTOPEN & ep->flags)) { 19955d681e99Schristos continue; 1996*eabc0478Schristos } 19975d681e99Schristos /* Find remote address that was linked to this interface */ 19985d681e99Schristos for (entry = remoteaddr_list; 19995d681e99Schristos entry != NULL; 20005d681e99Schristos entry = entry->link) { 20015d681e99Schristos if (entry->ep == ep) { 20025d681e99Schristos if (socket_multicast_enable(ep, &entry->addr)) { 20035d681e99Schristos msyslog(LOG_INFO, 20045d681e99Schristos "Joined %s socket to multicast group %s", 20055d681e99Schristos stoa(&ep->sin), 20065d681e99Schristos stoa(&entry->addr)); 20075d681e99Schristos } 20085d681e99Schristos break; 20095d681e99Schristos } 20105d681e99Schristos } 20115d681e99Schristos } 2012af12ab5eSchristos #endif /* MCAST */ 20135d681e99Schristos 2014abb0f93cSkardel return new_interface_found; 2015abb0f93cSkardel } 2016abb0f93cSkardel 2017abb0f93cSkardel 2018abb0f93cSkardel /* 2019abb0f93cSkardel * create_sockets - create a socket for each interface plus a default 2020abb0f93cSkardel * socket for when we don't know where to send 2021abb0f93cSkardel */ 2022abb0f93cSkardel static int 2023abb0f93cSkardel create_sockets( 2024abb0f93cSkardel u_short port 2025abb0f93cSkardel ) 2026abb0f93cSkardel { 2027abb0f93cSkardel #ifndef HAVE_IO_COMPLETION_PORT 2028abb0f93cSkardel /* 2029abb0f93cSkardel * I/O Completion Ports don't care about the select and FD_SET 2030abb0f93cSkardel */ 2031abb0f93cSkardel maxactivefd = 0; 2032abb0f93cSkardel FD_ZERO(&activefds); 2033abb0f93cSkardel #endif 2034abb0f93cSkardel 2035abb0f93cSkardel DPRINTF(2, ("create_sockets(%d)\n", port)); 2036abb0f93cSkardel 2037abb0f93cSkardel create_wildcards(port); 2038abb0f93cSkardel 2039abb0f93cSkardel update_interfaces(port, NULL, NULL); 2040abb0f93cSkardel 2041abb0f93cSkardel /* 2042abb0f93cSkardel * Now that we have opened all the sockets, turn off the reuse 2043abb0f93cSkardel * flag for security. 2044abb0f93cSkardel */ 2045abb0f93cSkardel set_reuseaddr(0); 2046abb0f93cSkardel 2047abb0f93cSkardel DPRINTF(2, ("create_sockets: Total interfaces = %d\n", ninterfaces)); 2048abb0f93cSkardel 2049abb0f93cSkardel return ninterfaces; 2050abb0f93cSkardel } 2051abb0f93cSkardel 2052abb0f93cSkardel /* 2053abb0f93cSkardel * create_interface - create a new interface for a given prototype 2054abb0f93cSkardel * binding the socket. 2055abb0f93cSkardel */ 2056*eabc0478Schristos static endpt * 2057abb0f93cSkardel create_interface( 2058abb0f93cSkardel u_short port, 2059*eabc0478Schristos endpt * protot 2060abb0f93cSkardel ) 2061abb0f93cSkardel { 2062abb0f93cSkardel sockaddr_u resmask; 20633123f114Skardel endpt * iface; 2064*eabc0478Schristos int/*BOOL*/ success; 20653123f114Skardel #if defined(MCAST) && defined(MULTICAST_NONEWSOCKET) 20663123f114Skardel remaddr_t * entry; 20673123f114Skardel remaddr_t * next_entry; 20683123f114Skardel #endif 2069*eabc0478Schristos DPRINTF(2, ("create_interface(%s)\n", sptoa(&protot->sin))); 2070abb0f93cSkardel 2071abb0f93cSkardel /* build an interface */ 2072abb0f93cSkardel iface = new_interface(protot); 2073abb0f93cSkardel 2074abb0f93cSkardel /* 2075abb0f93cSkardel * create socket 2076abb0f93cSkardel */ 2077abb0f93cSkardel iface->fd = open_socket(&iface->sin, 0, 0, iface); 2078abb0f93cSkardel 2079abb0f93cSkardel if (iface->fd != INVALID_SOCKET) 20803123f114Skardel log_listen_address(iface); 2081abb0f93cSkardel 2082abb0f93cSkardel if ((INT_BROADCAST & iface->flags) 2083abb0f93cSkardel && iface->bfd != INVALID_SOCKET) 2084*eabc0478Schristos msyslog(LOG_INFO, "Listening on broadcast address %s", 2085*eabc0478Schristos sptoa(&iface->bcast)); 2086abb0f93cSkardel 2087abb0f93cSkardel if (INVALID_SOCKET == iface->fd 2088abb0f93cSkardel && INVALID_SOCKET == iface->bfd) { 2089*eabc0478Schristos msyslog(LOG_ERR, "unable to create socket on %s (%d) for %s", 2090abb0f93cSkardel iface->name, 2091abb0f93cSkardel iface->ifnum, 2092*eabc0478Schristos sptoa(&iface->sin)); 2093abb0f93cSkardel delete_interface(iface); 2094abb0f93cSkardel return NULL; 2095abb0f93cSkardel } 2096abb0f93cSkardel 2097abb0f93cSkardel /* 2098abb0f93cSkardel * Blacklist our own addresses, no use talking to ourself 2099abb0f93cSkardel */ 2100abb0f93cSkardel SET_HOSTMASK(&resmask, AF(&iface->sin)); 2101*eabc0478Schristos success = hack_restrict(RESTRICT_FLAGS, &iface->sin, &resmask, 2102*eabc0478Schristos -4, RESM_NTPONLY | RESM_INTERFACE, 2103*eabc0478Schristos RES_IGNORE, 0); 2104*eabc0478Schristos if (!success) { 2105*eabc0478Schristos msyslog(LOG_ERR, 2106*eabc0478Schristos "unable to self-restrict %s", stoa(&iface->sin)); 2107*eabc0478Schristos } 2108abb0f93cSkardel 2109abb0f93cSkardel /* 2110abb0f93cSkardel * set globals with the first found 2111abb0f93cSkardel * loopback interface of the appropriate class 2112abb0f93cSkardel */ 2113abb0f93cSkardel if (NULL == loopback_interface && AF_INET == iface->family 2114abb0f93cSkardel && (INT_LOOPBACK & iface->flags)) 2115abb0f93cSkardel loopback_interface = iface; 2116abb0f93cSkardel 2117abb0f93cSkardel /* 2118abb0f93cSkardel * put into our interface list 2119abb0f93cSkardel */ 2120abb0f93cSkardel add_addr_to_list(&iface->sin, iface); 2121abb0f93cSkardel add_interface(iface); 2122abb0f93cSkardel 21233123f114Skardel #if defined(MCAST) && defined(MULTICAST_NONEWSOCKET) 21243123f114Skardel /* 21253123f114Skardel * Join any previously-configured compatible multicast groups. 21263123f114Skardel */ 21273123f114Skardel if (INT_MULTICAST & iface->flags && 21283123f114Skardel !((INT_LOOPBACK | INT_WILDCARD) & iface->flags) && 21293123f114Skardel !iface->ignore_packets) { 21303123f114Skardel for (entry = remoteaddr_list; 21313123f114Skardel entry != NULL; 21323123f114Skardel entry = next_entry) { 21333123f114Skardel next_entry = entry->link; 21343123f114Skardel if (AF(&iface->sin) != AF(&entry->addr) || 21353123f114Skardel !IS_MCAST(&entry->addr)) 21363123f114Skardel continue; 21373123f114Skardel if (socket_multicast_enable(iface, 21383123f114Skardel &entry->addr)) 21393123f114Skardel msyslog(LOG_INFO, 21403123f114Skardel "Joined %s socket to multicast group %s", 21413123f114Skardel stoa(&iface->sin), 21423123f114Skardel stoa(&entry->addr)); 21433123f114Skardel else 21443123f114Skardel msyslog(LOG_ERR, 21453123f114Skardel "Failed to join %s socket to multicast group %s", 21463123f114Skardel stoa(&iface->sin), 21473123f114Skardel stoa(&entry->addr)); 21483123f114Skardel } 21493123f114Skardel } 21503123f114Skardel #endif /* MCAST && MCAST_NONEWSOCKET */ 21513123f114Skardel 2152abb0f93cSkardel DPRINT_INTERFACE(2, (iface, "created ", "\n")); 2153abb0f93cSkardel return iface; 2154abb0f93cSkardel } 2155abb0f93cSkardel 2156abb0f93cSkardel 2157*eabc0478Schristos #ifdef DEBUG 2158*eabc0478Schristos const char * 2159*eabc0478Schristos iflags_str( 2160*eabc0478Schristos u_int32 iflags 2161*eabc0478Schristos ) 2162*eabc0478Schristos { 2163*eabc0478Schristos const size_t sz = LIB_BUFLENGTH; 2164*eabc0478Schristos char * ifs; 2165*eabc0478Schristos 2166*eabc0478Schristos LIB_GETBUF(ifs); 2167*eabc0478Schristos ifs[0] = '\0'; 2168*eabc0478Schristos 2169*eabc0478Schristos if (iflags & INT_UP) { 2170*eabc0478Schristos CLEAR_BIT_IF_DEBUG(INT_UP, iflags); 2171*eabc0478Schristos append_flagstr(ifs, sz, "up"); 2172*eabc0478Schristos } 2173*eabc0478Schristos 2174*eabc0478Schristos if (iflags & INT_PPP) { 2175*eabc0478Schristos CLEAR_BIT_IF_DEBUG(INT_PPP, iflags); 2176*eabc0478Schristos append_flagstr(ifs, sz, "ppp"); 2177*eabc0478Schristos } 2178*eabc0478Schristos 2179*eabc0478Schristos if (iflags & INT_LOOPBACK) { 2180*eabc0478Schristos CLEAR_BIT_IF_DEBUG(INT_LOOPBACK, iflags); 2181*eabc0478Schristos append_flagstr(ifs, sz, "loopback"); 2182*eabc0478Schristos } 2183*eabc0478Schristos 2184*eabc0478Schristos if (iflags & INT_BROADCAST) { 2185*eabc0478Schristos CLEAR_BIT_IF_DEBUG(INT_BROADCAST, iflags); 2186*eabc0478Schristos append_flagstr(ifs, sz, "broadcast"); 2187*eabc0478Schristos } 2188*eabc0478Schristos 2189*eabc0478Schristos if (iflags & INT_MULTICAST) { 2190*eabc0478Schristos CLEAR_BIT_IF_DEBUG(INT_MULTICAST, iflags); 2191*eabc0478Schristos append_flagstr(ifs, sz, "multicast"); 2192*eabc0478Schristos } 2193*eabc0478Schristos 2194*eabc0478Schristos if (iflags & INT_BCASTOPEN) { 2195*eabc0478Schristos CLEAR_BIT_IF_DEBUG(INT_BCASTOPEN, iflags); 2196*eabc0478Schristos append_flagstr(ifs, sz, "bcastopen"); 2197*eabc0478Schristos } 2198*eabc0478Schristos 2199*eabc0478Schristos if (iflags & INT_MCASTOPEN) { 2200*eabc0478Schristos CLEAR_BIT_IF_DEBUG(INT_MCASTOPEN, iflags); 2201*eabc0478Schristos append_flagstr(ifs, sz, "mcastopen"); 2202*eabc0478Schristos } 2203*eabc0478Schristos 2204*eabc0478Schristos if (iflags & INT_WILDCARD) { 2205*eabc0478Schristos CLEAR_BIT_IF_DEBUG(INT_WILDCARD, iflags); 2206*eabc0478Schristos append_flagstr(ifs, sz, "wildcard"); 2207*eabc0478Schristos } 2208*eabc0478Schristos 2209*eabc0478Schristos if (iflags & INT_MCASTIF) { 2210*eabc0478Schristos CLEAR_BIT_IF_DEBUG(INT_MCASTIF, iflags); 2211*eabc0478Schristos append_flagstr(ifs, sz, "mcastif"); 2212*eabc0478Schristos } 2213*eabc0478Schristos 2214*eabc0478Schristos if (iflags & INT_PRIVACY) { 2215*eabc0478Schristos CLEAR_BIT_IF_DEBUG(INT_PRIVACY, iflags); 2216*eabc0478Schristos append_flagstr(ifs, sz, "IPv6privacy"); 2217*eabc0478Schristos } 2218*eabc0478Schristos 2219*eabc0478Schristos if (iflags & INT_BCASTXMIT) { 2220*eabc0478Schristos CLEAR_BIT_IF_DEBUG(INT_BCASTXMIT, iflags); 2221*eabc0478Schristos append_flagstr(ifs, sz, "bcastxmit"); 2222*eabc0478Schristos } 2223*eabc0478Schristos 2224*eabc0478Schristos if (iflags & INT_LL_OF_GLOB) { 2225*eabc0478Schristos CLEAR_BIT_IF_DEBUG(INT_LL_OF_GLOB, iflags); 2226*eabc0478Schristos append_flagstr(ifs, sz, "linklocal-w-global"); 2227*eabc0478Schristos } 2228*eabc0478Schristos 2229*eabc0478Schristos DEBUG_INVARIANT(!iflags); 2230*eabc0478Schristos 2231*eabc0478Schristos return ifs; 2232*eabc0478Schristos } 2233*eabc0478Schristos #endif /* DEBUG */ 2234*eabc0478Schristos 2235*eabc0478Schristos 2236abb0f93cSkardel #ifdef SO_EXCLUSIVEADDRUSE 2237abb0f93cSkardel static void 2238abb0f93cSkardel set_excladdruse( 2239abb0f93cSkardel SOCKET fd 2240abb0f93cSkardel ) 2241abb0f93cSkardel { 2242abb0f93cSkardel int one = 1; 2243abb0f93cSkardel int failed; 2244abb0f93cSkardel #ifdef SYS_WINNT 2245abb0f93cSkardel DWORD err; 2246abb0f93cSkardel #endif 2247abb0f93cSkardel 2248abb0f93cSkardel failed = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, 22494eea345dSchristos (void *)&one, sizeof(one)); 2250abb0f93cSkardel 2251abb0f93cSkardel if (!failed) 2252abb0f93cSkardel return; 2253abb0f93cSkardel 2254abb0f93cSkardel #ifdef SYS_WINNT 2255abb0f93cSkardel /* 2256abb0f93cSkardel * Prior to Windows XP setting SO_EXCLUSIVEADDRUSE can fail with 2257abb0f93cSkardel * error WSAINVAL depending on service pack level and whether 2258abb0f93cSkardel * the user account is in the Administrators group. Do not 2259abb0f93cSkardel * complain if it fails that way on versions prior to XP (5.1). 2260abb0f93cSkardel */ 2261abb0f93cSkardel err = GetLastError(); 2262abb0f93cSkardel 2263abb0f93cSkardel if (isc_win32os_versioncheck(5, 1, 0, 0) < 0 /* < 5.1/XP */ 2264abb0f93cSkardel && WSAEINVAL == err) 2265abb0f93cSkardel return; 2266abb0f93cSkardel 2267abb0f93cSkardel SetLastError(err); 2268abb0f93cSkardel #endif 2269abb0f93cSkardel msyslog(LOG_ERR, 2270abb0f93cSkardel "setsockopt(%d, SO_EXCLUSIVEADDRUSE, on): %m", 2271abb0f93cSkardel (int)fd); 2272abb0f93cSkardel } 2273abb0f93cSkardel #endif /* SO_EXCLUSIVEADDRUSE */ 2274abb0f93cSkardel 2275abb0f93cSkardel 2276abb0f93cSkardel /* 2277abb0f93cSkardel * set_reuseaddr() - set/clear REUSEADDR on all sockets 2278abb0f93cSkardel * NB possible hole - should we be doing this on broadcast 2279abb0f93cSkardel * fd's also? 2280abb0f93cSkardel */ 2281abb0f93cSkardel static void 2282abb0f93cSkardel set_reuseaddr( 2283abb0f93cSkardel int flag 2284abb0f93cSkardel ) 2285abb0f93cSkardel { 2286abb0f93cSkardel #ifndef SO_EXCLUSIVEADDRUSE 22873123f114Skardel endpt *ep; 2288abb0f93cSkardel 22893123f114Skardel for (ep = ep_list; ep != NULL; ep = ep->elink) { 22903123f114Skardel if (ep->flags & INT_WILDCARD) 2291abb0f93cSkardel continue; 2292abb0f93cSkardel 2293abb0f93cSkardel /* 22943123f114Skardel * if ep->fd is INVALID_SOCKET, we might have a adapter 2295abb0f93cSkardel * configured but not present 2296abb0f93cSkardel */ 2297abb0f93cSkardel DPRINTF(4, ("setting SO_REUSEADDR on %.16s@%s to %s\n", 22983123f114Skardel ep->name, stoa(&ep->sin), 2299abb0f93cSkardel flag ? "on" : "off")); 2300abb0f93cSkardel 23013123f114Skardel if (ep->fd != INVALID_SOCKET) { 23023123f114Skardel if (setsockopt(ep->fd, SOL_SOCKET, SO_REUSEADDR, 23034eea345dSchristos (void *)&flag, sizeof(flag))) { 23043123f114Skardel msyslog(LOG_ERR, "set_reuseaddr: setsockopt(%s, SO_REUSEADDR, %s) failed: %m", 23053123f114Skardel stoa(&ep->sin), flag ? "on" : "off"); 2306abb0f93cSkardel } 2307abb0f93cSkardel } 2308abb0f93cSkardel } 2309abb0f93cSkardel #endif /* ! SO_EXCLUSIVEADDRUSE */ 2310abb0f93cSkardel } 2311abb0f93cSkardel 2312abb0f93cSkardel /* 2313abb0f93cSkardel * This is just a wrapper around an internal function so we can 2314abb0f93cSkardel * make other changes as necessary later on 2315abb0f93cSkardel */ 2316abb0f93cSkardel void 2317abb0f93cSkardel enable_broadcast( 2318*eabc0478Schristos endpt * iface, 2319abb0f93cSkardel sockaddr_u * baddr 2320abb0f93cSkardel ) 2321abb0f93cSkardel { 2322abb0f93cSkardel #ifdef OPEN_BCAST_SOCKET 2323abb0f93cSkardel socket_broadcast_enable(iface, iface->fd, baddr); 2324abb0f93cSkardel #endif 2325abb0f93cSkardel } 2326abb0f93cSkardel 2327abb0f93cSkardel #ifdef OPEN_BCAST_SOCKET 2328abb0f93cSkardel /* 2329abb0f93cSkardel * Enable a broadcast address to a given socket 23302950cc38Schristos * The socket is in the ep_list all we need to do is enable 2331abb0f93cSkardel * broadcasting. It is not this function's job to select the socket 2332abb0f93cSkardel */ 2333abb0f93cSkardel static isc_boolean_t 2334abb0f93cSkardel socket_broadcast_enable( 2335*eabc0478Schristos endpt * iface, 2336abb0f93cSkardel SOCKET fd, 2337abb0f93cSkardel sockaddr_u * baddr 2338abb0f93cSkardel ) 2339abb0f93cSkardel { 2340abb0f93cSkardel #ifdef SO_BROADCAST 2341abb0f93cSkardel int on = 1; 2342abb0f93cSkardel 2343abb0f93cSkardel if (IS_IPV4(baddr)) { 2344abb0f93cSkardel /* if this interface can support broadcast, set SO_BROADCAST */ 2345abb0f93cSkardel if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, 23464eea345dSchristos (void *)&on, sizeof(on))) 2347abb0f93cSkardel msyslog(LOG_ERR, 2348abb0f93cSkardel "setsockopt(SO_BROADCAST) enable failure on address %s: %m", 2349abb0f93cSkardel stoa(baddr)); 2350abb0f93cSkardel else 2351abb0f93cSkardel DPRINTF(2, ("Broadcast enabled on socket %d for address %s\n", 2352abb0f93cSkardel fd, stoa(baddr))); 2353abb0f93cSkardel } 23542950cc38Schristos iface->flags |= INT_BCASTXMIT; 2355abb0f93cSkardel return ISC_TRUE; 2356abb0f93cSkardel #else 2357abb0f93cSkardel return ISC_FALSE; 2358abb0f93cSkardel #endif /* SO_BROADCAST */ 2359abb0f93cSkardel } 2360abb0f93cSkardel 2361ea66d795Schristos #ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES 2362abb0f93cSkardel /* 2363abb0f93cSkardel * Remove a broadcast address from a given socket 23642950cc38Schristos * The socket is in the ep_list all we need to do is disable 2365abb0f93cSkardel * broadcasting. It is not this function's job to select the socket 2366abb0f93cSkardel */ 2367abb0f93cSkardel static isc_boolean_t 2368abb0f93cSkardel socket_broadcast_disable( 2369*eabc0478Schristos endpt * iface, 2370abb0f93cSkardel sockaddr_u * baddr 2371abb0f93cSkardel ) 2372abb0f93cSkardel { 2373abb0f93cSkardel #ifdef SO_BROADCAST 2374abb0f93cSkardel int off = 0; /* This seems to be OK as an int */ 2375abb0f93cSkardel 2376abb0f93cSkardel if (IS_IPV4(baddr) && setsockopt(iface->fd, SOL_SOCKET, 23774eea345dSchristos SO_BROADCAST, (void *)&off, sizeof(off))) 2378abb0f93cSkardel msyslog(LOG_ERR, 2379abb0f93cSkardel "setsockopt(SO_BROADCAST) disable failure on address %s: %m", 2380abb0f93cSkardel stoa(baddr)); 2381abb0f93cSkardel 23822950cc38Schristos iface->flags &= ~INT_BCASTXMIT; 2383abb0f93cSkardel return ISC_TRUE; 2384abb0f93cSkardel #else 2385abb0f93cSkardel return ISC_FALSE; 2386abb0f93cSkardel #endif /* SO_BROADCAST */ 2387abb0f93cSkardel } 2388ea66d795Schristos #endif /* OS_MISSES_SPECIFIC_ROUTE_UPDATES */ 2389abb0f93cSkardel 2390abb0f93cSkardel #endif /* OPEN_BCAST_SOCKET */ 2391abb0f93cSkardel 239268dbbb44Schristos 2393abb0f93cSkardel /* 2394abb0f93cSkardel * Check to see if the address is a multicast address 2395abb0f93cSkardel */ 2396abb0f93cSkardel static isc_boolean_t 2397abb0f93cSkardel addr_ismulticast( 2398abb0f93cSkardel sockaddr_u *maddr 2399abb0f93cSkardel ) 2400abb0f93cSkardel { 2401abb0f93cSkardel isc_boolean_t result; 2402abb0f93cSkardel 2403abb0f93cSkardel #ifndef INCLUDE_IPV6_MULTICAST_SUPPORT 2404abb0f93cSkardel /* 2405abb0f93cSkardel * If we don't have IPV6 support any IPV6 addr is not multicast 2406abb0f93cSkardel */ 2407abb0f93cSkardel if (IS_IPV6(maddr)) 2408abb0f93cSkardel result = ISC_FALSE; 2409abb0f93cSkardel else 2410abb0f93cSkardel #endif 2411abb0f93cSkardel result = IS_MCAST(maddr); 2412abb0f93cSkardel 2413abb0f93cSkardel if (!result) 2414abb0f93cSkardel DPRINTF(4, ("address %s is not multicast\n", 2415abb0f93cSkardel stoa(maddr))); 2416abb0f93cSkardel 2417abb0f93cSkardel return result; 2418abb0f93cSkardel } 2419abb0f93cSkardel 2420abb0f93cSkardel /* 2421abb0f93cSkardel * Multicast servers need to set the appropriate Multicast interface 2422abb0f93cSkardel * socket option in order for it to know which interface to use for 2423abb0f93cSkardel * send the multicast packet. 2424abb0f93cSkardel */ 2425abb0f93cSkardel void 2426abb0f93cSkardel enable_multicast_if( 2427*eabc0478Schristos endpt * iface, 2428abb0f93cSkardel sockaddr_u * maddr 2429abb0f93cSkardel ) 2430abb0f93cSkardel { 2431abb0f93cSkardel #ifdef MCAST 24322950cc38Schristos #ifdef IP_MULTICAST_LOOP 2433abb0f93cSkardel TYPEOF_IP_MULTICAST_LOOP off = 0; 24342950cc38Schristos #endif 2435f44489f8Sprlw1 #if defined(INCLUDE_IPV6_MULTICAST_SUPPORT) && defined(IPV6_MULTICAST_LOOP) 24362950cc38Schristos u_int off6 = 0; 24372950cc38Schristos #endif 2438abb0f93cSkardel 2439af12ab5eSchristos REQUIRE(AF(maddr) == AF(&iface->sin)); 2440abb0f93cSkardel 2441abb0f93cSkardel switch (AF(&iface->sin)) { 2442abb0f93cSkardel 2443abb0f93cSkardel case AF_INET: 2444abb0f93cSkardel #ifdef IP_MULTICAST_LOOP 2445abb0f93cSkardel /* 2446abb0f93cSkardel * Don't send back to itself, but allow failure to set 2447abb0f93cSkardel */ 2448abb0f93cSkardel if (setsockopt(iface->fd, IPPROTO_IP, 2449abb0f93cSkardel IP_MULTICAST_LOOP, 24504eea345dSchristos (void *)&off, 2451abb0f93cSkardel sizeof(off))) { 2452abb0f93cSkardel 2453abb0f93cSkardel msyslog(LOG_ERR, 2454abb0f93cSkardel "setsockopt IP_MULTICAST_LOOP failed: %m on socket %d, addr %s for multicast address %s", 2455abb0f93cSkardel iface->fd, stoa(&iface->sin), 2456abb0f93cSkardel stoa(maddr)); 2457abb0f93cSkardel } 2458abb0f93cSkardel #endif 2459abb0f93cSkardel break; 2460abb0f93cSkardel 2461abb0f93cSkardel case AF_INET6: 2462abb0f93cSkardel #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT 2463abb0f93cSkardel #ifdef IPV6_MULTICAST_LOOP 2464abb0f93cSkardel /* 2465abb0f93cSkardel * Don't send back to itself, but allow failure to set 2466abb0f93cSkardel */ 2467abb0f93cSkardel if (setsockopt(iface->fd, IPPROTO_IPV6, 2468abb0f93cSkardel IPV6_MULTICAST_LOOP, 24694eea345dSchristos (void *) &off6, sizeof(off6))) { 2470abb0f93cSkardel 2471abb0f93cSkardel msyslog(LOG_ERR, 24722950cc38Schristos "setsockopt IPV6_MULTICAST_LOOP failed: %m on socket %d, addr %s for multicast address %s", 2473abb0f93cSkardel iface->fd, stoa(&iface->sin), 2474abb0f93cSkardel stoa(maddr)); 2475abb0f93cSkardel } 2476abb0f93cSkardel #endif 2477abb0f93cSkardel break; 2478abb0f93cSkardel #else 2479abb0f93cSkardel return; 2480abb0f93cSkardel #endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */ 2481abb0f93cSkardel } 2482abb0f93cSkardel return; 2483abb0f93cSkardel #endif 2484abb0f93cSkardel } 2485abb0f93cSkardel 2486abb0f93cSkardel /* 2487abb0f93cSkardel * Add a multicast address to a given socket 24882950cc38Schristos * The socket is in the ep_list all we need to do is enable 2489abb0f93cSkardel * multicasting. It is not this function's job to select the socket 2490abb0f93cSkardel */ 24913123f114Skardel #if defined(MCAST) 2492abb0f93cSkardel static isc_boolean_t 2493abb0f93cSkardel socket_multicast_enable( 24943123f114Skardel endpt * iface, 2495abb0f93cSkardel sockaddr_u * maddr 2496abb0f93cSkardel ) 2497abb0f93cSkardel { 2498abb0f93cSkardel struct ip_mreq mreq; 2499abb0f93cSkardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT 2500abb0f93cSkardel struct ipv6_mreq mreq6; 2501abb0f93cSkardel # endif 2502abb0f93cSkardel switch (AF(maddr)) { 2503abb0f93cSkardel 2504abb0f93cSkardel case AF_INET: 25052950cc38Schristos ZERO(mreq); 2506abb0f93cSkardel mreq.imr_multiaddr = SOCK_ADDR4(maddr); 2507abb0f93cSkardel mreq.imr_interface.s_addr = htonl(INADDR_ANY); 2508abb0f93cSkardel if (setsockopt(iface->fd, 2509abb0f93cSkardel IPPROTO_IP, 2510abb0f93cSkardel IP_ADD_MEMBERSHIP, 25114eea345dSchristos (void *)&mreq, 2512abb0f93cSkardel sizeof(mreq))) { 25135d681e99Schristos DPRINTF(2, ( 2514abb0f93cSkardel "setsockopt IP_ADD_MEMBERSHIP failed: %m on socket %d, addr %s for %x / %x (%s)", 2515abb0f93cSkardel iface->fd, stoa(&iface->sin), 2516abb0f93cSkardel mreq.imr_multiaddr.s_addr, 2517abb0f93cSkardel mreq.imr_interface.s_addr, 25185d681e99Schristos stoa(maddr))); 2519abb0f93cSkardel return ISC_FALSE; 2520abb0f93cSkardel } 2521abb0f93cSkardel DPRINTF(4, ("Added IPv4 multicast membership on socket %d, addr %s for %x / %x (%s)\n", 2522abb0f93cSkardel iface->fd, stoa(&iface->sin), 2523abb0f93cSkardel mreq.imr_multiaddr.s_addr, 2524abb0f93cSkardel mreq.imr_interface.s_addr, stoa(maddr))); 2525abb0f93cSkardel break; 2526abb0f93cSkardel 2527abb0f93cSkardel case AF_INET6: 2528abb0f93cSkardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT 2529abb0f93cSkardel /* 2530abb0f93cSkardel * Enable reception of multicast packets. 2531abb0f93cSkardel * If the address is link-local we can get the 2532abb0f93cSkardel * interface index from the scope id. Don't do this 2533abb0f93cSkardel * for other types of multicast addresses. For now let 2534abb0f93cSkardel * the kernel figure it out. 2535abb0f93cSkardel */ 25362950cc38Schristos ZERO(mreq6); 2537abb0f93cSkardel mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr); 25383123f114Skardel mreq6.ipv6mr_interface = iface->ifindex; 2539abb0f93cSkardel 2540abb0f93cSkardel if (setsockopt(iface->fd, IPPROTO_IPV6, 25414eea345dSchristos IPV6_JOIN_GROUP, (void *)&mreq6, 2542abb0f93cSkardel sizeof(mreq6))) { 25435d681e99Schristos DPRINTF(2, ( 25443123f114Skardel "setsockopt IPV6_JOIN_GROUP failed: %m on socket %d, addr %s for interface %u (%s)", 2545abb0f93cSkardel iface->fd, stoa(&iface->sin), 25465d681e99Schristos mreq6.ipv6mr_interface, stoa(maddr))); 2547abb0f93cSkardel return ISC_FALSE; 2548abb0f93cSkardel } 25493123f114Skardel DPRINTF(4, ("Added IPv6 multicast group on socket %d, addr %s for interface %u (%s)\n", 2550abb0f93cSkardel iface->fd, stoa(&iface->sin), 2551abb0f93cSkardel mreq6.ipv6mr_interface, stoa(maddr))); 2552abb0f93cSkardel # else 2553abb0f93cSkardel return ISC_FALSE; 2554abb0f93cSkardel # endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */ 2555abb0f93cSkardel } 2556abb0f93cSkardel iface->flags |= INT_MCASTOPEN; 2557abb0f93cSkardel iface->num_mcast++; 25583123f114Skardel 2559abb0f93cSkardel return ISC_TRUE; 2560abb0f93cSkardel } 25613123f114Skardel #endif /* MCAST */ 25623123f114Skardel 2563abb0f93cSkardel 2564abb0f93cSkardel /* 2565abb0f93cSkardel * Remove a multicast address from a given socket 25662950cc38Schristos * The socket is in the ep_list all we need to do is disable 2567abb0f93cSkardel * multicasting. It is not this function's job to select the socket 2568abb0f93cSkardel */ 25693123f114Skardel #ifdef MCAST 2570abb0f93cSkardel static isc_boolean_t 2571abb0f93cSkardel socket_multicast_disable( 2572*eabc0478Schristos endpt * iface, 2573abb0f93cSkardel sockaddr_u * maddr 2574abb0f93cSkardel ) 2575abb0f93cSkardel { 2576abb0f93cSkardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT 2577abb0f93cSkardel struct ipv6_mreq mreq6; 2578abb0f93cSkardel # endif 2579abb0f93cSkardel struct ip_mreq mreq; 2580abb0f93cSkardel 2581abb0f93cSkardel if (find_addr_in_list(maddr) == NULL) { 2582abb0f93cSkardel DPRINTF(4, ("socket_multicast_disable(%s): not found\n", 2583abb0f93cSkardel stoa(maddr))); 2584abb0f93cSkardel return ISC_TRUE; 2585abb0f93cSkardel } 2586abb0f93cSkardel 2587abb0f93cSkardel switch (AF(maddr)) { 2588abb0f93cSkardel 2589abb0f93cSkardel case AF_INET: 2590*eabc0478Schristos ZERO(mreq); 2591abb0f93cSkardel mreq.imr_multiaddr = SOCK_ADDR4(maddr); 2592abb0f93cSkardel mreq.imr_interface = SOCK_ADDR4(&iface->sin); 2593abb0f93cSkardel if (setsockopt(iface->fd, IPPROTO_IP, 25944eea345dSchristos IP_DROP_MEMBERSHIP, (void *)&mreq, 2595abb0f93cSkardel sizeof(mreq))) { 2596abb0f93cSkardel 2597abb0f93cSkardel msyslog(LOG_ERR, 2598abb0f93cSkardel "setsockopt IP_DROP_MEMBERSHIP failed: %m on socket %d, addr %s for %x / %x (%s)", 2599abb0f93cSkardel iface->fd, stoa(&iface->sin), 2600abb0f93cSkardel SRCADR(maddr), SRCADR(&iface->sin), 2601abb0f93cSkardel stoa(maddr)); 2602abb0f93cSkardel return ISC_FALSE; 2603abb0f93cSkardel } 2604abb0f93cSkardel break; 2605abb0f93cSkardel case AF_INET6: 2606abb0f93cSkardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT 2607abb0f93cSkardel /* 2608abb0f93cSkardel * Disable reception of multicast packets 2609abb0f93cSkardel * If the address is link-local we can get the 2610abb0f93cSkardel * interface index from the scope id. Don't do this 2611abb0f93cSkardel * for other types of multicast addresses. For now let 2612abb0f93cSkardel * the kernel figure it out. 2613abb0f93cSkardel */ 2614*eabc0478Schristos ZERO(mreq6); 2615abb0f93cSkardel mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr); 26163123f114Skardel mreq6.ipv6mr_interface = iface->ifindex; 2617abb0f93cSkardel 2618abb0f93cSkardel if (setsockopt(iface->fd, IPPROTO_IPV6, 26194eea345dSchristos IPV6_LEAVE_GROUP, (void *)&mreq6, 2620abb0f93cSkardel sizeof(mreq6))) { 2621abb0f93cSkardel 2622abb0f93cSkardel msyslog(LOG_ERR, 2623abb0f93cSkardel "setsockopt IPV6_LEAVE_GROUP failure: %m on socket %d, addr %s for %d (%s)", 2624abb0f93cSkardel iface->fd, stoa(&iface->sin), 26253123f114Skardel iface->ifindex, stoa(maddr)); 2626abb0f93cSkardel return ISC_FALSE; 2627abb0f93cSkardel } 2628abb0f93cSkardel break; 2629abb0f93cSkardel # else 2630abb0f93cSkardel return ISC_FALSE; 2631abb0f93cSkardel # endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */ 2632abb0f93cSkardel } 2633abb0f93cSkardel 2634abb0f93cSkardel iface->num_mcast--; 2635*eabc0478Schristos if (iface->num_mcast <= 0) { 2636abb0f93cSkardel iface->flags &= ~INT_MCASTOPEN; 2637*eabc0478Schristos } 2638abb0f93cSkardel return ISC_TRUE; 2639abb0f93cSkardel } 2640abb0f93cSkardel #endif /* MCAST */ 2641abb0f93cSkardel 2642*eabc0478Schristos 2643abb0f93cSkardel /* 2644abb0f93cSkardel * io_setbclient - open the broadcast client sockets 2645abb0f93cSkardel */ 2646abb0f93cSkardel void 2647abb0f93cSkardel io_setbclient(void) 2648abb0f93cSkardel { 2649abb0f93cSkardel #ifdef OPEN_BCAST_SOCKET 2650cdfa2a7eSchristos endpt * ep; 2651*eabc0478Schristos unsigned int nif, ni4; 2652abb0f93cSkardel 2653*eabc0478Schristos nif = ni4 = 0; 2654abb0f93cSkardel set_reuseaddr(1); 2655abb0f93cSkardel 2656cdfa2a7eSchristos for (ep = ep_list; ep != NULL; ep = ep->elink) { 2657*eabc0478Schristos /* count IPv4 interfaces. Needed later to decide 2658cdfa2a7eSchristos * if we should log an error or not. 2659cdfa2a7eSchristos */ 2660*eabc0478Schristos if (AF_INET == ep->family) { 2661*eabc0478Schristos ++ni4; 2662cdfa2a7eSchristos } 2663abb0f93cSkardel 2664cdfa2a7eSchristos if (ep->flags & (INT_WILDCARD | INT_LOOPBACK)) 2665abb0f93cSkardel continue; 2666abb0f93cSkardel 2667abb0f93cSkardel /* use only allowed addresses */ 2668cdfa2a7eSchristos if (ep->ignore_packets) 2669abb0f93cSkardel continue; 2670abb0f93cSkardel 2671abb0f93cSkardel /* Need a broadcast-capable interface */ 2672cdfa2a7eSchristos if (!(ep->flags & INT_BROADCAST)) 2673abb0f93cSkardel continue; 2674abb0f93cSkardel 2675abb0f93cSkardel /* Only IPv4 addresses are valid for broadcast */ 2676cdfa2a7eSchristos REQUIRE(IS_IPV4(&ep->bcast)); 2677abb0f93cSkardel 2678abb0f93cSkardel /* Do we already have the broadcast address open? */ 2679cdfa2a7eSchristos if (ep->flags & INT_BCASTOPEN) { 2680abb0f93cSkardel /* 2681abb0f93cSkardel * account for already open interfaces to avoid 2682abb0f93cSkardel * misleading warning below 2683abb0f93cSkardel */ 2684abb0f93cSkardel nif++; 2685abb0f93cSkardel continue; 2686abb0f93cSkardel } 2687abb0f93cSkardel 2688abb0f93cSkardel /* 2689abb0f93cSkardel * Try to open the broadcast address 2690abb0f93cSkardel */ 2691cdfa2a7eSchristos ep->family = AF_INET; 2692cdfa2a7eSchristos ep->bfd = open_socket(&ep->bcast, 1, 0, ep); 2693abb0f93cSkardel 2694abb0f93cSkardel /* 2695abb0f93cSkardel * If we succeeded then we use it otherwise enable 2696abb0f93cSkardel * broadcast on the interface address 2697abb0f93cSkardel */ 2698cdfa2a7eSchristos if (ep->bfd != INVALID_SOCKET) { 2699abb0f93cSkardel nif++; 2700cdfa2a7eSchristos ep->flags |= INT_BCASTOPEN; 2701abb0f93cSkardel msyslog(LOG_INFO, 27022950cc38Schristos "Listen for broadcasts to %s on interface #%d %s", 2703cdfa2a7eSchristos stoa(&ep->bcast), ep->ifnum, ep->name); 270468dbbb44Schristos } else switch (errno) { 270568dbbb44Schristos /* Silently ignore EADDRINUSE as we probably 270668dbbb44Schristos * opened the socket already for an address in 270768dbbb44Schristos * the same network */ 270868dbbb44Schristos case EADDRINUSE: 270968dbbb44Schristos /* Some systems cannot bind a socket to a broadcast 271068dbbb44Schristos * address, as that is not a valid host address. */ 271168dbbb44Schristos case EADDRNOTAVAIL: 271268dbbb44Schristos # ifdef SYS_WINNT /*TODO: use for other systems, too? */ 271368dbbb44Schristos /* avoid recurrence here -- if we already have a 271468dbbb44Schristos * regular socket, it's quite useless to try this 271568dbbb44Schristos * again. 271668dbbb44Schristos */ 2717cdfa2a7eSchristos if (ep->fd != INVALID_SOCKET) { 2718cdfa2a7eSchristos ep->flags |= INT_BCASTOPEN; 271968dbbb44Schristos nif++; 272068dbbb44Schristos } 272168dbbb44Schristos # endif 272268dbbb44Schristos break; 272368dbbb44Schristos 272468dbbb44Schristos default: 27252950cc38Schristos msyslog(LOG_INFO, 27262950cc38Schristos "failed to listen for broadcasts to %s on interface #%d %s", 2727cdfa2a7eSchristos stoa(&ep->bcast), ep->ifnum, ep->name); 272868dbbb44Schristos break; 2729abb0f93cSkardel } 2730abb0f93cSkardel } 2731abb0f93cSkardel set_reuseaddr(0); 2732ccc794f0Schristos if (nif != 0) { 27332950cc38Schristos broadcast_client_enabled = ISC_TRUE; 27342950cc38Schristos DPRINTF(1, ("io_setbclient: listening to %d broadcast addresses\n", nif)); 2735ccc794f0Schristos } else { 27362950cc38Schristos broadcast_client_enabled = ISC_FALSE; 2737cdfa2a7eSchristos /* This is expected when having only IPv6 interfaces 2738cdfa2a7eSchristos * and no IPv4 interfaces at all. We suppress the error 2739cdfa2a7eSchristos * log in that case... everything else should work! 2740cdfa2a7eSchristos */ 2741*eabc0478Schristos if (ni4) { 2742abb0f93cSkardel msyslog(LOG_ERR, 2743abb0f93cSkardel "Unable to listen for broadcasts, no broadcast interfaces available"); 27442950cc38Schristos } 2745cdfa2a7eSchristos } 2746abb0f93cSkardel #else 2747abb0f93cSkardel msyslog(LOG_ERR, 2748abb0f93cSkardel "io_setbclient: Broadcast Client disabled by build"); 2749abb0f93cSkardel #endif /* OPEN_BCAST_SOCKET */ 2750abb0f93cSkardel } 2751abb0f93cSkardel 2752*eabc0478Schristos 2753abb0f93cSkardel /* 2754abb0f93cSkardel * io_unsetbclient - close the broadcast client sockets 2755abb0f93cSkardel */ 2756abb0f93cSkardel void 2757abb0f93cSkardel io_unsetbclient(void) 2758abb0f93cSkardel { 27593123f114Skardel endpt *ep; 2760abb0f93cSkardel 27613123f114Skardel for (ep = ep_list; ep != NULL; ep = ep->elink) { 27623123f114Skardel if (INT_WILDCARD & ep->flags) 2763abb0f93cSkardel continue; 27643123f114Skardel if (!(INT_BCASTOPEN & ep->flags)) 2765abb0f93cSkardel continue; 27662950cc38Schristos 27672950cc38Schristos if (ep->bfd != INVALID_SOCKET) { 27682950cc38Schristos /* destroy broadcast listening socket */ 27692950cc38Schristos msyslog(LOG_INFO, 27702950cc38Schristos "stop listening for broadcasts to %s on interface #%d %s", 27712950cc38Schristos stoa(&ep->bcast), ep->ifnum, ep->name); 2772*eabc0478Schristos close_and_delete_fd_from_list(ep->bfd, ep); 27732950cc38Schristos ep->bfd = INVALID_SOCKET; 2774abb0f93cSkardel } 277568dbbb44Schristos ep->flags &= ~INT_BCASTOPEN; 2776abb0f93cSkardel } 27772950cc38Schristos broadcast_client_enabled = ISC_FALSE; 27782950cc38Schristos } 2779abb0f93cSkardel 2780*eabc0478Schristos 2781abb0f93cSkardel /* 2782abb0f93cSkardel * io_multicast_add() - add multicast group address 2783abb0f93cSkardel */ 2784abb0f93cSkardel void 2785abb0f93cSkardel io_multicast_add( 2786abb0f93cSkardel sockaddr_u *addr 2787abb0f93cSkardel ) 2788abb0f93cSkardel { 2789abb0f93cSkardel #ifdef MCAST 27903123f114Skardel endpt * ep; 27913123f114Skardel endpt * one_ep; 2792abb0f93cSkardel 2793abb0f93cSkardel /* 2794abb0f93cSkardel * Check to see if this is a multicast address 2795abb0f93cSkardel */ 2796abb0f93cSkardel if (!addr_ismulticast(addr)) 2797abb0f93cSkardel return; 2798abb0f93cSkardel 2799abb0f93cSkardel /* If we already have it we can just return */ 2800abb0f93cSkardel if (NULL != find_flagged_addr_in_list(addr, INT_MCASTOPEN)) { 2801abb0f93cSkardel return; 2802abb0f93cSkardel } 2803abb0f93cSkardel 2804abb0f93cSkardel # ifndef MULTICAST_NONEWSOCKET 28053123f114Skardel ep = new_interface(NULL); 2806abb0f93cSkardel 2807abb0f93cSkardel /* 2808abb0f93cSkardel * Open a new socket for the multicast address 2809abb0f93cSkardel */ 28103123f114Skardel ep->sin = *addr; 28113123f114Skardel SET_PORT(&ep->sin, NTP_PORT); 28123123f114Skardel ep->family = AF(&ep->sin); 28133123f114Skardel AF(&ep->mask) = ep->family; 28143123f114Skardel SET_ONESMASK(&ep->mask); 2815abb0f93cSkardel 2816abb0f93cSkardel set_reuseaddr(1); 28173123f114Skardel ep->bfd = INVALID_SOCKET; 28183123f114Skardel ep->fd = open_socket(&ep->sin, 0, 0, ep); 28193123f114Skardel if (ep->fd != INVALID_SOCKET) { 28203123f114Skardel ep->ignore_packets = ISC_FALSE; 28213123f114Skardel ep->flags |= INT_MCASTIF; 28224eea345dSchristos ep->ifindex = SCOPE(addr); 2823abb0f93cSkardel 28242950cc38Schristos strlcpy(ep->name, "multicast", sizeof(ep->name)); 28253123f114Skardel DPRINT_INTERFACE(2, (ep, "multicast add ", "\n")); 28263123f114Skardel add_interface(ep); 28273123f114Skardel log_listen_address(ep); 2828abb0f93cSkardel } else { 2829abb0f93cSkardel /* bind failed, re-use wildcard interface */ 28303123f114Skardel delete_interface(ep); 2831abb0f93cSkardel 2832abb0f93cSkardel if (IS_IPV4(addr)) 28333123f114Skardel ep = wildipv4; 2834abb0f93cSkardel else if (IS_IPV6(addr)) 28353123f114Skardel ep = wildipv6; 2836abb0f93cSkardel else 28373123f114Skardel ep = NULL; 2838abb0f93cSkardel 28393123f114Skardel if (ep != NULL) { 2840abb0f93cSkardel /* HACK ! -- stuff in an address */ 2841abb0f93cSkardel /* because we don't bind addr? DH */ 28423123f114Skardel ep->bcast = *addr; 2843abb0f93cSkardel msyslog(LOG_ERR, 2844abb0f93cSkardel "multicast address %s using wildcard interface #%d %s", 28453123f114Skardel stoa(addr), ep->ifnum, ep->name); 2846abb0f93cSkardel } else { 2847abb0f93cSkardel msyslog(LOG_ERR, 2848abb0f93cSkardel "No multicast socket available to use for address %s", 2849abb0f93cSkardel stoa(addr)); 2850abb0f93cSkardel return; 2851abb0f93cSkardel } 2852abb0f93cSkardel } 28533123f114Skardel { /* in place of the { following for in #else clause */ 28543123f114Skardel one_ep = ep; 28553123f114Skardel # else /* MULTICAST_NONEWSOCKET follows */ 2856abb0f93cSkardel /* 28573123f114Skardel * For the case where we can't use a separate socket (Windows) 28583123f114Skardel * join each applicable endpoint socket to the group address. 2859abb0f93cSkardel */ 28603123f114Skardel if (IS_IPV4(addr)) 28613123f114Skardel one_ep = wildipv4; 28623123f114Skardel else 28633123f114Skardel one_ep = wildipv6; 28643123f114Skardel for (ep = ep_list; ep != NULL; ep = ep->elink) { 28653123f114Skardel if (ep->ignore_packets || AF(&ep->sin) != AF(addr) || 28663123f114Skardel !(INT_MULTICAST & ep->flags) || 28673123f114Skardel (INT_LOOPBACK | INT_WILDCARD) & ep->flags) 28683123f114Skardel continue; 28693123f114Skardel one_ep = ep; 28703123f114Skardel # endif /* MULTICAST_NONEWSOCKET */ 28713123f114Skardel if (socket_multicast_enable(ep, addr)) 28723123f114Skardel msyslog(LOG_INFO, 28733123f114Skardel "Joined %s socket to multicast group %s", 28743123f114Skardel stoa(&ep->sin), 2875abb0f93cSkardel stoa(addr)); 2876abb0f93cSkardel } 2877abb0f93cSkardel 28783123f114Skardel add_addr_to_list(addr, one_ep); 28793123f114Skardel #else /* !MCAST follows*/ 2880abb0f93cSkardel msyslog(LOG_ERR, 2881abb0f93cSkardel "Can not add multicast address %s: no multicast support", 2882abb0f93cSkardel stoa(addr)); 28833123f114Skardel #endif 2884abb0f93cSkardel return; 2885abb0f93cSkardel } 2886abb0f93cSkardel 2887abb0f93cSkardel 2888abb0f93cSkardel /* 2889abb0f93cSkardel * io_multicast_del() - delete multicast group address 2890abb0f93cSkardel */ 2891abb0f93cSkardel void 2892abb0f93cSkardel io_multicast_del( 2893abb0f93cSkardel sockaddr_u * addr 2894abb0f93cSkardel ) 2895abb0f93cSkardel { 2896abb0f93cSkardel #ifdef MCAST 28973123f114Skardel endpt *iface; 2898abb0f93cSkardel 2899abb0f93cSkardel /* 2900abb0f93cSkardel * Check to see if this is a multicast address 2901abb0f93cSkardel */ 2902abb0f93cSkardel if (!addr_ismulticast(addr)) { 2903abb0f93cSkardel msyslog(LOG_ERR, "invalid multicast address %s", 2904abb0f93cSkardel stoa(addr)); 2905abb0f93cSkardel return; 2906abb0f93cSkardel } 2907abb0f93cSkardel 2908abb0f93cSkardel /* 2909abb0f93cSkardel * Disable reception of multicast packets 2910abb0f93cSkardel */ 2911abb0f93cSkardel while ((iface = find_flagged_addr_in_list(addr, INT_MCASTOPEN)) 2912abb0f93cSkardel != NULL) 2913abb0f93cSkardel socket_multicast_disable(iface, addr); 2914abb0f93cSkardel 2915abb0f93cSkardel delete_addr_from_list(addr); 2916abb0f93cSkardel 2917abb0f93cSkardel #else /* not MCAST */ 2918abb0f93cSkardel msyslog(LOG_ERR, 2919abb0f93cSkardel "Can not delete multicast address %s: no multicast support", 2920abb0f93cSkardel stoa(addr)); 2921abb0f93cSkardel #endif /* not MCAST */ 2922abb0f93cSkardel } 2923abb0f93cSkardel 2924abb0f93cSkardel 2925abb0f93cSkardel /* 2926abb0f93cSkardel * open_socket - open a socket, returning the file descriptor 2927abb0f93cSkardel */ 2928abb0f93cSkardel 2929abb0f93cSkardel static SOCKET 2930abb0f93cSkardel open_socket( 2931abb0f93cSkardel sockaddr_u * addr, 2932abb0f93cSkardel int bcast, 2933abb0f93cSkardel int turn_off_reuse, 29343123f114Skardel endpt * interf 2935abb0f93cSkardel ) 2936abb0f93cSkardel { 2937abb0f93cSkardel SOCKET fd; 2938abb0f93cSkardel int errval; 2939abb0f93cSkardel /* 2940abb0f93cSkardel * int is OK for REUSEADR per 2941abb0f93cSkardel * http://www.kohala.com/start/mcast.api.txt 2942abb0f93cSkardel */ 2943abb0f93cSkardel int on = 1; 2944abb0f93cSkardel int off = 0; 2945abb0f93cSkardel 2946abb0f93cSkardel if (IS_IPV6(addr) && !ipv6_works) 2947abb0f93cSkardel return INVALID_SOCKET; 2948abb0f93cSkardel 2949abb0f93cSkardel /* create a datagram (UDP) socket */ 2950abb0f93cSkardel fd = socket(AF(addr), SOCK_DGRAM, 0); 2951abb0f93cSkardel if (INVALID_SOCKET == fd) { 29523123f114Skardel errval = socket_errno(); 2953abb0f93cSkardel msyslog(LOG_ERR, 2954abb0f93cSkardel "socket(AF_INET%s, SOCK_DGRAM, 0) failed on address %s: %m", 2955abb0f93cSkardel IS_IPV6(addr) ? "6" : "", stoa(addr)); 2956abb0f93cSkardel 2957abb0f93cSkardel if (errval == EPROTONOSUPPORT || 2958abb0f93cSkardel errval == EAFNOSUPPORT || 2959abb0f93cSkardel errval == EPFNOSUPPORT) 2960abb0f93cSkardel return (INVALID_SOCKET); 2961abb0f93cSkardel 2962abb0f93cSkardel errno = errval; 2963abb0f93cSkardel msyslog(LOG_ERR, 2964abb0f93cSkardel "unexpected socket() error %m code %d (not EPROTONOSUPPORT nor EAFNOSUPPORT nor EPFNOSUPPORT) - exiting", 2965abb0f93cSkardel errno); 2966abb0f93cSkardel exit(1); 2967abb0f93cSkardel } 2968abb0f93cSkardel 2969abb0f93cSkardel #ifdef SYS_WINNT 2970abb0f93cSkardel connection_reset_fix(fd, addr); 2971abb0f93cSkardel #endif 2972abb0f93cSkardel /* 2973abb0f93cSkardel * Fixup the file descriptor for some systems 2974abb0f93cSkardel * See bug #530 for details of the issue. 2975abb0f93cSkardel */ 2976abb0f93cSkardel fd = move_fd(fd); 2977abb0f93cSkardel 2978abb0f93cSkardel /* 2979abb0f93cSkardel * set SO_REUSEADDR since we will be binding the same port 2980abb0f93cSkardel * number on each interface according to turn_off_reuse. 2981abb0f93cSkardel * This is undesirable on Windows versions starting with 2982abb0f93cSkardel * Windows XP (numeric version 5.1). 2983abb0f93cSkardel */ 2984abb0f93cSkardel #ifdef SYS_WINNT 2985abb0f93cSkardel if (isc_win32os_versioncheck(5, 1, 0, 0) < 0) /* before 5.1 */ 2986abb0f93cSkardel #endif 2987abb0f93cSkardel if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 29884eea345dSchristos (void *)((turn_off_reuse) 2989abb0f93cSkardel ? &off 2990abb0f93cSkardel : &on), 2991abb0f93cSkardel sizeof(on))) { 2992abb0f93cSkardel 2993abb0f93cSkardel msyslog(LOG_ERR, 2994abb0f93cSkardel "setsockopt SO_REUSEADDR %s fails for address %s: %m", 2995abb0f93cSkardel (turn_off_reuse) 2996abb0f93cSkardel ? "off" 2997abb0f93cSkardel : "on", 2998abb0f93cSkardel stoa(addr)); 2999abb0f93cSkardel closesocket(fd); 3000abb0f93cSkardel return INVALID_SOCKET; 3001abb0f93cSkardel } 3002abb0f93cSkardel #ifdef SO_EXCLUSIVEADDRUSE 3003abb0f93cSkardel /* 3004abb0f93cSkardel * setting SO_EXCLUSIVEADDRUSE on the wildcard we open 3005abb0f93cSkardel * first will cause more specific binds to fail. 3006abb0f93cSkardel */ 3007abb0f93cSkardel if (!(interf->flags & INT_WILDCARD)) 3008abb0f93cSkardel set_excladdruse(fd); 3009abb0f93cSkardel #endif 3010abb0f93cSkardel 3011abb0f93cSkardel /* 3012abb0f93cSkardel * IPv4 specific options go here 3013abb0f93cSkardel */ 3014abb0f93cSkardel if (IS_IPV4(addr)) { 30152950cc38Schristos #if defined(IPPROTO_IP) && defined(IP_TOS) 30164eea345dSchristos if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void *)&qos, 3017abb0f93cSkardel sizeof(qos))) 3018abb0f93cSkardel msyslog(LOG_ERR, 3019abb0f93cSkardel "setsockopt IP_TOS (%02x) fails on address %s: %m", 3020abb0f93cSkardel qos, stoa(addr)); 30212950cc38Schristos #endif /* IPPROTO_IP && IP_TOS */ 3022abb0f93cSkardel if (bcast) 3023abb0f93cSkardel socket_broadcast_enable(interf, fd, addr); 3024abb0f93cSkardel } 3025abb0f93cSkardel 3026abb0f93cSkardel /* 3027abb0f93cSkardel * IPv6 specific options go here 3028abb0f93cSkardel */ 3029abb0f93cSkardel if (IS_IPV6(addr)) { 30302950cc38Schristos #if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) 30314eea345dSchristos if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, (void *)&qos, 30322950cc38Schristos sizeof(qos))) 30332950cc38Schristos msyslog(LOG_ERR, 30342950cc38Schristos "setsockopt IPV6_TCLASS (%02x) fails on address %s: %m", 30352950cc38Schristos qos, stoa(addr)); 30362950cc38Schristos #endif /* IPPROTO_IPV6 && IPV6_TCLASS */ 30373123f114Skardel #ifdef IPV6_V6ONLY 3038abb0f93cSkardel if (isc_net_probe_ipv6only() == ISC_R_SUCCESS 3039abb0f93cSkardel && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, 30404eea345dSchristos (void *)&on, sizeof(on))) 3041abb0f93cSkardel msyslog(LOG_ERR, 3042abb0f93cSkardel "setsockopt IPV6_V6ONLY on fails on address %s: %m", 3043abb0f93cSkardel stoa(addr)); 30443123f114Skardel #endif 30453123f114Skardel #ifdef IPV6_BINDV6ONLY 3046abb0f93cSkardel if (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDV6ONLY, 30474eea345dSchristos (void *)&on, sizeof(on))) 3048abb0f93cSkardel msyslog(LOG_ERR, 3049abb0f93cSkardel "setsockopt IPV6_BINDV6ONLY on fails on address %s: %m", 3050abb0f93cSkardel stoa(addr)); 30513123f114Skardel #endif 3052abb0f93cSkardel } 3053abb0f93cSkardel 3054abb0f93cSkardel #ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND 3055abb0f93cSkardel /* 3056abb0f93cSkardel * some OSes don't allow binding to more specific 3057abb0f93cSkardel * addresses if a wildcard address already bound 3058abb0f93cSkardel * to the port and SO_REUSEADDR is not set 3059abb0f93cSkardel */ 3060abb0f93cSkardel if (!is_wildcard_addr(addr)) 3061abb0f93cSkardel set_wildcard_reuse(AF(addr), 1); 3062abb0f93cSkardel #endif 3063abb0f93cSkardel 3064abb0f93cSkardel /* 3065abb0f93cSkardel * bind the local address. 3066abb0f93cSkardel */ 3067abb0f93cSkardel errval = bind(fd, &addr->sa, SOCKLEN(addr)); 3068abb0f93cSkardel 3069abb0f93cSkardel #ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND 3070abb0f93cSkardel if (!is_wildcard_addr(addr)) 3071abb0f93cSkardel set_wildcard_reuse(AF(addr), 0); 3072abb0f93cSkardel #endif 3073abb0f93cSkardel 3074abb0f93cSkardel if (errval < 0) { 3075abb0f93cSkardel /* 3076abb0f93cSkardel * Don't log this under all conditions 3077abb0f93cSkardel */ 3078abb0f93cSkardel if (turn_off_reuse == 0 3079abb0f93cSkardel #ifdef DEBUG 3080abb0f93cSkardel || debug > 1 3081abb0f93cSkardel #endif 3082abb0f93cSkardel ) { 3083abb0f93cSkardel msyslog(LOG_ERR, 3084*eabc0478Schristos "bind(%d) AF_INET%s %s%s flags 0x%x failed: %m", 3085abb0f93cSkardel fd, IS_IPV6(addr) ? "6" : "", 3086*eabc0478Schristos sptoa(addr), 3087abb0f93cSkardel IS_MCAST(addr) ? " (multicast)" : "", 3088abb0f93cSkardel interf->flags); 3089abb0f93cSkardel } 3090abb0f93cSkardel 3091abb0f93cSkardel closesocket(fd); 3092abb0f93cSkardel 3093abb0f93cSkardel return INVALID_SOCKET; 3094abb0f93cSkardel } 3095abb0f93cSkardel 3096abb0f93cSkardel #ifdef HAVE_TIMESTAMP 3097abb0f93cSkardel { 3098abb0f93cSkardel if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, 30994eea345dSchristos (void *)&on, sizeof(on))) 3100abb0f93cSkardel msyslog(LOG_DEBUG, 3101abb0f93cSkardel "setsockopt SO_TIMESTAMP on fails on address %s: %m", 3102abb0f93cSkardel stoa(addr)); 3103abb0f93cSkardel else 3104abb0f93cSkardel DPRINTF(4, ("setsockopt SO_TIMESTAMP enabled on fd %d address %s\n", 3105abb0f93cSkardel fd, stoa(addr))); 3106abb0f93cSkardel } 3107abb0f93cSkardel #endif 31082950cc38Schristos #ifdef HAVE_TIMESTAMPNS 31092950cc38Schristos { 31102950cc38Schristos if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS, 31114eea345dSchristos (void *)&on, sizeof(on))) 31122950cc38Schristos msyslog(LOG_DEBUG, 31132950cc38Schristos "setsockopt SO_TIMESTAMPNS on fails on address %s: %m", 31142950cc38Schristos stoa(addr)); 31152950cc38Schristos else 31162950cc38Schristos DPRINTF(4, ("setsockopt SO_TIMESTAMPNS enabled on fd %d address %s\n", 31172950cc38Schristos fd, stoa(addr))); 31182950cc38Schristos } 31192950cc38Schristos #endif 31202950cc38Schristos #ifdef HAVE_BINTIME 31212950cc38Schristos { 31222950cc38Schristos if (setsockopt(fd, SOL_SOCKET, SO_BINTIME, 31234eea345dSchristos (void *)&on, sizeof(on))) 31242950cc38Schristos msyslog(LOG_DEBUG, 31252950cc38Schristos "setsockopt SO_BINTIME on fails on address %s: %m", 31262950cc38Schristos stoa(addr)); 31272950cc38Schristos else 31282950cc38Schristos DPRINTF(4, ("setsockopt SO_BINTIME enabled on fd %d address %s\n", 31292950cc38Schristos fd, stoa(addr))); 31302950cc38Schristos } 31312950cc38Schristos #endif 31322950cc38Schristos 3133*eabc0478Schristos DPRINTF(4, ("bind(%d) addr %s, flags 0x%x\n", 3134*eabc0478Schristos fd, sptoa(addr), interf->flags)); 3135abb0f93cSkardel 31362950cc38Schristos make_socket_nonblocking(fd); 3137abb0f93cSkardel 3138abb0f93cSkardel #ifdef HAVE_SIGNALED_IO 3139abb0f93cSkardel init_socket_sig(fd); 3140abb0f93cSkardel #endif /* not HAVE_SIGNALED_IO */ 3141abb0f93cSkardel 3142abb0f93cSkardel add_fd_to_list(fd, FD_TYPE_SOCKET); 3143abb0f93cSkardel 3144abb0f93cSkardel #if !defined(SYS_WINNT) && !defined(VMS) 3145abb0f93cSkardel DPRINTF(4, ("flags for fd %d: 0x%x\n", fd, 3146abb0f93cSkardel fcntl(fd, F_GETFL, 0))); 3147abb0f93cSkardel #endif /* SYS_WINNT || VMS */ 3148abb0f93cSkardel 3149abb0f93cSkardel #if defined(HAVE_IO_COMPLETION_PORT) 3150abb0f93cSkardel /* 3151abb0f93cSkardel * Add the socket to the completion port 3152abb0f93cSkardel */ 315368dbbb44Schristos if (!io_completion_port_add_socket(fd, interf, bcast)) { 3154abb0f93cSkardel msyslog(LOG_ERR, "unable to set up io completion port - EXITING"); 3155abb0f93cSkardel exit(1); 3156abb0f93cSkardel } 3157abb0f93cSkardel #endif 3158abb0f93cSkardel return fd; 3159abb0f93cSkardel } 3160abb0f93cSkardel 31613123f114Skardel 31623123f114Skardel 3163abb0f93cSkardel /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 3164abb0f93cSkardel /* 3165*eabc0478Schristos * sendpkt - send a packet to the specified destination from the given endpt 3166*eabc0478Schristos * except for multicast, which may be sent from several addresses. 3167abb0f93cSkardel */ 3168abb0f93cSkardel void 3169abb0f93cSkardel sendpkt( 3170abb0f93cSkardel sockaddr_u * dest, 3171*eabc0478Schristos endpt * ep, 3172abb0f93cSkardel int ttl, 3173abb0f93cSkardel struct pkt * pkt, 3174abb0f93cSkardel int len 3175abb0f93cSkardel ) 3176abb0f93cSkardel { 31773123f114Skardel endpt * src; 31783123f114Skardel int ismcast; 3179abb0f93cSkardel int cc; 31803123f114Skardel int rc; 31813123f114Skardel u_char cttl; 3182cdfa2a7eSchristos l_fp fp_zero = { { 0 }, 0 }; 3183cdfa2a7eSchristos l_fp org, rec, xmt; 3184abb0f93cSkardel 31853123f114Skardel ismcast = IS_MCAST(dest); 3186*eabc0478Schristos if (!ismcast) { 31873123f114Skardel src = ep; 3188*eabc0478Schristos } else { 3189*eabc0478Schristos #ifndef MCAST 3190*eabc0478Schristos return; 3191*eabc0478Schristos #endif 31923123f114Skardel src = (IS_IPV4(dest)) 31933123f114Skardel ? mc4_list 31943123f114Skardel : mc6_list; 3195*eabc0478Schristos } 31963123f114Skardel 31973123f114Skardel if (NULL == src) { 3198abb0f93cSkardel /* 3199abb0f93cSkardel * unbound peer - drop request and wait for better 3200abb0f93cSkardel * network conditions 3201abb0f93cSkardel */ 3202abb0f93cSkardel DPRINTF(2, ("%ssendpkt(dst=%s, ttl=%d, len=%d): no interface - IGNORED\n", 32033123f114Skardel ismcast ? "\tMCAST\t***** " : "", 3204abb0f93cSkardel stoa(dest), ttl, len)); 3205abb0f93cSkardel return; 3206abb0f93cSkardel } 3207abb0f93cSkardel 32083123f114Skardel do { 3209*eabc0478Schristos if (INT_LL_OF_GLOB & src->flags) { 3210*eabc0478Schristos /* avoid duplicate multicasts on same IPv6 net */ 3211*eabc0478Schristos goto loop; 3212*eabc0478Schristos } 3213abb0f93cSkardel DPRINTF(2, ("%ssendpkt(%d, dst=%s, src=%s, ttl=%d, len=%d)\n", 32143123f114Skardel ismcast ? "\tMCAST\t***** " : "", src->fd, 32153123f114Skardel stoa(dest), stoa(&src->sin), ttl, len)); 3216abb0f93cSkardel #ifdef MCAST 32173123f114Skardel if (ismcast && ttl > 0 && ttl != src->last_ttl) { 3218abb0f93cSkardel /* 3219abb0f93cSkardel * set the multicast ttl for outgoing packets 3220abb0f93cSkardel */ 32213123f114Skardel switch (AF(&src->sin)) { 3222abb0f93cSkardel 3223abb0f93cSkardel case AF_INET : 3224abb0f93cSkardel cttl = (u_char)ttl; 32253123f114Skardel rc = setsockopt(src->fd, IPPROTO_IP, 3226abb0f93cSkardel IP_MULTICAST_TTL, 32273123f114Skardel (void *)&cttl, 32283123f114Skardel sizeof(cttl)); 3229abb0f93cSkardel break; 3230abb0f93cSkardel 3231abb0f93cSkardel # ifdef INCLUDE_IPV6_SUPPORT 3232abb0f93cSkardel case AF_INET6 : 32333123f114Skardel rc = setsockopt(src->fd, IPPROTO_IPV6, 3234abb0f93cSkardel IPV6_MULTICAST_HOPS, 32353123f114Skardel (void *)&ttl, 32363123f114Skardel sizeof(ttl)); 3237abb0f93cSkardel break; 3238abb0f93cSkardel # endif /* INCLUDE_IPV6_SUPPORT */ 3239abb0f93cSkardel 32403123f114Skardel default: 32413123f114Skardel rc = 0; 3242abb0f93cSkardel } 3243abb0f93cSkardel 32443123f114Skardel if (!rc) 32453123f114Skardel src->last_ttl = ttl; 3246abb0f93cSkardel else 3247abb0f93cSkardel msyslog(LOG_ERR, 3248abb0f93cSkardel "setsockopt IP_MULTICAST_TTL/IPV6_MULTICAST_HOPS fails on address %s: %m", 32493123f114Skardel stoa(&src->sin)); 3250abb0f93cSkardel } 3251abb0f93cSkardel #endif /* MCAST */ 3252abb0f93cSkardel 3253abb0f93cSkardel #ifdef SIM 32543123f114Skardel cc = simulate_server(dest, src, pkt); 325568dbbb44Schristos #elif defined(HAVE_IO_COMPLETION_PORT) 325668dbbb44Schristos cc = io_completion_port_sendto(src, src->fd, pkt, 3257*eabc0478Schristos (size_t)len, dest); 32583123f114Skardel #else 32593123f114Skardel cc = sendto(src->fd, (char *)pkt, (u_int)len, 0, 32603123f114Skardel &dest->sa, SOCKLEN(dest)); 3261abb0f93cSkardel #endif 32623123f114Skardel if (cc == -1) { 32633123f114Skardel src->notsent++; 3264abb0f93cSkardel packets_notsent++; 3265abb0f93cSkardel } else { 32663123f114Skardel src->sent++; 3267abb0f93cSkardel packets_sent++; 3268abb0f93cSkardel } 3269*eabc0478Schristos loop: 32703123f114Skardel if (ismcast) 32713123f114Skardel src = src->mclink; 32723123f114Skardel } while (ismcast && src != NULL); 32734eea345dSchristos 32744eea345dSchristos /* HMS: pkt->rootdisp is usually random here */ 3275cdfa2a7eSchristos NTOHL_FP(&pkt->org, &org); 3276cdfa2a7eSchristos NTOHL_FP(&pkt->rec, &rec); 3277cdfa2a7eSchristos NTOHL_FP(&pkt->xmt, &xmt); 32784eea345dSchristos record_raw_stats(src ? &src->sin : NULL, dest, 3279cdfa2a7eSchristos &org, &rec, &xmt, &fp_zero, 32804eea345dSchristos PKT_LEAP(pkt->li_vn_mode), 3281cdfa2a7eSchristos PKT_VERSION(pkt->li_vn_mode), 3282cdfa2a7eSchristos PKT_MODE(pkt->li_vn_mode), 32834eea345dSchristos pkt->stratum, 32844eea345dSchristos pkt->ppoll, pkt->precision, 3285*eabc0478Schristos FPTOD(NTOHS_FP(pkt->rootdelay)), 3286*eabc0478Schristos FPTOD(NTOHS_FP(pkt->rootdisp)), pkt->refid, 32874eea345dSchristos len - MIN_V4_PKT_LEN, (u_char *)&pkt->exten); 3288abb0f93cSkardel } 3289abb0f93cSkardel 3290abb0f93cSkardel 3291abb0f93cSkardel #if !defined(HAVE_IO_COMPLETION_PORT) 329268dbbb44Schristos #if !defined(HAVE_SIGNALED_IO) 3293abb0f93cSkardel /* 3294abb0f93cSkardel * fdbits - generate ascii representation of fd_set (FAU debug support) 3295abb0f93cSkardel * HFDF format - highest fd first. 3296abb0f93cSkardel */ 3297abb0f93cSkardel static char * 3298abb0f93cSkardel fdbits( 3299abb0f93cSkardel int count, 330068dbbb44Schristos const fd_set* set 3301abb0f93cSkardel ) 3302abb0f93cSkardel { 3303abb0f93cSkardel static char buffer[256]; 3304abb0f93cSkardel char * buf = buffer; 3305abb0f93cSkardel 3306*eabc0478Schristos count = min(count, sizeof(buffer) - 1); 3307abb0f93cSkardel 3308abb0f93cSkardel while (count >= 0) { 3309abb0f93cSkardel *buf++ = FD_ISSET(count, set) ? '#' : '-'; 3310abb0f93cSkardel count--; 3311abb0f93cSkardel } 3312abb0f93cSkardel *buf = '\0'; 3313abb0f93cSkardel 3314abb0f93cSkardel return buffer; 3315abb0f93cSkardel } 331668dbbb44Schristos #endif 33172950cc38Schristos 33182950cc38Schristos #ifdef REFCLOCK 3319abb0f93cSkardel /* 3320abb0f93cSkardel * Routine to read the refclock packets for a specific interface 3321abb0f93cSkardel * Return the number of bytes read. That way we know if we should 3322abb0f93cSkardel * read it again or go on to the next one if no bytes returned 3323abb0f93cSkardel */ 3324abb0f93cSkardel static inline int 33252950cc38Schristos read_refclock_packet( 33262950cc38Schristos SOCKET fd, 33272950cc38Schristos struct refclockio * rp, 33282950cc38Schristos l_fp ts 33292950cc38Schristos ) 3330abb0f93cSkardel { 3331af12ab5eSchristos u_int read_count; 3332abb0f93cSkardel int buflen; 33332950cc38Schristos int saved_errno; 33342950cc38Schristos int consumed; 33352950cc38Schristos struct recvbuf * rb; 3336abb0f93cSkardel 333750c1baceSchristos rb = get_free_recv_buffer(TRUE); 3338abb0f93cSkardel 3339abb0f93cSkardel if (NULL == rb) { 3340abb0f93cSkardel /* 334150c1baceSchristos * No buffer space available - just drop the 'packet'. 334250c1baceSchristos * Since this is a non-blocking character stream we read 334350c1baceSchristos * all data that we can. 334450c1baceSchristos * 334550c1baceSchristos * ...hmmmm... what about "tcflush(fd,TCIFLUSH)" here?!? 3346abb0f93cSkardel */ 334750c1baceSchristos char buf[128]; 334850c1baceSchristos do 334950c1baceSchristos buflen = read(fd, buf, sizeof(buf)); 335050c1baceSchristos while (buflen > 0); 3351abb0f93cSkardel packets_dropped++; 3352abb0f93cSkardel return (buflen); 3353abb0f93cSkardel } 3354abb0f93cSkardel 3355af12ab5eSchristos /* TALOS-CAN-0064: avoid signed/unsigned clashes that can lead 3356af12ab5eSchristos * to buffer overrun and memory corruption 3357af12ab5eSchristos */ 3358af12ab5eSchristos if (rp->datalen <= 0 || (size_t)rp->datalen > sizeof(rb->recv_space)) 3359af12ab5eSchristos read_count = sizeof(rb->recv_space); 3360af12ab5eSchristos else 3361af12ab5eSchristos read_count = (u_int)rp->datalen; 33622950cc38Schristos do { 3363af12ab5eSchristos buflen = read(fd, (char *)&rb->recv_space, read_count); 33642950cc38Schristos } while (buflen < 0 && EINTR == errno); 3365abb0f93cSkardel 33662950cc38Schristos if (buflen <= 0) { 33672950cc38Schristos saved_errno = errno; 3368abb0f93cSkardel freerecvbuf(rb); 33692950cc38Schristos errno = saved_errno; 33702950cc38Schristos return buflen; 3371abb0f93cSkardel } 3372abb0f93cSkardel 3373abb0f93cSkardel /* 3374abb0f93cSkardel * Got one. Mark how and when it got here, 3375abb0f93cSkardel * put it on the full list and do bookkeeping. 3376abb0f93cSkardel */ 3377abb0f93cSkardel rb->recv_length = buflen; 33782950cc38Schristos rb->recv_peer = rp->srcclock; 3379*eabc0478Schristos rb->dstadr = NULL; 3380abb0f93cSkardel rb->fd = fd; 3381abb0f93cSkardel rb->recv_time = ts; 3382abb0f93cSkardel rb->receiver = rp->clock_recv; 3383abb0f93cSkardel 33842950cc38Schristos consumed = indicate_refclock_packet(rp, rb); 33852950cc38Schristos if (!consumed) { 3386abb0f93cSkardel rp->recvcount++; 3387abb0f93cSkardel packets_received++; 3388abb0f93cSkardel } 3389abb0f93cSkardel 33902950cc38Schristos return buflen; 33912950cc38Schristos } 33922950cc38Schristos #endif /* REFCLOCK */ 3393abb0f93cSkardel 33942950cc38Schristos 33952950cc38Schristos #ifdef HAVE_PACKET_TIMESTAMP 3396abb0f93cSkardel /* 3397abb0f93cSkardel * extract timestamps from control message buffer 3398abb0f93cSkardel */ 3399abb0f93cSkardel static l_fp 3400abb0f93cSkardel fetch_timestamp( 3401abb0f93cSkardel struct recvbuf * rb, 3402abb0f93cSkardel struct msghdr * msghdr, 3403abb0f93cSkardel l_fp ts 3404abb0f93cSkardel ) 3405abb0f93cSkardel { 3406abb0f93cSkardel struct cmsghdr * cmsghdr; 34072950cc38Schristos unsigned long ticks; 34082950cc38Schristos double fuzz; 34092950cc38Schristos l_fp lfpfuzz; 34102950cc38Schristos l_fp nts; 34112950cc38Schristos #ifdef DEBUG_TIMING 34122950cc38Schristos l_fp dts; 34132950cc38Schristos #endif 3414abb0f93cSkardel 3415abb0f93cSkardel cmsghdr = CMSG_FIRSTHDR(msghdr); 3416abb0f93cSkardel while (cmsghdr != NULL) { 3417abb0f93cSkardel switch (cmsghdr->cmsg_type) 3418abb0f93cSkardel { 34192950cc38Schristos #ifdef HAVE_BINTIME 34202950cc38Schristos case SCM_BINTIME: 34212950cc38Schristos #endif /* HAVE_BINTIME */ 34222950cc38Schristos #ifdef HAVE_TIMESTAMPNS 34232950cc38Schristos case SCM_TIMESTAMPNS: 34242950cc38Schristos #endif /* HAVE_TIMESTAMPNS */ 34252950cc38Schristos #ifdef HAVE_TIMESTAMP 3426abb0f93cSkardel case SCM_TIMESTAMP: 34272950cc38Schristos #endif /* HAVE_TIMESTAMP */ 34282950cc38Schristos #if defined(HAVE_BINTIME) || defined (HAVE_TIMESTAMPNS) || defined(HAVE_TIMESTAMP) 34292950cc38Schristos switch (cmsghdr->cmsg_type) 3430abb0f93cSkardel { 34312950cc38Schristos #ifdef HAVE_BINTIME 34322950cc38Schristos case SCM_BINTIME: 3433717847f5Schristos { 3434717847f5Schristos struct bintime pbt; 3435717847f5Schristos memcpy(&pbt, CMSG_DATA(cmsghdr), sizeof(pbt)); 34362950cc38Schristos /* 34372950cc38Schristos * bintime documentation is at http://phk.freebsd.dk/pubs/timecounter.pdf 34382950cc38Schristos */ 3439717847f5Schristos nts.l_i = pbt.sec + JAN_1970; 3440717847f5Schristos nts.l_uf = (u_int32)(pbt.frac >> 32); 34412950cc38Schristos if (sys_tick > measured_tick && 34422950cc38Schristos sys_tick > 1e-9) { 34432950cc38Schristos ticks = (unsigned long)(nts.l_uf / (unsigned long)(sys_tick * FRAC)); 34442950cc38Schristos nts.l_uf = (unsigned long)(ticks * (unsigned long)(sys_tick * FRAC)); 34452950cc38Schristos } 34462950cc38Schristos DPRINTF(4, ("fetch_timestamp: system bintime network time stamp: %ld.%09lu\n", 3447*eabc0478Schristos (long)pbt.sec, (u_long)((nts.l_uf / FRAC) * 1e9))); 3448717847f5Schristos } 34492950cc38Schristos break; 34502950cc38Schristos #endif /* HAVE_BINTIME */ 34512950cc38Schristos #ifdef HAVE_TIMESTAMPNS 34522950cc38Schristos case SCM_TIMESTAMPNS: 3453717847f5Schristos { 3454717847f5Schristos struct timespec pts; 3455717847f5Schristos memcpy(&pts, CMSG_DATA(cmsghdr), sizeof(pts)); 34562950cc38Schristos if (sys_tick > measured_tick && 34572950cc38Schristos sys_tick > 1e-9) { 3458717847f5Schristos ticks = (unsigned long)((pts.tv_nsec * 1e-9) / 34592950cc38Schristos sys_tick); 3460717847f5Schristos pts.tv_nsec = (long)(ticks * 1e9 * 34612950cc38Schristos sys_tick); 34622950cc38Schristos } 34632950cc38Schristos DPRINTF(4, ("fetch_timestamp: system nsec network time stamp: %ld.%09ld\n", 3464717847f5Schristos pts.tv_sec, pts.tv_nsec)); 3465717847f5Schristos nts = tspec_stamp_to_lfp(pts); 3466717847f5Schristos } 34672950cc38Schristos break; 34682950cc38Schristos #endif /* HAVE_TIMESTAMPNS */ 34692950cc38Schristos #ifdef HAVE_TIMESTAMP 34702950cc38Schristos case SCM_TIMESTAMP: 3471717847f5Schristos { 3472717847f5Schristos struct timeval ptv; 3473717847f5Schristos memcpy(&ptv, CMSG_DATA(cmsghdr), sizeof(ptv)); 34742950cc38Schristos if (sys_tick > measured_tick && 34752950cc38Schristos sys_tick > 1e-6) { 3476717847f5Schristos ticks = (unsigned long)((ptv.tv_usec * 1e-6) / 34772950cc38Schristos sys_tick); 3478717847f5Schristos ptv.tv_usec = (long)(ticks * 1e6 * 34792950cc38Schristos sys_tick); 34802950cc38Schristos } 3481966c0b1bSchristos DPRINTF(4, ("fetch_timestamp: system usec network time stamp: %jd.%06ld\n", 3482717847f5Schristos (intmax_t)ptv.tv_sec, (long)ptv.tv_usec)); 3483717847f5Schristos nts = tval_stamp_to_lfp(ptv); 3484717847f5Schristos } 34852950cc38Schristos break; 34862950cc38Schristos #endif /* HAVE_TIMESTAMP */ 34872950cc38Schristos } 3488*eabc0478Schristos fuzz = ntp_uurandom() * sys_fuzz; 34892950cc38Schristos DTOLFP(fuzz, &lfpfuzz); 34902950cc38Schristos L_ADD(&nts, &lfpfuzz); 3491abb0f93cSkardel #ifdef DEBUG_TIMING 3492abb0f93cSkardel dts = ts; 3493abb0f93cSkardel L_SUB(&dts, &nts); 34942950cc38Schristos collect_timing(rb, "input processing delay", 1, 34952950cc38Schristos &dts); 34962950cc38Schristos DPRINTF(4, ("fetch_timestamp: timestamp delta: %s (incl. fuzz)\n", 3497abb0f93cSkardel lfptoa(&dts, 9))); 34982950cc38Schristos #endif /* DEBUG_TIMING */ 3499abb0f93cSkardel ts = nts; /* network time stamp */ 3500abb0f93cSkardel break; 35012950cc38Schristos #endif /* HAVE_BINTIME || HAVE_TIMESTAMPNS || HAVE_TIMESTAMP */ 35022950cc38Schristos 3503abb0f93cSkardel default: 3504abb0f93cSkardel DPRINTF(4, ("fetch_timestamp: skipping control message 0x%x\n", 3505abb0f93cSkardel cmsghdr->cmsg_type)); 3506abb0f93cSkardel } 3507abb0f93cSkardel cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr); 3508abb0f93cSkardel } 3509abb0f93cSkardel return ts; 3510abb0f93cSkardel } 35112950cc38Schristos #endif /* HAVE_PACKET_TIMESTAMP */ 3512abb0f93cSkardel 3513abb0f93cSkardel 3514abb0f93cSkardel /* 3515abb0f93cSkardel * Routine to read the network NTP packets for a specific interface 3516abb0f93cSkardel * Return the number of bytes read. That way we know if we should 3517abb0f93cSkardel * read it again or go on to the next one if no bytes returned 3518abb0f93cSkardel */ 3519abb0f93cSkardel static inline int 3520abb0f93cSkardel read_network_packet( 3521abb0f93cSkardel SOCKET fd, 3522*eabc0478Schristos endpt * itf, 3523abb0f93cSkardel l_fp ts 3524abb0f93cSkardel ) 3525abb0f93cSkardel { 3526abb0f93cSkardel GETSOCKNAME_SOCKLEN_TYPE fromlen; 3527abb0f93cSkardel int buflen; 3528abb0f93cSkardel register struct recvbuf *rb; 35292950cc38Schristos #ifdef HAVE_PACKET_TIMESTAMP 3530abb0f93cSkardel struct msghdr msghdr; 3531abb0f93cSkardel struct iovec iovec; 35322950cc38Schristos char control[CMSG_BUFSIZE]; 3533abb0f93cSkardel #endif 3534abb0f93cSkardel 3535abb0f93cSkardel /* 353650c1baceSchristos * Get a buffer and read the frame. If we haven't got a buffer, 353750c1baceSchristos * or this is received on a disallowed socket, just dump the 3538abb0f93cSkardel * packet. 3539abb0f93cSkardel */ 3540abb0f93cSkardel 354150c1baceSchristos rb = itf->ignore_packets ? NULL : get_free_recv_buffer(FALSE); 354250c1baceSchristos if (NULL == rb) { 354350c1baceSchristos /* A partial read on a UDP socket truncates the data and 354450c1baceSchristos * removes the message from the queue. So there's no 354550c1baceSchristos * need to have a full buffer here on the stack. 354650c1baceSchristos */ 354750c1baceSchristos char buf[16]; 3548abb0f93cSkardel sockaddr_u from; 3549abb0f93cSkardel 3550abb0f93cSkardel if (rb != NULL) 3551abb0f93cSkardel freerecvbuf(rb); 3552abb0f93cSkardel 3553abb0f93cSkardel fromlen = sizeof(from); 3554abb0f93cSkardel buflen = recvfrom(fd, buf, sizeof(buf), 0, 3555abb0f93cSkardel &from.sa, &fromlen); 3556abb0f93cSkardel DPRINTF(4, ("%s on (%lu) fd=%d from %s\n", 3557abb0f93cSkardel (itf->ignore_packets) 3558abb0f93cSkardel ? "ignore" 3559abb0f93cSkardel : "drop", 3560abb0f93cSkardel free_recvbuffs(), fd, stoa(&from))); 3561abb0f93cSkardel if (itf->ignore_packets) 3562abb0f93cSkardel packets_ignored++; 3563abb0f93cSkardel else 3564abb0f93cSkardel packets_dropped++; 3565abb0f93cSkardel return (buflen); 3566abb0f93cSkardel } 3567abb0f93cSkardel 3568abb0f93cSkardel fromlen = sizeof(rb->recv_srcadr); 3569abb0f93cSkardel 35702950cc38Schristos #ifndef HAVE_PACKET_TIMESTAMP 3571abb0f93cSkardel rb->recv_length = recvfrom(fd, (char *)&rb->recv_space, 3572abb0f93cSkardel sizeof(rb->recv_space), 0, 3573abb0f93cSkardel &rb->recv_srcadr.sa, &fromlen); 3574abb0f93cSkardel #else 3575abb0f93cSkardel iovec.iov_base = &rb->recv_space; 3576abb0f93cSkardel iovec.iov_len = sizeof(rb->recv_space); 3577abb0f93cSkardel msghdr.msg_name = &rb->recv_srcadr; 3578abb0f93cSkardel msghdr.msg_namelen = fromlen; 3579abb0f93cSkardel msghdr.msg_iov = &iovec; 3580abb0f93cSkardel msghdr.msg_iovlen = 1; 3581abb0f93cSkardel msghdr.msg_control = (void *)&control; 3582abb0f93cSkardel msghdr.msg_controllen = sizeof(control); 3583abb0f93cSkardel msghdr.msg_flags = 0; 3584abb0f93cSkardel rb->recv_length = recvmsg(fd, &msghdr, 0); 3585abb0f93cSkardel #endif 3586abb0f93cSkardel 3587abb0f93cSkardel buflen = rb->recv_length; 3588abb0f93cSkardel 3589abb0f93cSkardel if (buflen == 0 || (buflen == -1 && 3590abb0f93cSkardel (EWOULDBLOCK == errno 3591abb0f93cSkardel #ifdef EAGAIN 3592abb0f93cSkardel || EAGAIN == errno 3593abb0f93cSkardel #endif 3594abb0f93cSkardel ))) { 3595abb0f93cSkardel freerecvbuf(rb); 3596abb0f93cSkardel return (buflen); 3597abb0f93cSkardel } else if (buflen < 0) { 3598abb0f93cSkardel msyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m", 3599abb0f93cSkardel stoa(&rb->recv_srcadr), fd); 3600abb0f93cSkardel DPRINTF(5, ("read_network_packet: fd=%d dropped (bad recvfrom)\n", 3601abb0f93cSkardel fd)); 3602abb0f93cSkardel freerecvbuf(rb); 3603abb0f93cSkardel return (buflen); 3604abb0f93cSkardel } 3605abb0f93cSkardel 3606abb0f93cSkardel DPRINTF(3, ("read_network_packet: fd=%d length %d from %s\n", 3607abb0f93cSkardel fd, buflen, stoa(&rb->recv_srcadr))); 3608abb0f93cSkardel 360968dbbb44Schristos #ifdef ENABLE_BUG3020_FIX 361068dbbb44Schristos if (ISREFCLOCKADR(&rb->recv_srcadr)) { 361168dbbb44Schristos msyslog(LOG_ERR, "recvfrom(%s) fd=%d: refclock srcadr on a network interface!", 361268dbbb44Schristos stoa(&rb->recv_srcadr), fd); 361368dbbb44Schristos DPRINTF(1, ("read_network_packet: fd=%d dropped (refclock srcadr))\n", 361468dbbb44Schristos fd)); 361568dbbb44Schristos packets_dropped++; 361668dbbb44Schristos freerecvbuf(rb); 361768dbbb44Schristos return (buflen); 361868dbbb44Schristos } 361968dbbb44Schristos #endif 362068dbbb44Schristos 3621abb0f93cSkardel /* 3622ea66d795Schristos ** Bug 2672: Some OSes (MacOSX and Linux) don't block spoofed ::1 3623ea66d795Schristos */ 3624ea66d795Schristos 3625*eabc0478Schristos if ( IS_IPV6(&rb->recv_srcadr) 3626*eabc0478Schristos && IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&rb->recv_srcadr)) 3627*eabc0478Schristos && !(INT_LOOPBACK & itf->flags)) { 3628ea66d795Schristos 3629ea66d795Schristos packets_dropped++; 3630*eabc0478Schristos DPRINTF(2, ("DROPPING pkt with spoofed ::1 source on %s\n", latoa(itf))); 3631ea66d795Schristos freerecvbuf(rb); 3632*eabc0478Schristos return -1; 36337476e6e4Schristos } 3634ea66d795Schristos 3635ea66d795Schristos /* 3636abb0f93cSkardel * Got one. Mark how and when it got here, 3637abb0f93cSkardel * put it on the full list and do bookkeeping. 3638abb0f93cSkardel */ 3639abb0f93cSkardel rb->dstadr = itf; 3640abb0f93cSkardel rb->fd = fd; 36412950cc38Schristos #ifdef HAVE_PACKET_TIMESTAMP 3642abb0f93cSkardel /* pick up a network time stamp if possible */ 3643abb0f93cSkardel ts = fetch_timestamp(rb, &msghdr, ts); 3644abb0f93cSkardel #endif 3645abb0f93cSkardel rb->recv_time = ts; 3646abb0f93cSkardel rb->receiver = receive; 3647abb0f93cSkardel 3648abb0f93cSkardel add_full_recv_buffer(rb); 3649abb0f93cSkardel 3650abb0f93cSkardel itf->received++; 3651abb0f93cSkardel packets_received++; 3652abb0f93cSkardel return (buflen); 3653abb0f93cSkardel } 3654abb0f93cSkardel 36552950cc38Schristos /* 36562950cc38Schristos * attempt to handle io (select()/signaled IO) 36572950cc38Schristos */ 36582950cc38Schristos void 36592950cc38Schristos io_handler(void) 36602950cc38Schristos { 36612950cc38Schristos # ifndef HAVE_SIGNALED_IO 36622950cc38Schristos fd_set rdfdes; 36632950cc38Schristos int nfound; 36642950cc38Schristos 36652950cc38Schristos /* 36662950cc38Schristos * Use select() on all on all input fd's for unlimited 36672950cc38Schristos * time. select() will terminate on SIGALARM or on the 36682950cc38Schristos * reception of input. Using select() means we can't do 36692950cc38Schristos * robust signal handling and we get a potential race 36702950cc38Schristos * between checking for alarms and doing the select(). 36712950cc38Schristos * Mostly harmless, I think. 36722950cc38Schristos */ 36732950cc38Schristos /* 36742950cc38Schristos * On VMS, I suspect that select() can't be interrupted 36752950cc38Schristos * by a "signal" either, so I take the easy way out and 36762950cc38Schristos * have select() time out after one second. 36772950cc38Schristos * System clock updates really aren't time-critical, 36782950cc38Schristos * and - lacking a hardware reference clock - I have 36792950cc38Schristos * yet to learn about anything else that is. 36802950cc38Schristos */ 368168dbbb44Schristos ++handler_calls; 36822950cc38Schristos rdfdes = activefds; 36832950cc38Schristos # if !defined(VMS) && !defined(SYS_VXWORKS) 36842950cc38Schristos nfound = select(maxactivefd + 1, &rdfdes, NULL, 36852950cc38Schristos NULL, NULL); 36862950cc38Schristos # else /* VMS, VxWorks */ 36872950cc38Schristos /* make select() wake up after one second */ 36882950cc38Schristos { 36892950cc38Schristos struct timeval t1; 36902950cc38Schristos t1.tv_sec = 1; 36912950cc38Schristos t1.tv_usec = 0; 36922950cc38Schristos nfound = select(maxactivefd + 1, 36932950cc38Schristos &rdfdes, NULL, NULL, 36942950cc38Schristos &t1); 36952950cc38Schristos } 36962950cc38Schristos # endif /* VMS, VxWorks */ 369768dbbb44Schristos if (nfound < 0 && sanitize_fdset(errno)) { 369868dbbb44Schristos struct timeval t1; 369968dbbb44Schristos t1.tv_sec = 0; 370068dbbb44Schristos t1.tv_usec = 0; 370168dbbb44Schristos rdfdes = activefds; 370268dbbb44Schristos nfound = select(maxactivefd + 1, 370368dbbb44Schristos &rdfdes, NULL, NULL, 370468dbbb44Schristos &t1); 370568dbbb44Schristos } 370668dbbb44Schristos 37072950cc38Schristos if (nfound > 0) { 37082950cc38Schristos l_fp ts; 37092950cc38Schristos 37102950cc38Schristos get_systime(&ts); 37112950cc38Schristos 371268dbbb44Schristos input_handler_scan(&ts, &rdfdes); 37132950cc38Schristos } else if (nfound == -1 && errno != EINTR) { 37142950cc38Schristos msyslog(LOG_ERR, "select() error: %m"); 37152950cc38Schristos } 37162950cc38Schristos # ifdef DEBUG 37172950cc38Schristos else if (debug > 4) { 37182950cc38Schristos msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound); 37192950cc38Schristos } else { 37205d681e99Schristos DPRINTF(3, ("select() returned %d: %m\n", nfound)); 37212950cc38Schristos } 37222950cc38Schristos # endif /* DEBUG */ 37232950cc38Schristos # else /* HAVE_SIGNALED_IO */ 37242950cc38Schristos wait_for_signal(); 37252950cc38Schristos # endif /* HAVE_SIGNALED_IO */ 37262950cc38Schristos } 3727abb0f93cSkardel 372868dbbb44Schristos #ifdef HAVE_SIGNALED_IO 3729abb0f93cSkardel /* 3730abb0f93cSkardel * input_handler - receive packets asynchronously 373168dbbb44Schristos * 373268dbbb44Schristos * ALWAYS IN SIGNAL HANDLER CONTEXT -- only async-safe functions allowed! 3733abb0f93cSkardel */ 373468dbbb44Schristos static RETSIGTYPE 3735abb0f93cSkardel input_handler( 3736abb0f93cSkardel l_fp * cts 3737abb0f93cSkardel ) 3738abb0f93cSkardel { 3739abb0f93cSkardel int n; 374068dbbb44Schristos struct timeval tvzero; 374168dbbb44Schristos fd_set fds; 374268dbbb44Schristos 374368dbbb44Schristos ++handler_calls; 374468dbbb44Schristos 374568dbbb44Schristos /* 374668dbbb44Schristos * Do a poll to see who has data 374768dbbb44Schristos */ 374868dbbb44Schristos 374968dbbb44Schristos fds = activefds; 375068dbbb44Schristos tvzero.tv_sec = tvzero.tv_usec = 0; 375168dbbb44Schristos 375268dbbb44Schristos n = select(maxactivefd + 1, &fds, NULL, NULL, &tvzero); 375368dbbb44Schristos if (n < 0 && sanitize_fdset(errno)) { 375468dbbb44Schristos fds = activefds; 375568dbbb44Schristos tvzero.tv_sec = tvzero.tv_usec = 0; 375668dbbb44Schristos n = select(maxactivefd + 1, &fds, NULL, NULL, &tvzero); 375768dbbb44Schristos } 375868dbbb44Schristos if (n > 0) 375968dbbb44Schristos input_handler_scan(cts, &fds); 376068dbbb44Schristos } 376168dbbb44Schristos #endif /* HAVE_SIGNALED_IO */ 376268dbbb44Schristos 376368dbbb44Schristos 376468dbbb44Schristos /* 376568dbbb44Schristos * Try to sanitize the global FD set 376668dbbb44Schristos * 376768dbbb44Schristos * SIGNAL HANDLER CONTEXT if HAVE_SIGNALED_IO, ordinary userspace otherwise 376868dbbb44Schristos */ 376968dbbb44Schristos static int/*BOOL*/ 377068dbbb44Schristos sanitize_fdset( 377168dbbb44Schristos int errc 377268dbbb44Schristos ) 377368dbbb44Schristos { 377468dbbb44Schristos int j, b, maxscan; 377568dbbb44Schristos 377668dbbb44Schristos # ifndef HAVE_SIGNALED_IO 377768dbbb44Schristos /* 377868dbbb44Schristos * extended FAU debugging output 377968dbbb44Schristos */ 378068dbbb44Schristos if (errc != EINTR) { 378168dbbb44Schristos msyslog(LOG_ERR, 378268dbbb44Schristos "select(%d, %s, 0L, 0L, &0.0) error: %m", 378368dbbb44Schristos maxactivefd + 1, 378468dbbb44Schristos fdbits(maxactivefd, &activefds)); 378568dbbb44Schristos } 378668dbbb44Schristos # endif 378768dbbb44Schristos 378868dbbb44Schristos if (errc != EBADF) 378968dbbb44Schristos return FALSE; 379068dbbb44Schristos 379168dbbb44Schristos /* if we have oviously bad FDs, try to sanitize the FD set. */ 379268dbbb44Schristos for (j = 0, maxscan = 0; j <= maxactivefd; j++) { 379368dbbb44Schristos if (FD_ISSET(j, &activefds)) { 379468dbbb44Schristos if (-1 != read(j, &b, 0)) { 379568dbbb44Schristos maxscan = j; 379668dbbb44Schristos continue; 379768dbbb44Schristos } 379868dbbb44Schristos # ifndef HAVE_SIGNALED_IO 379968dbbb44Schristos msyslog(LOG_ERR, 380068dbbb44Schristos "Removing bad file descriptor %d from select set", 380168dbbb44Schristos j); 380268dbbb44Schristos # endif 380368dbbb44Schristos FD_CLR(j, &activefds); 380468dbbb44Schristos } 380568dbbb44Schristos } 380668dbbb44Schristos if (maxactivefd != maxscan) 380768dbbb44Schristos maxactivefd = maxscan; 380868dbbb44Schristos return TRUE; 380968dbbb44Schristos } 381068dbbb44Schristos 381168dbbb44Schristos /* 381268dbbb44Schristos * scan the known FDs (clocks, servers, ...) for presence in a 'fd_set'. 381368dbbb44Schristos * 381468dbbb44Schristos * SIGNAL HANDLER CONTEXT if HAVE_SIGNALED_IO, ordinary userspace otherwise 381568dbbb44Schristos */ 381668dbbb44Schristos static void 381768dbbb44Schristos input_handler_scan( 381868dbbb44Schristos const l_fp * cts, 381968dbbb44Schristos const fd_set * pfds 382068dbbb44Schristos ) 382168dbbb44Schristos { 382268dbbb44Schristos int buflen; 38232950cc38Schristos u_int idx; 3824abb0f93cSkardel int doing; 3825abb0f93cSkardel SOCKET fd; 38262950cc38Schristos blocking_child *c; 3827abb0f93cSkardel l_fp ts; /* Timestamp at BOselect() gob */ 382868dbbb44Schristos 382968dbbb44Schristos #if defined(DEBUG_TIMING) 3830abb0f93cSkardel l_fp ts_e; /* Timestamp at EOselect() gob */ 3831abb0f93cSkardel #endif 38323123f114Skardel endpt * ep; 38332950cc38Schristos #ifdef REFCLOCK 38342950cc38Schristos struct refclockio *rp; 38352950cc38Schristos int saved_errno; 38362950cc38Schristos const char * clk; 38372950cc38Schristos #endif 38382950cc38Schristos #ifdef HAS_ROUTING_SOCKET 3839abb0f93cSkardel struct asyncio_reader * asyncio_reader; 38402950cc38Schristos struct asyncio_reader * next_asyncio_reader; 3841abb0f93cSkardel #endif 3842abb0f93cSkardel 3843abb0f93cSkardel ++handler_pkts; 384468dbbb44Schristos ts = *cts; 3845abb0f93cSkardel 3846abb0f93cSkardel #ifdef REFCLOCK 3847abb0f93cSkardel /* 3848abb0f93cSkardel * Check out the reference clocks first, if any 3849abb0f93cSkardel */ 3850abb0f93cSkardel 3851abb0f93cSkardel for (rp = refio; rp != NULL; rp = rp->next) { 3852abb0f93cSkardel fd = rp->fd; 3853abb0f93cSkardel 385468dbbb44Schristos if (!FD_ISSET(fd, pfds)) 38552950cc38Schristos continue; 38562950cc38Schristos buflen = read_refclock_packet(fd, rp, ts); 38572950cc38Schristos /* 385868dbbb44Schristos * The first read must succeed after select() indicates 385968dbbb44Schristos * readability, or we've reached a permanent EOF. 386068dbbb44Schristos * http://bugs.ntp.org/1732 reported ntpd munching CPU 386168dbbb44Schristos * after a USB GPS was unplugged because select was 386268dbbb44Schristos * indicating EOF but ntpd didn't remove the descriptor 38632950cc38Schristos * from the activefds set. 38642950cc38Schristos */ 38652950cc38Schristos if (buflen < 0 && EAGAIN != errno) { 38662950cc38Schristos saved_errno = errno; 38672950cc38Schristos clk = refnumtoa(&rp->srcclock->srcadr); 38682950cc38Schristos errno = saved_errno; 38692950cc38Schristos msyslog(LOG_ERR, "%s read: %m", clk); 38702950cc38Schristos maintain_activefds(fd, TRUE); 38712950cc38Schristos } else if (0 == buflen) { 38722950cc38Schristos clk = refnumtoa(&rp->srcclock->srcadr); 38732950cc38Schristos msyslog(LOG_ERR, "%s read EOF", clk); 38742950cc38Schristos maintain_activefds(fd, TRUE); 38752950cc38Schristos } else { 38762950cc38Schristos /* drain any remaining refclock input */ 38772950cc38Schristos do { 38782950cc38Schristos buflen = read_refclock_packet(fd, rp, ts); 3879abb0f93cSkardel } while (buflen > 0); 3880abb0f93cSkardel } 3881abb0f93cSkardel } 3882abb0f93cSkardel #endif /* REFCLOCK */ 3883abb0f93cSkardel 3884abb0f93cSkardel /* 3885abb0f93cSkardel * Loop through the interfaces looking for data to read. 3886abb0f93cSkardel */ 38873123f114Skardel for (ep = ep_list; ep != NULL; ep = ep->elink) { 38883123f114Skardel for (doing = 0; doing < 2; doing++) { 38893123f114Skardel if (!doing) { 38903123f114Skardel fd = ep->fd; 38913123f114Skardel } else { 38923123f114Skardel if (!(ep->flags & INT_BCASTOPEN)) 3893abb0f93cSkardel break; 38943123f114Skardel fd = ep->bfd; 3895abb0f93cSkardel } 3896abb0f93cSkardel if (fd < 0) 3897abb0f93cSkardel continue; 389868dbbb44Schristos if (FD_ISSET(fd, pfds)) 3899abb0f93cSkardel do { 3900abb0f93cSkardel buflen = read_network_packet( 39013123f114Skardel fd, ep, ts); 3902abb0f93cSkardel } while (buflen > 0); 3903abb0f93cSkardel /* Check more interfaces */ 3904abb0f93cSkardel } 3905abb0f93cSkardel } 3906abb0f93cSkardel 3907abb0f93cSkardel #ifdef HAS_ROUTING_SOCKET 3908abb0f93cSkardel /* 3909abb0f93cSkardel * scan list of asyncio readers - currently only used for routing sockets 3910abb0f93cSkardel */ 3911abb0f93cSkardel asyncio_reader = asyncio_reader_list; 3912abb0f93cSkardel 3913abb0f93cSkardel while (asyncio_reader != NULL) { 39142950cc38Schristos /* callback may unlink and free asyncio_reader */ 39152950cc38Schristos next_asyncio_reader = asyncio_reader->link; 391668dbbb44Schristos if (FD_ISSET(asyncio_reader->fd, pfds)) 39172950cc38Schristos (*asyncio_reader->receiver)(asyncio_reader); 39182950cc38Schristos asyncio_reader = next_asyncio_reader; 3919abb0f93cSkardel } 3920abb0f93cSkardel #endif /* HAS_ROUTING_SOCKET */ 3921abb0f93cSkardel 3922abb0f93cSkardel /* 39232950cc38Schristos * Check for a response from a blocking child 3924abb0f93cSkardel */ 39252950cc38Schristos for (idx = 0; idx < blocking_children_alloc; idx++) { 39262950cc38Schristos c = blocking_children[idx]; 39272950cc38Schristos if (NULL == c || -1 == c->resp_read_pipe) 39282950cc38Schristos continue; 392968dbbb44Schristos if (FD_ISSET(c->resp_read_pipe, pfds)) { 393068dbbb44Schristos ++c->resp_ready_seen; 393168dbbb44Schristos ++blocking_child_ready_seen; 39322950cc38Schristos } 39332950cc38Schristos } 3934abb0f93cSkardel 3935abb0f93cSkardel /* We've done our work */ 393668dbbb44Schristos #if defined(DEBUG_TIMING) 3937abb0f93cSkardel get_systime(&ts_e); 3938abb0f93cSkardel /* 3939abb0f93cSkardel * (ts_e - ts) is the amount of time we spent 3940abb0f93cSkardel * processing this gob of file descriptors. Log 3941abb0f93cSkardel * it. 3942abb0f93cSkardel */ 3943abb0f93cSkardel L_SUB(&ts_e, &ts); 3944abb0f93cSkardel collect_timing(NULL, "input handler", 1, &ts_e); 3945abb0f93cSkardel if (debug > 3) 3946abb0f93cSkardel msyslog(LOG_DEBUG, 3947abb0f93cSkardel "input_handler: Processed a gob of fd's in %s msec", 3948abb0f93cSkardel lfptoms(&ts_e, 6)); 39492950cc38Schristos #endif /* DEBUG_TIMING */ 3950abb0f93cSkardel } 39512950cc38Schristos #endif /* !HAVE_IO_COMPLETION_PORT */ 39522950cc38Schristos 39532950cc38Schristos /* 39542950cc38Schristos * find an interface suitable for the src address 39552950cc38Schristos */ 39562950cc38Schristos endpt * 39572950cc38Schristos select_peerinterface( 39582950cc38Schristos struct peer * peer, 39592950cc38Schristos sockaddr_u * srcadr, 39602950cc38Schristos endpt * dstadr 39612950cc38Schristos ) 39622950cc38Schristos { 39632950cc38Schristos endpt *ep; 39642950cc38Schristos #ifndef SIM 39652950cc38Schristos endpt *wild; 39662950cc38Schristos 39672950cc38Schristos wild = ANY_INTERFACE_CHOOSE(srcadr); 39682950cc38Schristos 39692950cc38Schristos /* 39702950cc38Schristos * Initialize the peer structure and dance the interface jig. 39712950cc38Schristos * Reference clocks step the loopback waltz, the others 39722950cc38Schristos * squaredance around the interface list looking for a buddy. If 39732950cc38Schristos * the dance peters out, there is always the wildcard interface. 39742950cc38Schristos * This might happen in some systems and would preclude proper 39752950cc38Schristos * operation with public key cryptography. 39762950cc38Schristos */ 39772950cc38Schristos if (ISREFCLOCKADR(srcadr)) { 39782950cc38Schristos ep = loopback_interface; 39792950cc38Schristos } else if (peer->cast_flags & 39802950cc38Schristos (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) { 39812950cc38Schristos ep = findbcastinter(srcadr); 39822950cc38Schristos if (ep != NULL) 39832950cc38Schristos DPRINTF(4, ("Found *-cast interface %s for address %s\n", 39842950cc38Schristos stoa(&ep->sin), stoa(srcadr))); 39852950cc38Schristos else 39862950cc38Schristos DPRINTF(4, ("No *-cast local address found for address %s\n", 39872950cc38Schristos stoa(srcadr))); 39882950cc38Schristos } else { 39892950cc38Schristos ep = dstadr; 3990*eabc0478Schristos if (NULL == ep) { 39912950cc38Schristos ep = wild; 39922950cc38Schristos } 3993*eabc0478Schristos } 39942950cc38Schristos /* 39952950cc38Schristos * If it is a multicast address, findbcastinter() may not find 39962950cc38Schristos * it. For unicast, we get to find the interface when dstadr is 39972950cc38Schristos * given to us as the wildcard (ANY_INTERFACE_CHOOSE). Either 39982950cc38Schristos * way, try a little harder. 39992950cc38Schristos */ 4000*eabc0478Schristos if (wild == ep) { 40012950cc38Schristos ep = findinterface(srcadr); 4002*eabc0478Schristos } 40032950cc38Schristos /* 40042950cc38Schristos * we do not bind to the wildcard interfaces for output 40052950cc38Schristos * as our (network) source address would be undefined and 40062950cc38Schristos * crypto will not work without knowing the own transmit address 40072950cc38Schristos */ 4008*eabc0478Schristos if (ep != NULL && (INT_WILDCARD & ep->flags)) { 4009*eabc0478Schristos if (!accept_wildcard_if_for_winnt) { 40102950cc38Schristos ep = NULL; 4011*eabc0478Schristos } 4012*eabc0478Schristos } 40132950cc38Schristos #else /* SIM follows */ 40142950cc38Schristos ep = loopback_interface; 4015abb0f93cSkardel #endif 4016abb0f93cSkardel 40172950cc38Schristos return ep; 40182950cc38Schristos } 40192950cc38Schristos 40202950cc38Schristos 4021abb0f93cSkardel /* 4022abb0f93cSkardel * findinterface - find local interface corresponding to address 4023abb0f93cSkardel */ 40243123f114Skardel endpt * 4025abb0f93cSkardel findinterface( 4026abb0f93cSkardel sockaddr_u *addr 4027abb0f93cSkardel ) 4028abb0f93cSkardel { 40293123f114Skardel endpt *iface; 4030abb0f93cSkardel 4031abb0f93cSkardel iface = findlocalinterface(addr, INT_WILDCARD, 0); 4032abb0f93cSkardel 4033abb0f93cSkardel if (NULL == iface) { 4034abb0f93cSkardel DPRINTF(4, ("Found no interface for address %s - returning wildcard\n", 4035abb0f93cSkardel stoa(addr))); 4036abb0f93cSkardel 4037abb0f93cSkardel iface = ANY_INTERFACE_CHOOSE(addr); 4038abb0f93cSkardel } else 4039abb0f93cSkardel DPRINTF(4, ("Found interface #%d %s for address %s\n", 4040abb0f93cSkardel iface->ifnum, iface->name, stoa(addr))); 4041abb0f93cSkardel 4042abb0f93cSkardel return iface; 4043abb0f93cSkardel } 4044abb0f93cSkardel 4045abb0f93cSkardel /* 4046abb0f93cSkardel * findlocalinterface - find local interface corresponding to addr, 4047*eabc0478Schristos * which does not have any of flags set. If bcast is nonzero, addr is 4048abb0f93cSkardel * a broadcast address. 4049abb0f93cSkardel * 4050abb0f93cSkardel * This code attempts to find the local sending address for an outgoing 4051abb0f93cSkardel * address by connecting a new socket to destinationaddress:NTP_PORT 4052abb0f93cSkardel * and reading the sockname of the resulting connect. 4053abb0f93cSkardel * the complicated sequence simulates the routing table lookup 4054abb0f93cSkardel * for to first hop without duplicating any of the routing logic into 4055abb0f93cSkardel * ntpd. preferably we would have used an API call - but its not there - 4056abb0f93cSkardel * so this is the best we can do here short of duplicating to entire routing 4057abb0f93cSkardel * logic in ntpd which would be a silly and really unportable thing to do. 4058abb0f93cSkardel * 4059abb0f93cSkardel */ 40603123f114Skardel static endpt * 4061abb0f93cSkardel findlocalinterface( 4062abb0f93cSkardel sockaddr_u * addr, 4063abb0f93cSkardel int flags, 4064abb0f93cSkardel int bcast 4065abb0f93cSkardel ) 4066abb0f93cSkardel { 4067abb0f93cSkardel GETSOCKNAME_SOCKLEN_TYPE sockaddrlen; 40683123f114Skardel endpt * iface; 4069abb0f93cSkardel sockaddr_u saddr; 4070abb0f93cSkardel SOCKET s; 4071abb0f93cSkardel int rtn; 4072abb0f93cSkardel int on; 4073abb0f93cSkardel 4074abb0f93cSkardel DPRINTF(4, ("Finding interface for addr %s in list of addresses\n", 4075abb0f93cSkardel stoa(addr))); 4076abb0f93cSkardel 4077*eabc0478Schristos /* [Bug 3437] The prototype POOL peer can be AF_UNSPEC. 4078*eabc0478Schristos * This is bound to fail, but on the way to nowhere it 40794eea345dSchristos * triggers a security incident on SELinux. 40804eea345dSchristos * 4081*eabc0478Schristos * Checking the condition and failing early is probably good 40824eea345dSchristos * advice, and even saves us some syscalls in that case. 40834eea345dSchristos * Thanks to Miroslav Lichvar for finding this. 40844eea345dSchristos */ 4085*eabc0478Schristos if (AF_UNSPEC == AF(addr)) { 40864eea345dSchristos return NULL; 4087*eabc0478Schristos } 4088abb0f93cSkardel s = socket(AF(addr), SOCK_DGRAM, 0); 4089*eabc0478Schristos if (INVALID_SOCKET == s) { 4090abb0f93cSkardel return NULL; 4091*eabc0478Schristos } 4092abb0f93cSkardel /* 4093abb0f93cSkardel * If we are looking for broadcast interface we need to set this 4094abb0f93cSkardel * socket to allow broadcast 4095abb0f93cSkardel */ 4096abb0f93cSkardel if (bcast) { 4097abb0f93cSkardel on = 1; 40982950cc38Schristos if (SOCKET_ERROR == setsockopt(s, SOL_SOCKET, 40992950cc38Schristos SO_BROADCAST, 41004eea345dSchristos (void *)&on, 41012950cc38Schristos sizeof(on))) { 41022950cc38Schristos closesocket(s); 41032950cc38Schristos return NULL; 41042950cc38Schristos } 4105abb0f93cSkardel } 4106abb0f93cSkardel 4107abb0f93cSkardel rtn = connect(s, &addr->sa, SOCKLEN(addr)); 4108abb0f93cSkardel if (SOCKET_ERROR == rtn) { 4109abb0f93cSkardel closesocket(s); 4110abb0f93cSkardel return NULL; 4111abb0f93cSkardel } 4112abb0f93cSkardel 4113abb0f93cSkardel sockaddrlen = sizeof(saddr); 4114abb0f93cSkardel rtn = getsockname(s, &saddr.sa, &sockaddrlen); 4115abb0f93cSkardel closesocket(s); 4116abb0f93cSkardel if (SOCKET_ERROR == rtn) 4117abb0f93cSkardel return NULL; 4118abb0f93cSkardel 4119abb0f93cSkardel DPRINTF(4, ("findlocalinterface: kernel maps %s to %s\n", 4120abb0f93cSkardel stoa(addr), stoa(&saddr))); 4121abb0f93cSkardel 4122abb0f93cSkardel iface = getinterface(&saddr, flags); 4123abb0f93cSkardel 4124abb0f93cSkardel /* 41253123f114Skardel * if we didn't find an exact match on saddr, find the closest 41263123f114Skardel * available local address. This handles the case of the 41273123f114Skardel * address suggested by the kernel being excluded by nic rules 41283123f114Skardel * or the user's -I and -L options to ntpd. 41293123f114Skardel * See http://bugs.ntp.org/1184 and http://bugs.ntp.org/1683 41303123f114Skardel * for more background. 4131abb0f93cSkardel */ 4132*eabc0478Schristos if (NULL == iface || iface->ignore_packets) { 41333123f114Skardel iface = findclosestinterface(&saddr, 41343123f114Skardel flags | INT_LOOPBACK); 4135*eabc0478Schristos } 4136*eabc0478Schristos /* 4137*eabc0478Schristos * Don't select an interface which will ignore replies, or one 4138*eabc0478Schristos * dedicated to multicast receive. 4139*eabc0478Schristos */ 4140*eabc0478Schristos if ( iface != NULL 4141*eabc0478Schristos && (iface->ignore_packets || (INT_MCASTIF & iface->flags))) { 4142abb0f93cSkardel iface = NULL; 4143*eabc0478Schristos } 4144abb0f93cSkardel return iface; 4145abb0f93cSkardel } 4146abb0f93cSkardel 4147abb0f93cSkardel 4148abb0f93cSkardel /* 41493123f114Skardel * findclosestinterface 41503123f114Skardel * 41513123f114Skardel * If there are -I/--interface or -L/novirtualips command-line options, 41523123f114Skardel * or "nic" or "interface" rules in ntp.conf, findlocalinterface() may 41533123f114Skardel * find the kernel's preferred local address for a given peer address is 41543123f114Skardel * administratively unavailable to ntpd, and punt to this routine's more 41553123f114Skardel * expensive search. 41563123f114Skardel * 41573123f114Skardel * Find the numerically closest local address to the one connect() 41583123f114Skardel * suggested. This matches an address on the same subnet first, as 41593123f114Skardel * needed by Bug 1184, and provides a consistent choice if there are 41603123f114Skardel * multiple feasible local addresses, regardless of the order ntpd 41613123f114Skardel * enumerated them. 4162abb0f93cSkardel */ 41632950cc38Schristos endpt * 41643123f114Skardel findclosestinterface( 4165abb0f93cSkardel sockaddr_u * addr, 4166abb0f93cSkardel int flags 4167abb0f93cSkardel ) 4168abb0f93cSkardel { 41693123f114Skardel endpt * ep; 41703123f114Skardel endpt * winner; 41713123f114Skardel sockaddr_u addr_dist; 41723123f114Skardel sockaddr_u min_dist; 41733123f114Skardel 41742950cc38Schristos ZERO_SOCK(&min_dist); 41753123f114Skardel winner = NULL; 41763123f114Skardel 41773123f114Skardel for (ep = ep_list; ep != NULL; ep = ep->elink) { 41783123f114Skardel if (ep->ignore_packets || 41793123f114Skardel AF(addr) != ep->family || 41803123f114Skardel flags & ep->flags) 41813123f114Skardel continue; 41823123f114Skardel 41833123f114Skardel calc_addr_distance(&addr_dist, addr, &ep->sin); 41843123f114Skardel if (NULL == winner || 41853123f114Skardel -1 == cmp_addr_distance(&addr_dist, &min_dist)) { 41863123f114Skardel min_dist = addr_dist; 41873123f114Skardel winner = ep; 41883123f114Skardel } 41893123f114Skardel } 41903123f114Skardel if (NULL == winner) 41913123f114Skardel DPRINTF(4, ("findclosestinterface(%s) failed\n", 41923123f114Skardel stoa(addr))); 41933123f114Skardel else 41943123f114Skardel DPRINTF(4, ("findclosestinterface(%s) -> %s\n", 41953123f114Skardel stoa(addr), stoa(&winner->sin))); 41963123f114Skardel 41973123f114Skardel return winner; 41983123f114Skardel } 41993123f114Skardel 42003123f114Skardel 42013123f114Skardel /* 42023123f114Skardel * calc_addr_distance - calculate the distance between two addresses, 42033123f114Skardel * the absolute value of the difference between 42043123f114Skardel * the addresses numerically, stored as an address. 42053123f114Skardel */ 42063123f114Skardel static void 42073123f114Skardel calc_addr_distance( 42083123f114Skardel sockaddr_u * dist, 42093123f114Skardel const sockaddr_u * a1, 42103123f114Skardel const sockaddr_u * a2 42113123f114Skardel ) 42123123f114Skardel { 4213*eabc0478Schristos u_char * pdist; 4214*eabc0478Schristos const u_char * p1; 4215*eabc0478Schristos const u_char * p2; 4216*eabc0478Schristos size_t cb; 4217*eabc0478Schristos int different; 42183123f114Skardel int a1_greater; 4219*eabc0478Schristos u_int u; 42203123f114Skardel 4221af12ab5eSchristos REQUIRE(AF(a1) == AF(a2)); 42223123f114Skardel 42232950cc38Schristos ZERO_SOCK(dist); 42243123f114Skardel AF(dist) = AF(a1); 42253123f114Skardel 42263123f114Skardel if (IS_IPV4(a1)) { 4227*eabc0478Schristos pdist = ( u_char *)&NSRCADR(dist); 4228*eabc0478Schristos p1 = (const u_char *)&NSRCADR(a1); 4229*eabc0478Schristos p2 = (const u_char *)&NSRCADR(a2); 42303123f114Skardel } else { 4231*eabc0478Schristos pdist = ( u_char *)&NSRCADR(dist); 4232*eabc0478Schristos p1 = (const u_char *)&NSRCADR(a1); 4233*eabc0478Schristos p2 = (const u_char *)&NSRCADR(a2); 4234*eabc0478Schristos } 4235*eabc0478Schristos cb = SIZEOF_INADDR(AF(dist)); 4236*eabc0478Schristos different = FALSE; 4237*eabc0478Schristos a1_greater = FALSE; 4238*eabc0478Schristos for (u = 0; u < cb; u++) { 4239*eabc0478Schristos if (!different && p1[u] != p2[u]) { 4240*eabc0478Schristos a1_greater = (p1[u] > p2[u]); 4241*eabc0478Schristos different = TRUE; 4242*eabc0478Schristos } 4243*eabc0478Schristos if (a1_greater) { 4244*eabc0478Schristos pdist[u] = p1[u] - p2[u]; 4245*eabc0478Schristos } else { 4246*eabc0478Schristos pdist[u] = p2[u] - p1[u]; 42473123f114Skardel } 42483123f114Skardel } 42493123f114Skardel } 42503123f114Skardel 42513123f114Skardel 42523123f114Skardel /* 42533123f114Skardel * cmp_addr_distance - compare two address distances, returning -1, 0, 42543123f114Skardel * 1 to indicate their relationship. 42553123f114Skardel */ 42563123f114Skardel static int 42573123f114Skardel cmp_addr_distance( 42583123f114Skardel const sockaddr_u * d1, 42593123f114Skardel const sockaddr_u * d2 42603123f114Skardel ) 42613123f114Skardel { 42623123f114Skardel int i; 42633123f114Skardel 4264af12ab5eSchristos REQUIRE(AF(d1) == AF(d2)); 42653123f114Skardel 42663123f114Skardel if (IS_IPV4(d1)) { 42673123f114Skardel if (SRCADR(d1) < SRCADR(d2)) 42683123f114Skardel return -1; 42693123f114Skardel else if (SRCADR(d1) == SRCADR(d2)) 42703123f114Skardel return 0; 42713123f114Skardel else 42723123f114Skardel return 1; 42733123f114Skardel } 42743123f114Skardel 4275a2545411Skardel for (i = 0; i < (int)sizeof(NSRCADR6(d1)); i++) { 42763123f114Skardel if (NSRCADR6(d1)[i] < NSRCADR6(d2)[i]) 42773123f114Skardel return -1; 42783123f114Skardel else if (NSRCADR6(d1)[i] > NSRCADR6(d2)[i]) 42793123f114Skardel return 1; 42803123f114Skardel } 42813123f114Skardel 42823123f114Skardel return 0; 42833123f114Skardel } 42843123f114Skardel 42853123f114Skardel 42863123f114Skardel 42873123f114Skardel /* 42883123f114Skardel * fetch an interface structure the matches the 42893123f114Skardel * address and has the given flags NOT set 42903123f114Skardel */ 42912950cc38Schristos endpt * 42923123f114Skardel getinterface( 42933123f114Skardel sockaddr_u * addr, 42943123f114Skardel u_int32 flags 42953123f114Skardel ) 42963123f114Skardel { 42973123f114Skardel endpt *iface; 4298abb0f93cSkardel 4299abb0f93cSkardel iface = find_addr_in_list(addr); 4300abb0f93cSkardel 4301abb0f93cSkardel if (iface != NULL && (iface->flags & flags)) 4302abb0f93cSkardel iface = NULL; 4303abb0f93cSkardel 4304abb0f93cSkardel return iface; 4305abb0f93cSkardel } 4306abb0f93cSkardel 4307abb0f93cSkardel 4308abb0f93cSkardel /* 4309abb0f93cSkardel * findbcastinter - find broadcast interface corresponding to address 4310abb0f93cSkardel */ 43113123f114Skardel endpt * 4312abb0f93cSkardel findbcastinter( 4313abb0f93cSkardel sockaddr_u *addr 4314abb0f93cSkardel ) 4315abb0f93cSkardel { 43162950cc38Schristos endpt * iface; 43172950cc38Schristos 43182950cc38Schristos iface = NULL; 4319abb0f93cSkardel #if !defined(MPE) && (defined(SIOCGIFCONF) || defined(SYS_WINNT)) 4320abb0f93cSkardel DPRINTF(4, ("Finding broadcast/multicast interface for addr %s in list of addresses\n", 4321abb0f93cSkardel stoa(addr))); 4322abb0f93cSkardel 4323abb0f93cSkardel iface = findlocalinterface(addr, INT_LOOPBACK | INT_WILDCARD, 4324abb0f93cSkardel 1); 4325abb0f93cSkardel if (iface != NULL) { 4326abb0f93cSkardel DPRINTF(4, ("Easily found bcast-/mcast- interface index #%d %s\n", 4327abb0f93cSkardel iface->ifnum, iface->name)); 4328abb0f93cSkardel return iface; 4329abb0f93cSkardel } 4330abb0f93cSkardel 4331abb0f93cSkardel /* 4332abb0f93cSkardel * plan B - try to find something reasonable in our lists in 4333abb0f93cSkardel * case kernel lookup doesn't help 4334abb0f93cSkardel */ 43353123f114Skardel for (iface = ep_list; iface != NULL; iface = iface->elink) { 4336abb0f93cSkardel if (iface->flags & INT_WILDCARD) 4337abb0f93cSkardel continue; 4338abb0f93cSkardel 4339abb0f93cSkardel /* Don't bother with ignored interfaces */ 4340abb0f93cSkardel if (iface->ignore_packets) 4341abb0f93cSkardel continue; 4342abb0f93cSkardel 4343abb0f93cSkardel /* 4344abb0f93cSkardel * First look if this is the correct family 4345abb0f93cSkardel */ 4346abb0f93cSkardel if(AF(&iface->sin) != AF(addr)) 4347abb0f93cSkardel continue; 4348abb0f93cSkardel 4349abb0f93cSkardel /* Skip the loopback addresses */ 4350abb0f93cSkardel if (iface->flags & INT_LOOPBACK) 4351abb0f93cSkardel continue; 4352abb0f93cSkardel 4353abb0f93cSkardel /* 4354abb0f93cSkardel * If we are looking to match a multicast address and 4355abb0f93cSkardel * this interface is one... 4356abb0f93cSkardel */ 4357abb0f93cSkardel if (addr_ismulticast(addr) 4358abb0f93cSkardel && (iface->flags & INT_MULTICAST)) { 4359abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT 4360abb0f93cSkardel /* 4361abb0f93cSkardel * ...it is the winner unless we're looking for 4362abb0f93cSkardel * an interface to use for link-local multicast 4363abb0f93cSkardel * and its address is not link-local. 4364abb0f93cSkardel */ 4365abb0f93cSkardel if (IS_IPV6(addr) 4366abb0f93cSkardel && IN6_IS_ADDR_MC_LINKLOCAL(PSOCK_ADDR6(addr)) 4367abb0f93cSkardel && !IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(&iface->sin))) 4368abb0f93cSkardel continue; 4369abb0f93cSkardel #endif 4370abb0f93cSkardel break; 4371abb0f93cSkardel } 4372abb0f93cSkardel 4373abb0f93cSkardel /* 4374abb0f93cSkardel * We match only those interfaces marked as 4375abb0f93cSkardel * broadcastable and either the explicit broadcast 4376abb0f93cSkardel * address or the network portion of the IP address. 4377abb0f93cSkardel * Sloppy. 4378abb0f93cSkardel */ 4379abb0f93cSkardel if (IS_IPV4(addr)) { 4380abb0f93cSkardel if (SOCK_EQ(&iface->bcast, addr)) 4381abb0f93cSkardel break; 4382abb0f93cSkardel 4383abb0f93cSkardel if ((NSRCADR(&iface->sin) & NSRCADR(&iface->mask)) 4384abb0f93cSkardel == (NSRCADR(addr) & NSRCADR(&iface->mask))) 4385abb0f93cSkardel break; 4386abb0f93cSkardel } 4387abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT 4388abb0f93cSkardel else if (IS_IPV6(addr)) { 4389abb0f93cSkardel if (SOCK_EQ(&iface->bcast, addr)) 4390abb0f93cSkardel break; 4391abb0f93cSkardel 4392abb0f93cSkardel if (SOCK_EQ(netof(&iface->sin), netof(addr))) 4393abb0f93cSkardel break; 4394abb0f93cSkardel } 4395abb0f93cSkardel #endif 4396abb0f93cSkardel } 4397abb0f93cSkardel #endif /* SIOCGIFCONF */ 4398abb0f93cSkardel if (NULL == iface) { 4399abb0f93cSkardel DPRINTF(4, ("No bcast interface found for %s\n", 4400abb0f93cSkardel stoa(addr))); 4401abb0f93cSkardel iface = ANY_INTERFACE_CHOOSE(addr); 44022950cc38Schristos } else { 4403abb0f93cSkardel DPRINTF(4, ("Found bcast-/mcast- interface index #%d %s\n", 4404abb0f93cSkardel iface->ifnum, iface->name)); 44052950cc38Schristos } 44062950cc38Schristos 4407abb0f93cSkardel return iface; 4408abb0f93cSkardel } 4409abb0f93cSkardel 4410abb0f93cSkardel 4411abb0f93cSkardel /* 4412abb0f93cSkardel * io_clr_stats - clear I/O module statistics 4413abb0f93cSkardel */ 4414abb0f93cSkardel void 4415abb0f93cSkardel io_clr_stats(void) 4416abb0f93cSkardel { 4417abb0f93cSkardel packets_dropped = 0; 4418abb0f93cSkardel packets_ignored = 0; 4419abb0f93cSkardel packets_received = 0; 4420abb0f93cSkardel packets_sent = 0; 4421abb0f93cSkardel packets_notsent = 0; 4422abb0f93cSkardel 4423abb0f93cSkardel handler_calls = 0; 4424abb0f93cSkardel handler_pkts = 0; 4425abb0f93cSkardel io_timereset = current_time; 4426abb0f93cSkardel } 4427abb0f93cSkardel 4428abb0f93cSkardel 4429abb0f93cSkardel #ifdef REFCLOCK 4430abb0f93cSkardel /* 4431abb0f93cSkardel * io_addclock - add a reference clock to the list and arrange that we 4432abb0f93cSkardel * get SIGIO interrupts from it. 4433abb0f93cSkardel */ 4434abb0f93cSkardel int 4435abb0f93cSkardel io_addclock( 4436abb0f93cSkardel struct refclockio *rio 4437abb0f93cSkardel ) 4438abb0f93cSkardel { 4439abb0f93cSkardel BLOCKIO(); 4440abb0f93cSkardel 4441abb0f93cSkardel /* 4442abb0f93cSkardel * Stuff the I/O structure in the list and mark the descriptor 4443abb0f93cSkardel * in use. There is a harmless (I hope) race condition here. 4444abb0f93cSkardel */ 44452950cc38Schristos rio->active = TRUE; 4446abb0f93cSkardel 4447abb0f93cSkardel # ifdef HAVE_SIGNALED_IO 4448abb0f93cSkardel if (init_clock_sig(rio)) { 4449abb0f93cSkardel UNBLOCKIO(); 4450abb0f93cSkardel return 0; 4451abb0f93cSkardel } 4452abb0f93cSkardel # elif defined(HAVE_IO_COMPLETION_PORT) 445368dbbb44Schristos if (!io_completion_port_add_clock_io(rio)) { 4454abb0f93cSkardel UNBLOCKIO(); 4455abb0f93cSkardel return 0; 4456abb0f93cSkardel } 4457abb0f93cSkardel # endif 4458abb0f93cSkardel 4459abb0f93cSkardel /* 4460abb0f93cSkardel * enqueue 4461abb0f93cSkardel */ 44622950cc38Schristos LINK_SLIST(refio, rio, next); 4463abb0f93cSkardel 4464abb0f93cSkardel /* 4465abb0f93cSkardel * register fd 4466abb0f93cSkardel */ 4467abb0f93cSkardel add_fd_to_list(rio->fd, FD_TYPE_FILE); 4468abb0f93cSkardel 4469abb0f93cSkardel UNBLOCKIO(); 4470abb0f93cSkardel return 1; 4471abb0f93cSkardel } 4472abb0f93cSkardel 44732950cc38Schristos 4474abb0f93cSkardel /* 4475abb0f93cSkardel * io_closeclock - close the clock in the I/O structure given 4476abb0f93cSkardel */ 4477abb0f93cSkardel void 4478abb0f93cSkardel io_closeclock( 4479abb0f93cSkardel struct refclockio *rio 4480abb0f93cSkardel ) 4481abb0f93cSkardel { 44822950cc38Schristos struct refclockio *unlinked; 4483abb0f93cSkardel 4484abb0f93cSkardel BLOCKIO(); 4485abb0f93cSkardel 4486abb0f93cSkardel /* 4487abb0f93cSkardel * Remove structure from the list 4488abb0f93cSkardel */ 44892950cc38Schristos rio->active = FALSE; 44902950cc38Schristos UNLINK_SLIST(unlinked, refio, rio, next, struct refclockio); 44912950cc38Schristos if (NULL != unlinked) { 449268dbbb44Schristos /* Close the descriptor. The order of operations is 449368dbbb44Schristos * important here in case of async / overlapped IO: 449468dbbb44Schristos * only after we have removed the clock from the 449568dbbb44Schristos * IO completion port we can be sure no further 449668dbbb44Schristos * input is queued. So... 449768dbbb44Schristos * - we first disable feeding to the queu by removing 449868dbbb44Schristos * the clock from the IO engine 449968dbbb44Schristos * - close the file (which brings down any IO on it) 450068dbbb44Schristos * - clear the buffer from results for this fd 4501abb0f93cSkardel */ 450268dbbb44Schristos # ifdef HAVE_IO_COMPLETION_PORT 450368dbbb44Schristos io_completion_port_remove_clock_io(rio); 450468dbbb44Schristos # endif 4505*eabc0478Schristos close_and_delete_fd_from_list(rio->fd, NULL); 450668dbbb44Schristos purge_recv_buffers_for_fd(rio->fd); 45072950cc38Schristos rio->fd = -1; 450868dbbb44Schristos } 45092950cc38Schristos 4510abb0f93cSkardel UNBLOCKIO(); 4511abb0f93cSkardel } 4512abb0f93cSkardel #endif /* REFCLOCK */ 4513abb0f93cSkardel 45142950cc38Schristos 4515abb0f93cSkardel /* 4516abb0f93cSkardel * On NT a SOCKET is an unsigned int so we cannot possibly keep it in 4517abb0f93cSkardel * an array. So we use one of the ISC_LIST functions to hold the 4518abb0f93cSkardel * socket value and use that when we want to enumerate it. 4519abb0f93cSkardel * 4520abb0f93cSkardel * This routine is called by the forked intres child process to close 4521abb0f93cSkardel * all open sockets. On Windows there's no need as intres runs in 4522abb0f93cSkardel * the same process as a thread. 4523abb0f93cSkardel */ 4524abb0f93cSkardel #ifndef SYS_WINNT 4525abb0f93cSkardel void 45262950cc38Schristos kill_asyncio( 45272950cc38Schristos int startfd 45282950cc38Schristos ) 4529abb0f93cSkardel { 4530abb0f93cSkardel BLOCKIO(); 4531abb0f93cSkardel 4532abb0f93cSkardel /* 4533abb0f93cSkardel * In the child process we do not maintain activefds and 4534abb0f93cSkardel * maxactivefd. Zeroing maxactivefd disables code which 4535abb0f93cSkardel * maintains it in close_and_delete_fd_from_list(). 4536abb0f93cSkardel */ 4537abb0f93cSkardel maxactivefd = 0; 4538abb0f93cSkardel 4539abb0f93cSkardel while (fd_list != NULL) 4540*eabc0478Schristos close_and_delete_fd_from_list(fd_list->fd, NULL); 4541abb0f93cSkardel 4542abb0f93cSkardel UNBLOCKIO(); 4543abb0f93cSkardel } 4544abb0f93cSkardel #endif /* !SYS_WINNT */ 4545abb0f93cSkardel 45462950cc38Schristos 4547abb0f93cSkardel /* 4548*eabc0478Schristos * Add and delete functions for the list of input file descriptors 4549abb0f93cSkardel */ 4550abb0f93cSkardel static void 4551abb0f93cSkardel add_fd_to_list( 4552abb0f93cSkardel SOCKET fd, 4553abb0f93cSkardel enum desc_type type 4554abb0f93cSkardel ) 4555abb0f93cSkardel { 4556abb0f93cSkardel vsock_t *lsock = emalloc(sizeof(*lsock)); 4557abb0f93cSkardel 4558abb0f93cSkardel lsock->fd = fd; 4559abb0f93cSkardel lsock->type = type; 4560abb0f93cSkardel 4561abb0f93cSkardel LINK_SLIST(fd_list, lsock, link); 45622950cc38Schristos maintain_activefds(fd, 0); 4563abb0f93cSkardel } 4564abb0f93cSkardel 4565abb0f93cSkardel 4566abb0f93cSkardel static void 4567abb0f93cSkardel close_and_delete_fd_from_list( 4568*eabc0478Schristos SOCKET fd, 4569*eabc0478Schristos endpt *ep /* req. if fd is in struct endpt */ 4570abb0f93cSkardel ) 4571abb0f93cSkardel { 4572abb0f93cSkardel vsock_t *lsock; 4573abb0f93cSkardel 4574abb0f93cSkardel UNLINK_EXPR_SLIST(lsock, fd_list, fd == 4575abb0f93cSkardel UNLINK_EXPR_SLIST_CURRENT()->fd, link, vsock_t); 4576abb0f93cSkardel 45772950cc38Schristos if (NULL == lsock) 45782950cc38Schristos return; 45792950cc38Schristos 4580abb0f93cSkardel switch (lsock->type) { 45812950cc38Schristos 4582abb0f93cSkardel case FD_TYPE_SOCKET: 4583*eabc0478Schristos #ifdef HAVE_IO_COMPLETION_PORT 4584*eabc0478Schristos if (ep != NULL) { 4585*eabc0478Schristos io_completion_port_remove_socket(fd, ep); 4586*eabc0478Schristos } 4587*eabc0478Schristos #endif 4588abb0f93cSkardel closesocket(lsock->fd); 4589abb0f93cSkardel break; 4590abb0f93cSkardel 4591abb0f93cSkardel case FD_TYPE_FILE: 45928b8da087Schristos closeserial((int)lsock->fd); 4593abb0f93cSkardel break; 4594abb0f93cSkardel 4595abb0f93cSkardel default: 4596abb0f93cSkardel msyslog(LOG_ERR, 4597abb0f93cSkardel "internal error - illegal descriptor type %d - EXITING", 4598abb0f93cSkardel (int)lsock->type); 4599abb0f93cSkardel exit(1); 4600abb0f93cSkardel } 4601abb0f93cSkardel 4602abb0f93cSkardel free(lsock); 4603abb0f93cSkardel /* 4604abb0f93cSkardel * remove from activefds 4605abb0f93cSkardel */ 46062950cc38Schristos maintain_activefds(fd, 1); 46072950cc38Schristos } 4608abb0f93cSkardel 4609abb0f93cSkardel 4610abb0f93cSkardel static void 4611abb0f93cSkardel add_addr_to_list( 4612abb0f93cSkardel sockaddr_u * addr, 46133123f114Skardel endpt * ep 4614abb0f93cSkardel ) 4615abb0f93cSkardel { 4616abb0f93cSkardel remaddr_t *laddr; 4617abb0f93cSkardel 4618abb0f93cSkardel #ifdef DEBUG 4619abb0f93cSkardel if (find_addr_in_list(addr) == NULL) { 4620abb0f93cSkardel #endif 4621abb0f93cSkardel /* not there yet - add to list */ 4622abb0f93cSkardel laddr = emalloc(sizeof(*laddr)); 46233123f114Skardel laddr->addr = *addr; 46243123f114Skardel laddr->ep = ep; 4625abb0f93cSkardel 4626abb0f93cSkardel LINK_SLIST(remoteaddr_list, laddr, link); 4627abb0f93cSkardel 4628abb0f93cSkardel DPRINTF(4, ("Added addr %s to list of addresses\n", 4629abb0f93cSkardel stoa(addr))); 4630abb0f93cSkardel #ifdef DEBUG 4631abb0f93cSkardel } else 4632abb0f93cSkardel DPRINTF(4, ("WARNING: Attempt to add duplicate addr %s to address list\n", 4633abb0f93cSkardel stoa(addr))); 4634abb0f93cSkardel #endif 4635abb0f93cSkardel } 4636abb0f93cSkardel 4637abb0f93cSkardel 4638abb0f93cSkardel static void 4639abb0f93cSkardel delete_addr_from_list( 4640abb0f93cSkardel sockaddr_u *addr 4641abb0f93cSkardel ) 4642abb0f93cSkardel { 4643abb0f93cSkardel remaddr_t *unlinked; 4644abb0f93cSkardel 4645abb0f93cSkardel UNLINK_EXPR_SLIST(unlinked, remoteaddr_list, SOCK_EQ(addr, 4646abb0f93cSkardel &(UNLINK_EXPR_SLIST_CURRENT()->addr)), link, remaddr_t); 4647abb0f93cSkardel 4648abb0f93cSkardel if (unlinked != NULL) { 4649abb0f93cSkardel DPRINTF(4, ("Deleted addr %s from list of addresses\n", 4650abb0f93cSkardel stoa(addr))); 4651abb0f93cSkardel free(unlinked); 4652abb0f93cSkardel } 4653abb0f93cSkardel } 4654abb0f93cSkardel 4655abb0f93cSkardel 4656abb0f93cSkardel static void 4657abb0f93cSkardel delete_interface_from_list( 46583123f114Skardel endpt *iface 4659abb0f93cSkardel ) 4660abb0f93cSkardel { 4661abb0f93cSkardel remaddr_t *unlinked; 4662abb0f93cSkardel 4663ea66d795Schristos for (;;) { 4664abb0f93cSkardel UNLINK_EXPR_SLIST(unlinked, remoteaddr_list, iface == 46653123f114Skardel UNLINK_EXPR_SLIST_CURRENT()->ep, link, 4666abb0f93cSkardel remaddr_t); 4667abb0f93cSkardel 4668ea66d795Schristos if (unlinked == NULL) 4669ea66d795Schristos break; 4670abb0f93cSkardel DPRINTF(4, ("Deleted addr %s for interface #%d %s from list of addresses\n", 4671abb0f93cSkardel stoa(&unlinked->addr), iface->ifnum, 4672abb0f93cSkardel iface->name)); 4673abb0f93cSkardel free(unlinked); 4674abb0f93cSkardel } 4675abb0f93cSkardel } 4676abb0f93cSkardel 4677abb0f93cSkardel 4678*eabc0478Schristos static endpt * 4679abb0f93cSkardel find_addr_in_list( 4680abb0f93cSkardel sockaddr_u *addr 4681abb0f93cSkardel ) 4682abb0f93cSkardel { 4683abb0f93cSkardel remaddr_t *entry; 4684abb0f93cSkardel 4685abb0f93cSkardel DPRINTF(4, ("Searching for addr %s in list of addresses - ", 4686abb0f93cSkardel stoa(addr))); 4687abb0f93cSkardel 4688abb0f93cSkardel for (entry = remoteaddr_list; 4689abb0f93cSkardel entry != NULL; 4690abb0f93cSkardel entry = entry->link) 4691abb0f93cSkardel if (SOCK_EQ(&entry->addr, addr)) { 4692abb0f93cSkardel DPRINTF(4, ("FOUND\n")); 46933123f114Skardel return entry->ep; 4694abb0f93cSkardel } 4695abb0f93cSkardel 4696abb0f93cSkardel DPRINTF(4, ("NOT FOUND\n")); 4697abb0f93cSkardel return NULL; 4698abb0f93cSkardel } 4699abb0f93cSkardel 4700abb0f93cSkardel 4701abb0f93cSkardel /* 4702abb0f93cSkardel * Find the given address with the all given flags set in the list 4703abb0f93cSkardel */ 47043123f114Skardel static endpt * 4705abb0f93cSkardel find_flagged_addr_in_list( 4706abb0f93cSkardel sockaddr_u * addr, 47073123f114Skardel u_int32 flags 4708abb0f93cSkardel ) 4709abb0f93cSkardel { 4710abb0f93cSkardel remaddr_t *entry; 4711abb0f93cSkardel 4712abb0f93cSkardel DPRINTF(4, ("Finding addr %s with flags %d in list: ", 4713abb0f93cSkardel stoa(addr), flags)); 4714abb0f93cSkardel 4715abb0f93cSkardel for (entry = remoteaddr_list; 4716abb0f93cSkardel entry != NULL; 4717abb0f93cSkardel entry = entry->link) 4718abb0f93cSkardel 4719abb0f93cSkardel if (SOCK_EQ(&entry->addr, addr) 47203123f114Skardel && (entry->ep->flags & flags) == flags) { 4721abb0f93cSkardel 4722abb0f93cSkardel DPRINTF(4, ("FOUND\n")); 47233123f114Skardel return entry->ep; 4724abb0f93cSkardel } 4725abb0f93cSkardel 4726abb0f93cSkardel DPRINTF(4, ("NOT FOUND\n")); 4727abb0f93cSkardel return NULL; 4728abb0f93cSkardel } 4729abb0f93cSkardel 4730abb0f93cSkardel 47313123f114Skardel const char * 47323123f114Skardel localaddrtoa( 47333123f114Skardel endpt *la 47343123f114Skardel ) 47353123f114Skardel { 47363123f114Skardel return (NULL == la) 47373123f114Skardel ? "<null>" 47383123f114Skardel : stoa(&la->sin); 47393123f114Skardel } 47403123f114Skardel 47413123f114Skardel 4742abb0f93cSkardel #ifdef HAS_ROUTING_SOCKET 4743abb0f93cSkardel # ifndef UPDATE_GRACE 4744*eabc0478Schristos # define UPDATE_GRACE 3 /* min. UPDATE_GRACE - 1 seconds before scanning */ 4745abb0f93cSkardel # endif 4746abb0f93cSkardel 4747abb0f93cSkardel static void 4748abb0f93cSkardel process_routing_msgs(struct asyncio_reader *reader) 4749abb0f93cSkardel { 4750*eabc0478Schristos static void * buffer; 4751*eabc0478Schristos static size_t buffsz = 8192; 4752*eabc0478Schristos int cnt, new, msg_type; 4753*eabc0478Schristos socklen_t len; 4754abb0f93cSkardel #ifdef HAVE_RTNETLINK 4755abb0f93cSkardel struct nlmsghdr *nh; 4756abb0f93cSkardel #else 47572950cc38Schristos struct rt_msghdr rtm; 4758abb0f93cSkardel char *p; 4759*eabc0478Schristos char *endp; 4760abb0f93cSkardel #endif 4761abb0f93cSkardel 4762*eabc0478Schristos if (scan_addrs_once) { 4763abb0f93cSkardel /* 4764abb0f93cSkardel * discard ourselves if we are not needed any more 4765abb0f93cSkardel * usually happens when running unprivileged 4766abb0f93cSkardel */ 4767*eabc0478Schristos goto disable; 4768abb0f93cSkardel } 4769abb0f93cSkardel 4770*eabc0478Schristos if (NULL == buffer) { 4771*eabc0478Schristos buffer = emalloc(buffsz); 4772*eabc0478Schristos } 4773*eabc0478Schristos 4774*eabc0478Schristos cnt = read(reader->fd, buffer, buffsz); 4775abb0f93cSkardel 4776abb0f93cSkardel if (cnt < 0) { 4777af12ab5eSchristos if (errno == ENOBUFS) { 4778*eabc0478Schristos /* increase socket buffer by 25% */ 4779*eabc0478Schristos len = sizeof cnt; 4780*eabc0478Schristos if (0 > getsockopt(reader->fd, SOL_SOCKET, SO_RCVBUF, &cnt, &len) || 4781*eabc0478Schristos sizeof cnt != len) { 4782*eabc0478Schristos msyslog(LOG_ERR, 4783*eabc0478Schristos "routing getsockopt SO_RCVBUF %u %u: %m - disabling", 4784*eabc0478Schristos (u_int)cnt, (u_int)sizeof cnt); 4785*eabc0478Schristos goto disable; 4786*eabc0478Schristos } 4787*eabc0478Schristos new = cnt + (cnt / 4); 4788*eabc0478Schristos if (0 > setsockopt(reader->fd, SOL_SOCKET, SO_RCVBUF, &new, sizeof new)) { 4789*eabc0478Schristos msyslog(LOG_ERR, 4790*eabc0478Schristos "routing setsockopt SO_RCVBUF %d -> %d: %m - disabling", 4791*eabc0478Schristos cnt, new); 4792*eabc0478Schristos goto disable; 4793*eabc0478Schristos } 4794*eabc0478Schristos } else { 4795af12ab5eSchristos msyslog(LOG_ERR, 4796af12ab5eSchristos "routing socket reports: %m - disabling"); 4797*eabc0478Schristos disable: 4798abb0f93cSkardel remove_asyncio_reader(reader); 4799abb0f93cSkardel delete_asyncio_reader(reader); 4800abb0f93cSkardel return; 4801abb0f93cSkardel } 4802*eabc0478Schristos } 4803abb0f93cSkardel 4804abb0f93cSkardel /* 4805abb0f93cSkardel * process routing message 4806abb0f93cSkardel */ 4807abb0f93cSkardel #ifdef HAVE_RTNETLINK 4808*eabc0478Schristos for (nh = buffer; NLMSG_OK(nh, cnt); nh = NLMSG_NEXT(nh, cnt)) 480950c1baceSchristos { 4810abb0f93cSkardel msg_type = nh->nlmsg_type; 4811abb0f93cSkardel #else 4812*eabc0478Schristos for (p = buffer, endp = p + cnt; 4813*eabc0478Schristos (p + sizeof(struct rt_msghdr)) <= endp; 481450c1baceSchristos p += rtm.rtm_msglen) 481550c1baceSchristos { 48162950cc38Schristos memcpy(&rtm, p, sizeof(rtm)); 48172950cc38Schristos if (rtm.rtm_version != RTM_VERSION) { 4818abb0f93cSkardel msyslog(LOG_ERR, 4819abb0f93cSkardel "version mismatch (got %d - expected %d) on routing socket - disabling", 48202950cc38Schristos rtm.rtm_version, RTM_VERSION); 4821abb0f93cSkardel 4822abb0f93cSkardel remove_asyncio_reader(reader); 4823abb0f93cSkardel delete_asyncio_reader(reader); 4824abb0f93cSkardel return; 4825abb0f93cSkardel } 48262950cc38Schristos msg_type = rtm.rtm_type; 4827*eabc0478Schristos #endif /* !HAVE_RTNETLINK */ 4828abb0f93cSkardel switch (msg_type) { 4829abb0f93cSkardel #ifdef RTM_NEWADDR 4830abb0f93cSkardel case RTM_NEWADDR: 4831abb0f93cSkardel #endif 4832abb0f93cSkardel #ifdef RTM_DELADDR 4833abb0f93cSkardel case RTM_DELADDR: 4834abb0f93cSkardel #endif 4835abb0f93cSkardel #ifdef RTM_ADD 4836abb0f93cSkardel case RTM_ADD: 4837abb0f93cSkardel #endif 4838abb0f93cSkardel #ifdef RTM_DELETE 4839abb0f93cSkardel case RTM_DELETE: 4840abb0f93cSkardel #endif 4841abb0f93cSkardel #ifdef RTM_REDIRECT 4842abb0f93cSkardel case RTM_REDIRECT: 4843abb0f93cSkardel #endif 4844abb0f93cSkardel #ifdef RTM_CHANGE 4845abb0f93cSkardel case RTM_CHANGE: 4846abb0f93cSkardel #endif 4847abb0f93cSkardel #ifdef RTM_IFINFO 4848abb0f93cSkardel case RTM_IFINFO: 4849abb0f93cSkardel #endif 4850abb0f93cSkardel #ifdef RTM_NEWLINK 4851abb0f93cSkardel case RTM_NEWLINK: 4852abb0f93cSkardel #endif 4853abb0f93cSkardel #ifdef RTM_DELLINK 4854abb0f93cSkardel case RTM_DELLINK: 4855abb0f93cSkardel #endif 4856abb0f93cSkardel #ifdef RTM_NEWROUTE 4857abb0f93cSkardel case RTM_NEWROUTE: 4858abb0f93cSkardel #endif 4859abb0f93cSkardel #ifdef RTM_DELROUTE 4860abb0f93cSkardel case RTM_DELROUTE: 4861abb0f93cSkardel #endif 4862abb0f93cSkardel /* 4863abb0f93cSkardel * we are keen on new and deleted addresses and 4864abb0f93cSkardel * if an interface goes up and down or routing 4865abb0f93cSkardel * changes 4866abb0f93cSkardel */ 4867abb0f93cSkardel DPRINTF(3, ("routing message op = %d: scheduling interface update\n", 4868abb0f93cSkardel msg_type)); 4869*eabc0478Schristos endpt_scan_timer = UPDATE_GRACE + current_time; 4870abb0f93cSkardel break; 4871abb0f93cSkardel #ifdef HAVE_RTNETLINK 4872abb0f93cSkardel case NLMSG_DONE: 4873abb0f93cSkardel /* end of multipart message */ 4874abb0f93cSkardel return; 4875abb0f93cSkardel #endif 4876abb0f93cSkardel default: 4877abb0f93cSkardel /* 4878abb0f93cSkardel * the rest doesn't bother us. 4879abb0f93cSkardel */ 4880abb0f93cSkardel DPRINTF(4, ("routing message op = %d: ignored\n", 4881abb0f93cSkardel msg_type)); 4882abb0f93cSkardel break; 4883abb0f93cSkardel } 4884abb0f93cSkardel } 4885abb0f93cSkardel } 4886abb0f93cSkardel 4887abb0f93cSkardel /* 4888abb0f93cSkardel * set up routing notifications 4889abb0f93cSkardel */ 4890abb0f93cSkardel static void 4891*eabc0478Schristos init_async_notifications(void) 4892abb0f93cSkardel { 4893abb0f93cSkardel struct asyncio_reader *reader; 4894abb0f93cSkardel #ifdef HAVE_RTNETLINK 4895abb0f93cSkardel int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 4896abb0f93cSkardel struct sockaddr_nl sa; 4897abb0f93cSkardel #else 4898*eabc0478Schristos int fd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); 4899ddf02b26Sroy #ifdef SO_RERROR 4900ddf02b26Sroy int on = 1; 4901ddf02b26Sroy #endif 4902abb0f93cSkardel #endif 4903f2128fd5Sroy #ifdef RO_MSGFILTER 4904f2128fd5Sroy unsigned char msgfilter[] = { 4905f2128fd5Sroy #ifdef RTM_NEWADDR 4906f2128fd5Sroy RTM_NEWADDR, 4907f2128fd5Sroy #endif 4908f2128fd5Sroy #ifdef RTM_DELADDR 4909f2128fd5Sroy RTM_DELADDR, 4910f2128fd5Sroy #endif 4911f2128fd5Sroy #ifdef RTM_ADD 4912f2128fd5Sroy RTM_ADD, 4913f2128fd5Sroy #endif 4914f2128fd5Sroy #ifdef RTM_DELETE 4915f2128fd5Sroy RTM_DELETE, 4916f2128fd5Sroy #endif 4917f2128fd5Sroy #ifdef RTM_REDIRECT 4918f2128fd5Sroy RTM_REDIRECT, 4919f2128fd5Sroy #endif 4920f2128fd5Sroy #ifdef RTM_CHANGE 4921f2128fd5Sroy RTM_CHANGE, 4922f2128fd5Sroy #endif 4923f2128fd5Sroy #ifdef RTM_IFINFO 4924f2128fd5Sroy RTM_IFINFO, 4925f2128fd5Sroy #endif 4926f2128fd5Sroy #ifdef RTM_NEWLINK 4927f2128fd5Sroy RTM_NEWLINK, 4928f2128fd5Sroy #endif 4929f2128fd5Sroy #ifdef RTM_DELLINK 4930f2128fd5Sroy RTM_DELLINK, 4931f2128fd5Sroy #endif 4932f2128fd5Sroy #ifdef RTM_NEWROUTE 4933f2128fd5Sroy RTM_NEWROUTE, 4934f2128fd5Sroy #endif 4935f2128fd5Sroy #ifdef RTM_DELROUTE 4936f2128fd5Sroy RTM_DELROUTE, 4937f2128fd5Sroy #endif 4938f2128fd5Sroy }; 4939f2128fd5Sroy #endif /* !RO_MSGFILTER */ 4940f2128fd5Sroy 4941abb0f93cSkardel if (fd < 0) { 4942abb0f93cSkardel msyslog(LOG_ERR, 4943abb0f93cSkardel "unable to open routing socket (%m) - using polled interface update"); 4944abb0f93cSkardel return; 4945abb0f93cSkardel } 4946abb0f93cSkardel 4947abb0f93cSkardel fd = move_fd(fd); 4948abb0f93cSkardel #ifdef HAVE_RTNETLINK 49492950cc38Schristos ZERO(sa); 4950abb0f93cSkardel sa.nl_family = PF_NETLINK; 4951abb0f93cSkardel sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR 4952abb0f93cSkardel | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_ROUTE 4953abb0f93cSkardel | RTMGRP_IPV4_MROUTE | RTMGRP_IPV6_ROUTE 4954abb0f93cSkardel | RTMGRP_IPV6_MROUTE; 4955abb0f93cSkardel if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 4956abb0f93cSkardel msyslog(LOG_ERR, 4957abb0f93cSkardel "bind failed on routing socket (%m) - using polled interface update"); 4958abb0f93cSkardel return; 4959abb0f93cSkardel } 4960abb0f93cSkardel #endif 4961f2128fd5Sroy #ifdef RO_MSGFILTER 4962f2128fd5Sroy if (setsockopt(fd, PF_ROUTE, RO_MSGFILTER, 4963f2128fd5Sroy &msgfilter, sizeof(msgfilter)) == -1) 4964f2128fd5Sroy msyslog(LOG_ERR, "RO_MSGFILTER: %m"); 4965f2128fd5Sroy #endif 4966ddf02b26Sroy #ifdef SO_RERROR 4967ddf02b26Sroy if (setsockopt(fd, SOL_SOCKET, SO_RERROR, &on, sizeof(on)) == -1) 4968ddf02b26Sroy msyslog(LOG_ERR, "SO_RERROR: %m"); 4969ddf02b26Sroy #endif 49702950cc38Schristos make_socket_nonblocking(fd); 4971abb0f93cSkardel #if defined(HAVE_SIGNALED_IO) 4972abb0f93cSkardel init_socket_sig(fd); 4973abb0f93cSkardel #endif /* HAVE_SIGNALED_IO */ 4974abb0f93cSkardel 4975abb0f93cSkardel reader = new_asyncio_reader(); 4976abb0f93cSkardel 4977abb0f93cSkardel reader->fd = fd; 4978abb0f93cSkardel reader->receiver = process_routing_msgs; 4979abb0f93cSkardel 4980abb0f93cSkardel add_asyncio_reader(reader, FD_TYPE_SOCKET); 4981abb0f93cSkardel msyslog(LOG_INFO, 4982abb0f93cSkardel "Listening on routing socket on fd #%d for interface updates", 4983abb0f93cSkardel fd); 4984abb0f93cSkardel } 4985abb0f93cSkardel #else 4986abb0f93cSkardel /* HAS_ROUTING_SOCKET not defined */ 4987abb0f93cSkardel static void 4988abb0f93cSkardel init_async_notifications(void) 4989abb0f93cSkardel { 4990abb0f93cSkardel } 4991abb0f93cSkardel #endif 4992