154359Sroberto/* 254359Sroberto * ntp_io.c - input/output routines for ntpd. The socket-opening code 354359Sroberto * was shamelessly stolen from ntpd. 454359Sroberto */ 554359Sroberto 654359Sroberto#ifdef HAVE_CONFIG_H 754359Sroberto# include <config.h> 854359Sroberto#endif 954359Sroberto 10290000Sglebius#include <stdio.h> 11290000Sglebius#include <signal.h> 12290000Sglebius#ifdef HAVE_FNMATCH_H 13290000Sglebius# include <fnmatch.h> 14290000Sglebius# if !defined(FNM_CASEFOLD) && defined(FNM_IGNORECASE) 15290000Sglebius# define FNM_CASEFOLD FNM_IGNORECASE 16290000Sglebius# endif 17290000Sglebius#endif 18290000Sglebius#ifdef HAVE_SYS_PARAM_H 19290000Sglebius# include <sys/param.h> 20290000Sglebius#endif 21290000Sglebius#ifdef HAVE_SYS_IOCTL_H 22290000Sglebius# include <sys/ioctl.h> 23290000Sglebius#endif 24290000Sglebius#ifdef HAVE_SYS_SOCKIO_H /* UXPV: SIOC* #defines (Frank Vance <fvance@waii.com>) */ 25290000Sglebius# include <sys/sockio.h> 26290000Sglebius#endif 27290000Sglebius#ifdef HAVE_SYS_UIO_H 28290000Sglebius# include <sys/uio.h> 29290000Sglebius#endif 30290000Sglebius 3182498Sroberto#include "ntp_machine.h" 3282498Sroberto#include "ntpd.h" 3382498Sroberto#include "ntp_io.h" 3482498Sroberto#include "iosignal.h" 35290000Sglebius#include "ntp_lists.h" 3682498Sroberto#include "ntp_refclock.h" 3782498Sroberto#include "ntp_stdlib.h" 38290000Sglebius#include "ntp_worker.h" 39182007Sroberto#include "ntp_request.h" 40290000Sglebius#include "ntp_assert.h" 41290000Sglebius#include "timevalops.h" 42290000Sglebius#include "timespecops.h" 43290000Sglebius#include "ntpd-opts.h" 44293894Sglebius#include "safecast.h" 4582498Sroberto 46132451Sroberto/* Don't include ISC's version of IPv6 variables and structures */ 47132451Sroberto#define ISC_IPV6_H 1 48290000Sglebius#include <isc/mem.h> 49132451Sroberto#include <isc/interfaceiter.h> 50290000Sglebius#include <isc/netaddr.h> 51132451Sroberto#include <isc/result.h> 52290000Sglebius#include <isc/sockaddr.h> 53132451Sroberto 54132451Sroberto#ifdef SIM 55132451Sroberto#include "ntpsim.h" 56132451Sroberto#endif 57132451Sroberto 58290000Sglebius#ifdef HAS_ROUTING_SOCKET 59290000Sglebius# include <net/route.h> 60290000Sglebius# ifdef HAVE_RTNETLINK 61290000Sglebius# include <linux/rtnetlink.h> 62290000Sglebius# endif 6354359Sroberto#endif 6454359Sroberto 65182007Sroberto/* 66182007Sroberto * setsockopt does not always have the same arg declaration 67182007Sroberto * across all platforms. If it's not defined we make it empty 68182007Sroberto */ 69182007Sroberto 70182007Sroberto#ifndef SETSOCKOPT_ARG_CAST 71182007Sroberto#define SETSOCKOPT_ARG_CAST 72182007Sroberto#endif 73182007Sroberto 74290000Sglebiusextern int listen_to_virtual_ips; 75182007Sroberto 76290000Sglebius#ifndef IPTOS_DSCP_EF 77290000Sglebius#define IPTOS_DSCP_EF 0xb8 78290000Sglebius#endif 79290000Sglebiusint qos = IPTOS_DSCP_EF; /* QoS RFC3246 */ 80182007Sroberto 81290000Sglebius#ifdef LEAP_SMEAR 82290000Sglebius/* TODO burnicki: This should be moved to ntp_timer.c, but if we do so 83290000Sglebius * we get a linker error. Since we're running out of time before the leap 84290000Sglebius * second occurs, we let it here where it just works. 85290000Sglebius */ 86290000Sglebiusint leap_smear_intv; 87290000Sglebius#endif 88182007Sroberto 89290000Sglebius/* 90290000Sglebius * NIC rule entry 91290000Sglebius */ 92290000Sglebiustypedef struct nic_rule_tag nic_rule; 93182007Sroberto 94290000Sglebiusstruct nic_rule_tag { 95290000Sglebius nic_rule * next; 96290000Sglebius nic_rule_action action; 97290000Sglebius nic_rule_match match_type; 98290000Sglebius char * if_name; 99290000Sglebius sockaddr_u addr; 100290000Sglebius int prefixlen; 101290000Sglebius}; 102182007Sroberto 103290000Sglebius/* 104290000Sglebius * NIC rule listhead. Entries are added at the head so that the first 105290000Sglebius * match in the list is the last matching rule specified. 106290000Sglebius */ 107290000Sglebiusnic_rule *nic_rule_list; 108199995Sume 109106163Sroberto 110290000Sglebius#if defined(SO_BINTIME) && defined(SCM_BINTIME) && defined(CMSG_FIRSTHDR) 111290000Sglebius# define HAVE_PACKET_TIMESTAMP 112290000Sglebius# define HAVE_BINTIME 113290000Sglebius# ifdef BINTIME_CTLMSGBUF_SIZE 114290000Sglebius# define CMSG_BUFSIZE BINTIME_CTLMSGBUF_SIZE 115290000Sglebius# else 116290000Sglebius# define CMSG_BUFSIZE 1536 /* moderate default */ 117290000Sglebius# endif 118290000Sglebius#elif defined(SO_TIMESTAMPNS) && defined(SCM_TIMESTAMPNS) && defined(CMSG_FIRSTHDR) 119290000Sglebius# define HAVE_PACKET_TIMESTAMP 120290000Sglebius# define HAVE_TIMESTAMPNS 121290000Sglebius# ifdef TIMESTAMPNS_CTLMSGBUF_SIZE 122290000Sglebius# define CMSG_BUFSIZE TIMESTAMPNS_CTLMSGBUF_SIZE 123290000Sglebius# else 124290000Sglebius# define CMSG_BUFSIZE 1536 /* moderate default */ 125290000Sglebius# endif 126290000Sglebius#elif defined(SO_TIMESTAMP) && defined(SCM_TIMESTAMP) && defined(CMSG_FIRSTHDR) 127290000Sglebius# define HAVE_PACKET_TIMESTAMP 128290000Sglebius# define HAVE_TIMESTAMP 129290000Sglebius# ifdef TIMESTAMP_CTLMSGBUF_SIZE 130290000Sglebius# define CMSG_BUFSIZE TIMESTAMP_CTLMSGBUF_SIZE 131290000Sglebius# else 132290000Sglebius# define CMSG_BUFSIZE 1536 /* moderate default */ 133290000Sglebius# endif 134182007Sroberto#else 135182007Sroberto/* fill in for old/other timestamp interfaces */ 136182007Sroberto#endif 137182007Sroberto 138132451Sroberto#if defined(SYS_WINNT) 139290000Sglebius#include "win32_io.h" 140132451Sroberto#include <isc/win32os.h> 14154359Sroberto#endif 14254359Sroberto 143200576Sroberto/* 14454359Sroberto * We do asynchronous input using the SIGIO facility. A number of 14554359Sroberto * recvbuf buffers are preallocated for input. In the signal 14654359Sroberto * handler we poll to see which sockets are ready and read the 14754359Sroberto * packets from them into the recvbuf's along with a time stamp and 14854359Sroberto * an indication of the source host and the interface it was received 14954359Sroberto * through. This allows us to get as accurate receive time stamps 15054359Sroberto * as possible independent of other processing going on. 15154359Sroberto * 15254359Sroberto * We watch the number of recvbufs available to the signal handler 15354359Sroberto * and allocate more when this number drops below the low water 15454359Sroberto * mark. If the signal handler should run out of buffers in the 15554359Sroberto * interim it will drop incoming frames, the idea being that it is 15654359Sroberto * better to drop a packet than to be inaccurate. 15754359Sroberto */ 15854359Sroberto 15954359Sroberto 16054359Sroberto/* 16154359Sroberto * Other statistics of possible interest 16254359Sroberto */ 16354359Srobertovolatile u_long packets_dropped; /* total number of packets dropped on reception */ 16454359Srobertovolatile u_long packets_ignored; /* packets received on wild card interface */ 16554359Srobertovolatile u_long packets_received; /* total number of packets received */ 166290000Sglebius u_long packets_sent; /* total number of packets sent */ 167290000Sglebius u_long packets_notsent; /* total number of packets which couldn't be sent */ 16854359Sroberto 16954359Srobertovolatile u_long handler_calls; /* number of calls to interrupt handler */ 17054359Srobertovolatile u_long handler_pkts; /* number of pkts received by handler */ 17154359Srobertou_long io_timereset; /* time counters were reset */ 17254359Sroberto 17354359Sroberto/* 17454359Sroberto * Interface stuff 17554359Sroberto */ 176290000Sglebiusendpt * any_interface; /* wildcard ipv4 interface */ 177290000Sglebiusendpt * any6_interface; /* wildcard ipv6 interface */ 178290000Sglebiusendpt * loopback_interface; /* loopback ipv4 interface */ 179182007Sroberto 180290000Sglebiusisc_boolean_t broadcast_client_enabled; /* is broadcast client enabled */ 181290000Sglebiusu_int sys_ifnum; /* next .ifnum to assign */ 182132451Srobertoint ninterfaces; /* Total number of interfaces */ 18354359Sroberto 184290000Sglebiusint disable_dynamic_updates; /* scan interfaces once only */ 185182007Sroberto 18654359Sroberto#ifdef REFCLOCK 18754359Sroberto/* 18854359Sroberto * Refclock stuff. We keep a chain of structures with data concerning 18954359Sroberto * the guys we are doing I/O for. 19054359Sroberto */ 19154359Srobertostatic struct refclockio *refio; 19254359Sroberto#endif /* REFCLOCK */ 19354359Sroberto 19454359Sroberto/* 195290000Sglebius * File descriptor masks etc. for call to select 196290000Sglebius * Not needed for I/O Completion Ports or anything outside this file 197132451Sroberto */ 198290000Sglebiusstatic fd_set activefds; 199290000Sglebiusstatic int maxactivefd; 200132451Sroberto 201132451Sroberto/* 202182007Sroberto * bit alternating value to detect verified interfaces during an update cycle 203182007Sroberto */ 204290000Sglebiusstatic u_short sys_interphase = 0; 20554359Sroberto 206290000Sglebiusstatic endpt * new_interface(endpt *); 207290000Sglebiusstatic void add_interface(endpt *); 208290000Sglebiusstatic int update_interfaces(u_short, interface_receiver_t, 209290000Sglebius void *); 210290000Sglebiusstatic void remove_interface(endpt *); 211290000Sglebiusstatic endpt * create_interface(u_short, endpt *); 212182007Sroberto 213290000Sglebiusstatic int is_wildcard_addr (const sockaddr_u *); 214182007Sroberto 215182007Sroberto/* 216182007Sroberto * Multicast functions 217182007Sroberto */ 218290000Sglebiusstatic isc_boolean_t addr_ismulticast (sockaddr_u *); 219290000Sglebiusstatic isc_boolean_t is_anycast (sockaddr_u *, 220290000Sglebius const char *); 221290000Sglebius 222182007Sroberto/* 223182007Sroberto * Not all platforms support multicast 224182007Sroberto */ 225182007Sroberto#ifdef MCAST 226290000Sglebiusstatic isc_boolean_t socket_multicast_enable (endpt *, sockaddr_u *); 227290000Sglebiusstatic isc_boolean_t socket_multicast_disable(endpt *, sockaddr_u *); 228132451Sroberto#endif 22954359Sroberto 230182007Sroberto#ifdef DEBUG 231290000Sglebiusstatic void interface_dump (const endpt *); 232290000Sglebiusstatic void sockaddr_dump (const sockaddr_u *); 233290000Sglebiusstatic void print_interface (const endpt *, const char *, const char *); 234290000Sglebius#define DPRINT_INTERFACE(level, args) do { if (debug >= (level)) { print_interface args; } } while (0) 235182007Sroberto#else 236290000Sglebius#define DPRINT_INTERFACE(level, args) do {} while (0) 237182007Sroberto#endif 238182007Sroberto 239132451Srobertotypedef struct vsock vsock_t; 240182007Srobertoenum desc_type { FD_TYPE_SOCKET, FD_TYPE_FILE }; 241132451Sroberto 242132451Srobertostruct vsock { 243290000Sglebius vsock_t * link; 244290000Sglebius SOCKET fd; 245290000Sglebius enum desc_type type; 246132451Sroberto}; 247132451Sroberto 248290000Sglebiusvsock_t *fd_list; 249290000Sglebius 250182007Sroberto#if !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) 251182007Sroberto/* 252182007Sroberto * async notification processing (e. g. routing sockets) 253182007Sroberto */ 254182007Sroberto/* 255182007Sroberto * support for receiving data on fd that is not a refclock or a socket 256182007Sroberto * like e. g. routing sockets 257182007Sroberto */ 258182007Srobertostruct asyncio_reader { 259290000Sglebius struct asyncio_reader *link; /* the list this is being kept in */ 260290000Sglebius SOCKET fd; /* fd to be read */ 261290000Sglebius void *data; /* possibly local data */ 262182007Sroberto void (*receiver)(struct asyncio_reader *); /* input handler */ 263182007Sroberto}; 264132451Sroberto 265290000Sglebiusstruct asyncio_reader *asyncio_reader_list; 266182007Sroberto 267290000Sglebiusstatic void delete_asyncio_reader (struct asyncio_reader *); 268290000Sglebiusstatic struct asyncio_reader *new_asyncio_reader (void); 269290000Sglebiusstatic void add_asyncio_reader (struct asyncio_reader *, enum desc_type); 270290000Sglebiusstatic void remove_asyncio_reader (struct asyncio_reader *); 271182007Sroberto 272182007Sroberto#endif /* !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) */ 273182007Sroberto 274290000Sglebiusstatic void init_async_notifications (void); 275182007Sroberto 276290000Sglebiusstatic int addr_eqprefix (const sockaddr_u *, const sockaddr_u *, 277290000Sglebius int); 278290000Sglebiusstatic int addr_samesubnet (const sockaddr_u *, const sockaddr_u *, 279290000Sglebius const sockaddr_u *, const sockaddr_u *); 280290000Sglebiusstatic int create_sockets (u_short); 281290000Sglebiusstatic SOCKET open_socket (sockaddr_u *, int, int, endpt *); 282290000Sglebiusstatic void set_reuseaddr (int); 283290000Sglebiusstatic isc_boolean_t socket_broadcast_enable (struct interface *, SOCKET, sockaddr_u *); 284294904Sdelphij 285294904Sdelphij#if !defined(HAVE_IO_COMPLETION_PORT) && !defined(HAVE_SIGNALED_IO) 286294904Sdelphijstatic char * fdbits (int, const fd_set *); 287294904Sdelphij#endif 288290000Sglebius#ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES 289290000Sglebiusstatic isc_boolean_t socket_broadcast_disable (struct interface *, sockaddr_u *); 290290000Sglebius#endif 291182007Sroberto 292132451Srobertotypedef struct remaddr remaddr_t; 293132451Sroberto 294132451Srobertostruct remaddr { 295290000Sglebius remaddr_t * link; 296290000Sglebius sockaddr_u addr; 297290000Sglebius endpt * ep; 298132451Sroberto}; 299132451Sroberto 300290000Sglebiusremaddr_t * remoteaddr_list; 301290000Sglebiusendpt * ep_list; /* complete endpt list */ 302290000Sglebiusendpt * mc4_list; /* IPv4 mcast-capable unicast endpts */ 303290000Sglebiusendpt * mc6_list; /* IPv6 mcast-capable unicast endpts */ 304132451Sroberto 305290000Sglebiusstatic endpt * wildipv4; 306290000Sglebiusstatic endpt * wildipv6; 307132451Sroberto 308290000Sglebius#ifdef SYS_WINNT 309290000Sglebiusint accept_wildcard_if_for_winnt; 310290000Sglebius#else 311290000Sglebiusconst int accept_wildcard_if_for_winnt = FALSE; 312290000Sglebius#endif 313182007Sroberto 314290000Sglebiusstatic void add_fd_to_list (SOCKET, enum desc_type); 315290000Sglebiusstatic endpt * find_addr_in_list (sockaddr_u *); 316290000Sglebiusstatic endpt * find_flagged_addr_in_list(sockaddr_u *, u_int32); 317290000Sglebiusstatic void delete_addr_from_list (sockaddr_u *); 318290000Sglebiusstatic void delete_interface_from_list(endpt *); 319290000Sglebiusstatic void close_and_delete_fd_from_list(SOCKET); 320290000Sglebiusstatic void add_addr_to_list (sockaddr_u *, endpt *); 321290000Sglebiusstatic void create_wildcards (u_short); 322290000Sglebiusstatic endpt * findlocalinterface (sockaddr_u *, int, int); 323290000Sglebiusstatic endpt * findclosestinterface (sockaddr_u *, int); 324290000Sglebius#ifdef DEBUG 325290000Sglebiusstatic const char * action_text (nic_rule_action); 326290000Sglebius#endif 327290000Sglebiusstatic nic_rule_action interface_action(char *, sockaddr_u *, u_int32); 328290000Sglebiusstatic void convert_isc_if (isc_interface_t *, 329290000Sglebius endpt *, u_short); 330290000Sglebiusstatic void calc_addr_distance(sockaddr_u *, 331290000Sglebius const sockaddr_u *, 332290000Sglebius const sockaddr_u *); 333290000Sglebiusstatic int cmp_addr_distance(const sockaddr_u *, 334290000Sglebius const sockaddr_u *); 335182007Sroberto 336182007Sroberto/* 337182007Sroberto * Routines to read the ntp packets 338182007Sroberto */ 339182007Sroberto#if !defined(HAVE_IO_COMPLETION_PORT) 340290000Sglebiusstatic inline int read_network_packet (SOCKET, struct interface *, l_fp); 341290000Sglebiusstatic void ntpd_addremove_io_fd (int, int, int); 342294904Sdelphijstatic void input_handler_scan (const l_fp*, const fd_set*); 343294904Sdelphijstatic int/*BOOL*/ sanitize_fdset (int errc); 344290000Sglebius#ifdef REFCLOCK 345290000Sglebiusstatic inline int read_refclock_packet (SOCKET, struct refclockio *, l_fp); 346182007Sroberto#endif 347294904Sdelphij#ifdef HAVE_SIGNALED_IO 348294904Sdelphijstatic void input_handler (l_fp*); 349290000Sglebius#endif 350294904Sdelphij#endif 351182007Sroberto 352290000Sglebius 353290000Sglebius#ifndef HAVE_IO_COMPLETION_PORT 354200576Srobertovoid 355290000Sglebiusmaintain_activefds( 356290000Sglebius int fd, 357290000Sglebius int closing 358200576Sroberto ) 359200576Sroberto{ 360290000Sglebius int i; 361132451Sroberto 362290000Sglebius if (fd < 0 || fd >= FD_SETSIZE) { 363290000Sglebius msyslog(LOG_ERR, 364290000Sglebius "Too many sockets in use, FD_SETSIZE %d exceeded by fd %d", 365290000Sglebius FD_SETSIZE, fd); 366290000Sglebius exit(1); 367200576Sroberto } 368182007Sroberto 369290000Sglebius if (!closing) { 370290000Sglebius FD_SET(fd, &activefds); 371290000Sglebius maxactivefd = max(fd, maxactivefd); 372290000Sglebius } else { 373290000Sglebius FD_CLR(fd, &activefds); 374290000Sglebius if (maxactivefd && fd == maxactivefd) { 375290000Sglebius for (i = maxactivefd - 1; i >= 0; i--) 376290000Sglebius if (FD_ISSET(i, &activefds)) { 377290000Sglebius maxactivefd = i; 378290000Sglebius break; 379290000Sglebius } 380290000Sglebius INSIST(fd != maxactivefd); 381290000Sglebius } 382182007Sroberto } 383182007Sroberto} 384290000Sglebius#endif /* !HAVE_IO_COMPLETION_PORT */ 385182007Sroberto 386290000Sglebius 387182007Sroberto#ifdef DEBUG_TIMING 388182007Sroberto/* 389182007Sroberto * collect timing information for various processing 390290000Sglebius * paths. currently we only pass them on to the file 391182007Sroberto * for later processing. this could also do histogram 392182007Sroberto * based analysis in other to reduce the load (and skew) 393182007Sroberto * dur to the file output 394182007Sroberto */ 395182007Srobertovoid 396182007Srobertocollect_timing(struct recvbuf *rb, const char *tag, int count, l_fp *dts) 397182007Sroberto{ 398290000Sglebius char buf[256]; 399182007Sroberto 400290000Sglebius snprintf(buf, sizeof(buf), "%s %d %s %s", 401290000Sglebius (rb != NULL) 402290000Sglebius ? ((rb->dstadr != NULL) 403290000Sglebius ? stoa(&rb->recv_srcadr) 404290000Sglebius : "-REFCLOCK-") 405290000Sglebius : "-", 406182007Sroberto count, lfptoa(dts, 9), tag); 407182007Sroberto record_timing_stats(buf); 408182007Sroberto} 409182007Sroberto#endif 410290000Sglebius 411182007Sroberto/* 412182007Sroberto * About dynamic interfaces, sockets, reception and more... 413182007Sroberto * 414182007Sroberto * the code solves following tasks: 415182007Sroberto * 416182007Sroberto * - keep a current list of active interfaces in order 417182007Sroberto * to bind to to the interface address on NTP_PORT so that 418182007Sroberto * all wild and specific bindings for NTP_PORT are taken by ntpd 419182007Sroberto * to avoid other daemons messing with the time or sockets. 420290000Sglebius * - all interfaces keep a list of peers that are referencing 421182007Sroberto * the interface in order to quickly re-assign the peers to 422182007Sroberto * new interface in case an interface is deleted (=> gone from system or 423182007Sroberto * down) 424182007Sroberto * - have a preconfigured socket ready with the right local address 425182007Sroberto * for transmission and reception 426182007Sroberto * - have an address list for all destination addresses used within ntpd 427182007Sroberto * to find the "right" preconfigured socket. 428182007Sroberto * - facilitate updating the internal interface list with respect to 429182007Sroberto * the current kernel state 430182007Sroberto * 431182007Sroberto * special issues: 432182007Sroberto * 433182007Sroberto * - mapping of multicast addresses to the interface affected is not always 434182007Sroberto * one to one - especially on hosts with multiple interfaces 435182007Sroberto * the code here currently allocates a separate interface entry for those 436182007Sroberto * multicast addresses 437182007Sroberto * iff it is able to bind to a *new* socket with the multicast address (flags |= MCASTIF) 438182007Sroberto * in case of failure the multicast address is bound to an existing interface. 439182007Sroberto * - on some systems it is perfectly legal to assign the same address to 440182007Sroberto * multiple interfaces. Therefore this code does not keep a list of interfaces 441182007Sroberto * but a list of interfaces that represent a unique address as determined by the kernel 442182007Sroberto * by the procedure in findlocalinterface. Thus it is perfectly legal to see only 443182007Sroberto * one representative of a group of real interfaces if they share the same address. 444290000Sglebius * 445182007Sroberto * Frank Kardel 20050910 446182007Sroberto */ 447182007Sroberto 448182007Sroberto/* 449290000Sglebius * init_io - initialize I/O module. 45054359Sroberto */ 45154359Srobertovoid 45254359Srobertoinit_io(void) 45354359Sroberto{ 454290000Sglebius /* Init buffer free list and stat counters */ 45554359Sroberto init_recvbuff(RECV_INIT); 456290000Sglebius /* update interface every 5 minutes as default */ 457290000Sglebius interface_interval = 300; 45854359Sroberto 459290000Sglebius#ifdef WORK_PIPE 460290000Sglebius addremove_io_fd = &ntpd_addremove_io_fd; 461290000Sglebius#endif 46254359Sroberto 463294904Sdelphij#if defined(SYS_WINNT) 464290000Sglebius init_io_completion_port(); 465294904Sdelphij#elif defined(HAVE_SIGNALED_IO) 466290000Sglebius (void) set_signal(input_handler); 46754359Sroberto#endif 468290000Sglebius} 46954359Sroberto 47054359Sroberto 471290000Sglebiusstatic void 472290000Sglebiusntpd_addremove_io_fd( 473290000Sglebius int fd, 474290000Sglebius int is_pipe, 475290000Sglebius int remove_it 476290000Sglebius ) 477290000Sglebius{ 478290000Sglebius UNUSED_ARG(is_pipe); 479132451Sroberto 480290000Sglebius#ifdef HAVE_SIGNALED_IO 481294904Sdelphij if (!remove_it) 482294904Sdelphij init_socket_sig(fd); 483290000Sglebius#endif /* not HAVE_SIGNALED_IO */ 484132451Sroberto 485290000Sglebius maintain_activefds(fd, remove_it); 486290000Sglebius} 487182007Sroberto 488290000Sglebius 489290000Sglebius/* 490290000Sglebius * io_open_sockets - call socket creation routine 491290000Sglebius */ 492290000Sglebiusvoid 493290000Sglebiusio_open_sockets(void) 494290000Sglebius{ 495290000Sglebius static int already_opened; 496290000Sglebius 497290000Sglebius if (already_opened || HAVE_OPT( SAVECONFIGQUIT )) 498290000Sglebius return; 499290000Sglebius 500290000Sglebius already_opened = 1; 501290000Sglebius 50254359Sroberto /* 50354359Sroberto * Create the sockets 50454359Sroberto */ 50554359Sroberto BLOCKIO(); 506290000Sglebius create_sockets(NTP_PORT); 50754359Sroberto UNBLOCKIO(); 50854359Sroberto 509182007Sroberto init_async_notifications(); 510182007Sroberto 511290000Sglebius DPRINTF(3, ("io_open_sockets: maxactivefd %d\n", maxactivefd)); 512182007Sroberto} 513182007Sroberto 514290000Sglebius 51554359Sroberto#ifdef DEBUG 516182007Sroberto/* 517182007Sroberto * function to dump the contents of the interface structure 518182007Sroberto * for debugging use only. 519182007Sroberto */ 520182007Srobertovoid 521290000Sglebiusinterface_dump(const endpt *itf) 522182007Sroberto{ 523182007Sroberto printf("Dumping interface: %p\n", itf); 524182007Sroberto printf("fd = %d\n", itf->fd); 525182007Sroberto printf("bfd = %d\n", itf->bfd); 526290000Sglebius printf("sin = %s,\n", stoa(&itf->sin)); 527290000Sglebius sockaddr_dump(&itf->sin); 528290000Sglebius printf("bcast = %s,\n", stoa(&itf->bcast)); 529290000Sglebius sockaddr_dump(&itf->bcast); 530290000Sglebius printf("mask = %s,\n", stoa(&itf->mask)); 531290000Sglebius sockaddr_dump(&itf->mask); 532182007Sroberto printf("name = %s\n", itf->name); 533182007Sroberto printf("flags = 0x%08x\n", itf->flags); 534182007Sroberto printf("last_ttl = %d\n", itf->last_ttl); 535182007Sroberto printf("addr_refid = %08x\n", itf->addr_refid); 536182007Sroberto printf("num_mcast = %d\n", itf->num_mcast); 537182007Sroberto printf("received = %ld\n", itf->received); 538182007Sroberto printf("sent = %ld\n", itf->sent); 539182007Sroberto printf("notsent = %ld\n", itf->notsent); 540182007Sroberto printf("ifindex = %u\n", itf->ifindex); 541182007Sroberto printf("peercnt = %u\n", itf->peercnt); 542182007Sroberto printf("phase = %u\n", itf->phase); 543182007Sroberto} 544182007Sroberto 545182007Sroberto/* 546290000Sglebius * sockaddr_dump - hex dump the start of a sockaddr_u 547290000Sglebius */ 548290000Sglebiusstatic void 549290000Sglebiussockaddr_dump(const sockaddr_u *psau) 550290000Sglebius{ 551290000Sglebius /* Limit the size of the sockaddr_in6 hex dump */ 552290000Sglebius const int maxsize = min(32, sizeof(psau->sa6)); 553290000Sglebius const u_char * cp; 554290000Sglebius int i; 555290000Sglebius 556290000Sglebius /* XXX: Should we limit maxsize based on psau->saX.sin_family? */ 557290000Sglebius cp = (const void *)&psau->sa6; 558290000Sglebius 559290000Sglebius for(i = 0; i < maxsize; i++) { 560290000Sglebius printf("%02x", *cp++); 561290000Sglebius if (!((i + 1) % 4)) 562290000Sglebius printf(" "); 563290000Sglebius } 564290000Sglebius printf("\n"); 565290000Sglebius} 566290000Sglebius 567290000Sglebius/* 568182007Sroberto * print_interface - helper to output debug information 569182007Sroberto */ 570182007Srobertostatic void 571290000Sglebiusprint_interface(const endpt *iface, const char *pfx, const char *sfx) 572182007Sroberto{ 573290000Sglebius printf("%sinterface #%d: fd=%d, bfd=%d, name=%s, flags=0x%x, ifindex=%u, sin=%s", 574182007Sroberto pfx, 575182007Sroberto iface->ifnum, 576182007Sroberto iface->fd, 577182007Sroberto iface->bfd, 578182007Sroberto iface->name, 579182007Sroberto iface->flags, 580290000Sglebius iface->ifindex, 581290000Sglebius stoa(&iface->sin)); 582290000Sglebius if (AF_INET == iface->family) { 583290000Sglebius if (iface->flags & INT_BROADCAST) 584290000Sglebius printf(", bcast=%s", stoa(&iface->bcast)); 585290000Sglebius printf(", mask=%s", stoa(&iface->mask)); 586290000Sglebius } 587290000Sglebius printf(", %s:%s", 588290000Sglebius (iface->ignore_packets) 589290000Sglebius ? "Disabled" 590290000Sglebius : "Enabled", 591290000Sglebius sfx); 592182007Sroberto if (debug > 4) /* in-depth debugging only */ 593182007Sroberto interface_dump(iface); 594182007Sroberto} 59554359Sroberto#endif 596182007Sroberto 597182007Sroberto#if !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) 598182007Sroberto/* 599182007Sroberto * create an asyncio_reader structure 600182007Sroberto */ 601182007Srobertostatic struct asyncio_reader * 602290000Sglebiusnew_asyncio_reader(void) 603182007Sroberto{ 604182007Sroberto struct asyncio_reader *reader; 605182007Sroberto 606290000Sglebius reader = emalloc_zero(sizeof(*reader)); 607290000Sglebius reader->fd = INVALID_SOCKET; 608182007Sroberto 609182007Sroberto return reader; 61054359Sroberto} 61154359Sroberto 612182007Sroberto/* 613182007Sroberto * delete a reader 614182007Sroberto */ 615182007Srobertostatic void 616290000Sglebiusdelete_asyncio_reader( 617290000Sglebius struct asyncio_reader *reader 618290000Sglebius ) 619182007Sroberto{ 620182007Sroberto free(reader); 621182007Sroberto} 62254359Sroberto 623182007Sroberto/* 624182007Sroberto * add asynchio_reader 625182007Sroberto */ 626182007Srobertostatic void 627290000Sglebiusadd_asyncio_reader( 628290000Sglebius struct asyncio_reader * reader, 629290000Sglebius enum desc_type type) 630182007Sroberto{ 631290000Sglebius LINK_SLIST(asyncio_reader_list, reader, link); 632182007Sroberto add_fd_to_list(reader->fd, type); 633182007Sroberto} 634290000Sglebius 635182007Sroberto/* 636182007Sroberto * remove asynchio_reader 637182007Sroberto */ 638182007Srobertostatic void 639290000Sglebiusremove_asyncio_reader( 640290000Sglebius struct asyncio_reader *reader 641290000Sglebius ) 642182007Sroberto{ 643290000Sglebius struct asyncio_reader *unlinked; 644182007Sroberto 645290000Sglebius UNLINK_SLIST(unlinked, asyncio_reader_list, reader, link, 646290000Sglebius struct asyncio_reader); 647290000Sglebius 648182007Sroberto if (reader->fd != INVALID_SOCKET) 649182007Sroberto close_and_delete_fd_from_list(reader->fd); 650182007Sroberto 651182007Sroberto reader->fd = INVALID_SOCKET; 652182007Sroberto} 653182007Sroberto#endif /* !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) */ 654182007Sroberto 655290000Sglebius 656290000Sglebius/* compare two sockaddr prefixes */ 657290000Sglebiusstatic int 658290000Sglebiusaddr_eqprefix( 659290000Sglebius const sockaddr_u * a, 660290000Sglebius const sockaddr_u * b, 661290000Sglebius int prefixlen 662290000Sglebius ) 663290000Sglebius{ 664290000Sglebius isc_netaddr_t isc_a; 665290000Sglebius isc_netaddr_t isc_b; 666290000Sglebius isc_sockaddr_t isc_sa; 667290000Sglebius 668290000Sglebius ZERO(isc_sa); 669290000Sglebius memcpy(&isc_sa.type, a, min(sizeof(isc_sa.type), sizeof(*a))); 670290000Sglebius isc_netaddr_fromsockaddr(&isc_a, &isc_sa); 671290000Sglebius 672290000Sglebius ZERO(isc_sa); 673290000Sglebius memcpy(&isc_sa.type, b, min(sizeof(isc_sa.type), sizeof(*b))); 674290000Sglebius isc_netaddr_fromsockaddr(&isc_b, &isc_sa); 675290000Sglebius 676290000Sglebius return (int)isc_netaddr_eqprefix(&isc_a, &isc_b, 677290000Sglebius (u_int)prefixlen); 678290000Sglebius} 679290000Sglebius 680290000Sglebius 681290000Sglebiusstatic int 682290000Sglebiusaddr_samesubnet( 683290000Sglebius const sockaddr_u * a, 684290000Sglebius const sockaddr_u * a_mask, 685290000Sglebius const sockaddr_u * b, 686290000Sglebius const sockaddr_u * b_mask 687290000Sglebius ) 688290000Sglebius{ 689290000Sglebius const u_int32 * pa; 690290000Sglebius const u_int32 * pa_limit; 691290000Sglebius const u_int32 * pb; 692290000Sglebius const u_int32 * pm; 693290000Sglebius size_t loops; 694290000Sglebius 695290000Sglebius REQUIRE(AF(a) == AF(a_mask)); 696290000Sglebius REQUIRE(AF(b) == AF(b_mask)); 697290000Sglebius /* 698290000Sglebius * With address and mask families verified to match, comparing 699290000Sglebius * the masks also validates the address's families match. 700290000Sglebius */ 701290000Sglebius if (!SOCK_EQ(a_mask, b_mask)) 702290000Sglebius return FALSE; 703290000Sglebius 704290000Sglebius if (IS_IPV6(a)) { 705290000Sglebius loops = sizeof(NSRCADR6(a)) / sizeof(*pa); 706290000Sglebius pa = (const void *)&NSRCADR6(a); 707290000Sglebius pb = (const void *)&NSRCADR6(b); 708290000Sglebius pm = (const void *)&NSRCADR6(a_mask); 709290000Sglebius } else { 710290000Sglebius loops = sizeof(NSRCADR(a)) / sizeof(*pa); 711290000Sglebius pa = (const void *)&NSRCADR(a); 712290000Sglebius pb = (const void *)&NSRCADR(b); 713290000Sglebius pm = (const void *)&NSRCADR(a_mask); 714290000Sglebius } 715290000Sglebius for (pa_limit = pa + loops; pa < pa_limit; pa++, pb++, pm++) 716290000Sglebius if ((*pa & *pm) != (*pb & *pm)) 717290000Sglebius return FALSE; 718290000Sglebius 719290000Sglebius return TRUE; 720290000Sglebius} 721290000Sglebius 722290000Sglebius 723182007Sroberto/* 724182007Sroberto * interface list enumerator - visitor pattern 725182007Sroberto */ 726182007Srobertovoid 727290000Sglebiusinterface_enumerate( 728290000Sglebius interface_receiver_t receiver, 729290000Sglebius void * data 730290000Sglebius ) 731182007Sroberto{ 732182007Sroberto interface_info_t ifi; 733182007Sroberto 734182007Sroberto ifi.action = IFS_EXISTS; 735290000Sglebius for (ifi.ep = ep_list; ifi.ep != NULL; ifi.ep = ifi.ep->elink) 736290000Sglebius (*receiver)(data, &ifi); 737182007Sroberto} 738182007Sroberto 739182007Sroberto/* 740182007Sroberto * do standard initialization of interface structure 741182007Sroberto */ 742182007Srobertostatic void 743290000Sglebiusinit_interface( 744290000Sglebius endpt *ep 745290000Sglebius ) 746182007Sroberto{ 747290000Sglebius ZERO(*ep); 748290000Sglebius ep->fd = INVALID_SOCKET; 749290000Sglebius ep->bfd = INVALID_SOCKET; 750290000Sglebius ep->phase = sys_interphase; 751182007Sroberto} 752182007Sroberto 753290000Sglebius 754182007Sroberto/* 755182007Sroberto * create new interface structure initialize from 756182007Sroberto * template structure or via standard initialization 757182007Sroberto * function 758182007Sroberto */ 759182007Srobertostatic struct interface * 760290000Sglebiusnew_interface( 761290000Sglebius struct interface *interface 762290000Sglebius ) 763182007Sroberto{ 764290000Sglebius struct interface * iface; 765182007Sroberto 766290000Sglebius iface = emalloc(sizeof(*iface)); 767182007Sroberto 768290000Sglebius if (NULL == interface) 769182007Sroberto init_interface(iface); 770290000Sglebius else /* use the template */ 771290000Sglebius memcpy(iface, interface, sizeof(*iface)); 772182007Sroberto 773290000Sglebius /* count every new instance of an interface in the system */ 774290000Sglebius iface->ifnum = sys_ifnum++; 775182007Sroberto iface->starttime = current_time; 776182007Sroberto 777298770Sdelphij# ifdef HAVE_IO_COMPLETION_PORT 778298770Sdelphij if (!io_completion_port_add_interface(iface)) { 779298770Sdelphij msyslog(LOG_EMERG, "cannot register interface with IO engine -- will exit now"); 780298770Sdelphij exit(1); 781298770Sdelphij } 782298770Sdelphij# endif 783182007Sroberto return iface; 784182007Sroberto} 785182007Sroberto 786290000Sglebius 787182007Sroberto/* 788182007Sroberto * return interface storage into free memory pool 789182007Sroberto */ 790298770Sdelphijstatic void 791290000Sglebiusdelete_interface( 792290000Sglebius endpt *ep 793290000Sglebius ) 794182007Sroberto{ 795298770Sdelphij# ifdef HAVE_IO_COMPLETION_PORT 796298770Sdelphij io_completion_port_remove_interface(ep); 797298770Sdelphij# endif 798290000Sglebius free(ep); 799182007Sroberto} 800182007Sroberto 801290000Sglebius 802182007Sroberto/* 803182007Sroberto * link interface into list of known interfaces 804182007Sroberto */ 805182007Srobertostatic void 806290000Sglebiusadd_interface( 807290000Sglebius endpt * ep 808290000Sglebius ) 809182007Sroberto{ 810290000Sglebius endpt ** pmclisthead; 811290000Sglebius endpt * scan; 812290000Sglebius endpt * scan_next; 813290000Sglebius endpt * unlinked; 814290000Sglebius sockaddr_u * addr; 815290000Sglebius int ep_local; 816290000Sglebius int scan_local; 817290000Sglebius int same_subnet; 818290000Sglebius int ep_univ_iid; /* iface ID from MAC address */ 819290000Sglebius int scan_univ_iid; /* see RFC 4291 */ 820290000Sglebius int ep_privacy; /* random local iface ID */ 821290000Sglebius int scan_privacy; /* see RFC 4941 */ 822290000Sglebius int rc; 823200576Sroberto 824290000Sglebius /* Calculate the refid */ 825290000Sglebius ep->addr_refid = addr2refid(&ep->sin); 826290000Sglebius /* link at tail so ntpdc -c ifstats index increases each row */ 827290000Sglebius LINK_TAIL_SLIST(ep_list, ep, elink, endpt); 828290000Sglebius ninterfaces++; 829290000Sglebius#ifdef MCAST 830290000Sglebius /* the rest is for enabled multicast-capable addresses only */ 831290000Sglebius if (ep->ignore_packets || !(INT_MULTICAST & ep->flags) || 832290000Sglebius INT_LOOPBACK & ep->flags) 833290000Sglebius return; 834290000Sglebius# ifndef INCLUDE_IPV6_MULTICAST_SUPPORT 835290000Sglebius if (AF_INET6 == ep->family) 836290000Sglebius return; 837290000Sglebius# endif 838290000Sglebius pmclisthead = (AF_INET == ep->family) 839290000Sglebius ? &mc4_list 840290000Sglebius : &mc6_list; 841290000Sglebius 842290000Sglebius if (AF_INET6 == ep->family) { 843290000Sglebius ep_local = 844290000Sglebius IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(&ep->sin)) || 845290000Sglebius IN6_IS_ADDR_SITELOCAL(PSOCK_ADDR6(&ep->sin)); 846290000Sglebius ep_univ_iid = IS_IID_UNIV(&ep->sin); 847290000Sglebius ep_privacy = !!(INT_PRIVACY & ep->flags); 848290000Sglebius } else { 849290000Sglebius ep_local = FALSE; 850290000Sglebius ep_univ_iid = FALSE; 851290000Sglebius ep_privacy = FALSE; 852290000Sglebius } 853290000Sglebius DPRINTF(4, ("add_interface mcast-capable %s%s%s%s\n", 854290000Sglebius stoa(&ep->sin), 855290000Sglebius (ep_local) ? " link/scope-local" : "", 856290000Sglebius (ep_univ_iid) ? " univ-IID" : "", 857290000Sglebius (ep_privacy) ? " privacy" : "")); 858132451Sroberto /* 859290000Sglebius * If we have multiple local addresses on the same network 860290000Sglebius * interface, and some are link- or site-local, do not multicast 861290000Sglebius * out from the link-/site-local addresses by default, to avoid 862290000Sglebius * duplicate manycastclient associations between v6 peers using 863290000Sglebius * link-local and global addresses. link-local can still be 864290000Sglebius * chosen using "nic ignore myv6globalprefix::/64". 865290000Sglebius * Similarly, if we have multiple global addresses from the same 866290000Sglebius * prefix on the same network interface, multicast from one, 867290000Sglebius * preferring EUI-64, then static, then least RFC 4941 privacy 868290000Sglebius * addresses. 869200576Sroberto */ 870290000Sglebius for (scan = *pmclisthead; scan != NULL; scan = scan_next) { 871290000Sglebius scan_next = scan->mclink; 872290000Sglebius if (ep->family != scan->family) 873290000Sglebius continue; 874290000Sglebius if (strcmp(ep->name, scan->name)) 875290000Sglebius continue; 876290000Sglebius same_subnet = addr_samesubnet(&ep->sin, &ep->mask, 877290000Sglebius &scan->sin, &scan->mask); 878290000Sglebius if (AF_INET6 == ep->family) { 879290000Sglebius addr = &scan->sin; 880290000Sglebius scan_local = 881290000Sglebius IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(addr)) || 882290000Sglebius IN6_IS_ADDR_SITELOCAL(PSOCK_ADDR6(addr)); 883290000Sglebius scan_univ_iid = IS_IID_UNIV(addr); 884290000Sglebius scan_privacy = !!(INT_PRIVACY & scan->flags); 885290000Sglebius } else { 886290000Sglebius scan_local = FALSE; 887290000Sglebius scan_univ_iid = FALSE; 888290000Sglebius scan_privacy = FALSE; 889290000Sglebius } 890290000Sglebius DPRINTF(4, ("add_interface mcast-capable scan %s%s%s%s\n", 891290000Sglebius stoa(&scan->sin), 892290000Sglebius (scan_local) ? " link/scope-local" : "", 893290000Sglebius (scan_univ_iid) ? " univ-IID" : "", 894290000Sglebius (scan_privacy) ? " privacy" : "")); 895290000Sglebius if ((ep_local && !scan_local) || (same_subnet && 896290000Sglebius ((ep_privacy && !scan_privacy) || 897290000Sglebius (!ep_univ_iid && scan_univ_iid)))) { 898290000Sglebius DPRINTF(4, ("did not add %s to %s of IPv6 multicast-capable list which already has %s\n", 899290000Sglebius stoa(&ep->sin), 900290000Sglebius (ep_local) 901290000Sglebius ? "tail" 902290000Sglebius : "head", 903290000Sglebius stoa(&scan->sin))); 904290000Sglebius return; 905290000Sglebius } 906290000Sglebius if ((scan_local && !ep_local) || (same_subnet && 907290000Sglebius ((scan_privacy && !ep_privacy) || 908290000Sglebius (!scan_univ_iid && ep_univ_iid)))) { 909290000Sglebius UNLINK_SLIST(unlinked, *pmclisthead, 910290000Sglebius scan, mclink, endpt); 911290000Sglebius DPRINTF(4, ("%s %s from IPv6 multicast-capable list to add %s\n", 912290000Sglebius (unlinked != scan) 913290000Sglebius ? "Failed to remove" 914290000Sglebius : "removed", 915290000Sglebius stoa(&scan->sin), stoa(&ep->sin))); 916290000Sglebius } 917200576Sroberto } 918200576Sroberto /* 919290000Sglebius * Add link/site local at the tail of the multicast- 920290000Sglebius * capable unicast interfaces list, so that ntpd will 921290000Sglebius * send from global addresses before link-/site-local 922290000Sglebius * ones. 923182007Sroberto */ 924290000Sglebius if (ep_local) 925290000Sglebius LINK_TAIL_SLIST(*pmclisthead, ep, mclink, endpt); 926290000Sglebius else 927290000Sglebius LINK_SLIST(*pmclisthead, ep, mclink); 928290000Sglebius DPRINTF(4, ("added %s to %s of IPv%s multicast-capable unicast local address list\n", 929290000Sglebius stoa(&ep->sin), 930290000Sglebius (ep_local) 931290000Sglebius ? "tail" 932290000Sglebius : "head", 933290000Sglebius (AF_INET == ep->family) 934290000Sglebius ? "4" 935290000Sglebius : "6")); 936290000Sglebius 937290000Sglebius if (INVALID_SOCKET == ep->fd) 938290000Sglebius return; 939290000Sglebius 940290000Sglebius /* 941290000Sglebius * select the local address from which to send to multicast. 942290000Sglebius */ 943290000Sglebius switch (AF(&ep->sin)) { 944290000Sglebius 945290000Sglebius case AF_INET : 946290000Sglebius rc = setsockopt(ep->fd, IPPROTO_IP, 947290000Sglebius IP_MULTICAST_IF, 948290000Sglebius (void *)&NSRCADR(&ep->sin), 949290000Sglebius sizeof(NSRCADR(&ep->sin))); 950290000Sglebius if (rc) 951290000Sglebius msyslog(LOG_ERR, 952290000Sglebius "setsockopt IP_MULTICAST_IF %s fails: %m", 953290000Sglebius stoa(&ep->sin)); 954290000Sglebius break; 955290000Sglebius 956290000Sglebius# ifdef INCLUDE_IPV6_MULTICAST_SUPPORT 957290000Sglebius case AF_INET6 : 958290000Sglebius rc = setsockopt(ep->fd, IPPROTO_IPV6, 959290000Sglebius IPV6_MULTICAST_IF, 960290000Sglebius (void *)&ep->ifindex, 961290000Sglebius sizeof(ep->ifindex)); 962290000Sglebius /* do not complain if bound addr scope is ifindex */ 963290000Sglebius if (rc && ep->ifindex != SCOPE(&ep->sin)) 964290000Sglebius msyslog(LOG_ERR, 965290000Sglebius "setsockopt IPV6_MULTICAST_IF %u for %s fails: %m", 966290000Sglebius ep->ifindex, stoa(&ep->sin)); 967290000Sglebius break; 968290000Sglebius# endif 969290000Sglebius } 970290000Sglebius#endif /* MCAST */ 971182007Sroberto} 972182007Sroberto 973290000Sglebius 974182007Sroberto/* 975182007Sroberto * remove interface from known interface list and clean up 976182007Sroberto * associated resources 977182007Sroberto */ 978182007Srobertostatic void 979290000Sglebiusremove_interface( 980290000Sglebius endpt * ep 981290000Sglebius ) 982182007Sroberto{ 983290000Sglebius endpt * unlinked; 984290000Sglebius endpt ** pmclisthead; 985290000Sglebius sockaddr_u resmask; 986182007Sroberto 987290000Sglebius UNLINK_SLIST(unlinked, ep_list, ep, elink, endpt); 988290000Sglebius if (!ep->ignore_packets && INT_MULTICAST & ep->flags) { 989290000Sglebius pmclisthead = (AF_INET == ep->family) 990290000Sglebius ? &mc4_list 991290000Sglebius : &mc6_list; 992290000Sglebius UNLINK_SLIST(unlinked, *pmclisthead, ep, mclink, endpt); 993290000Sglebius DPRINTF(4, ("%s %s IPv%s multicast-capable unicast local address list\n", 994290000Sglebius stoa(&ep->sin), 995290000Sglebius (unlinked != NULL) 996290000Sglebius ? "removed from" 997290000Sglebius : "not found on", 998290000Sglebius (AF_INET == ep->family) 999290000Sglebius ? "4" 1000290000Sglebius : "6")); 1001290000Sglebius } 1002290000Sglebius delete_interface_from_list(ep); 1003182007Sroberto 1004290000Sglebius if (ep->fd != INVALID_SOCKET) { 1005290000Sglebius msyslog(LOG_INFO, 1006290000Sglebius "Deleting interface #%d %s, %s#%d, interface stats: received=%ld, sent=%ld, dropped=%ld, active_time=%ld secs", 1007290000Sglebius ep->ifnum, 1008290000Sglebius ep->name, 1009290000Sglebius stoa(&ep->sin), 1010290000Sglebius SRCPORT(&ep->sin), 1011290000Sglebius ep->received, 1012290000Sglebius ep->sent, 1013290000Sglebius ep->notsent, 1014290000Sglebius current_time - ep->starttime); 1015298770Sdelphij# ifdef HAVE_IO_COMPLETION_PORT 1016298770Sdelphij io_completion_port_remove_socket(ep->fd, ep); 1017298770Sdelphij# endif 1018290000Sglebius close_and_delete_fd_from_list(ep->fd); 1019290000Sglebius ep->fd = INVALID_SOCKET; 1020290000Sglebius } 1021182007Sroberto 1022290000Sglebius if (ep->bfd != INVALID_SOCKET) { 1023290000Sglebius msyslog(LOG_INFO, 1024290000Sglebius "stop listening for broadcasts to %s on interface #%d %s", 1025290000Sglebius stoa(&ep->bcast), ep->ifnum, ep->name); 1026298770Sdelphij# ifdef HAVE_IO_COMPLETION_PORT 1027298770Sdelphij io_completion_port_remove_socket(ep->bfd, ep); 1028298770Sdelphij# endif 1029290000Sglebius close_and_delete_fd_from_list(ep->bfd); 1030290000Sglebius ep->bfd = INVALID_SOCKET; 1031182007Sroberto } 1032298770Sdelphij# ifdef HAVE_IO_COMPLETION_PORT 1033298770Sdelphij io_completion_port_remove_interface(ep); 1034298770Sdelphij# endif 1035182007Sroberto 1036182007Sroberto ninterfaces--; 1037290000Sglebius mon_clearinterface(ep); 1038182007Sroberto 1039182007Sroberto /* remove restrict interface entry */ 1040290000Sglebius SET_HOSTMASK(&resmask, AF(&ep->sin)); 1041290000Sglebius hack_restrict(RESTRICT_REMOVEIF, &ep->sin, &resmask, 1042290000Sglebius RESM_NTPONLY | RESM_INTERFACE, RES_IGNORE, 0); 1043182007Sroberto} 1044182007Sroberto 1045290000Sglebius 1046182007Srobertostatic void 1047290000Sglebiuslog_listen_address( 1048290000Sglebius endpt * ep 1049290000Sglebius ) 1050182007Sroberto{ 1051290000Sglebius msyslog(LOG_INFO, "%s on %d %s %s", 1052290000Sglebius (ep->ignore_packets) 1053290000Sglebius ? "Listen and drop" 1054290000Sglebius : "Listen normally", 1055290000Sglebius ep->ifnum, 1056290000Sglebius ep->name, 1057290000Sglebius sptoa(&ep->sin)); 1058182007Sroberto} 1059182007Sroberto 1060290000Sglebius 1061182007Srobertostatic void 1062290000Sglebiuscreate_wildcards( 1063290000Sglebius u_short port 1064290000Sglebius ) 1065290000Sglebius{ 1066290000Sglebius int v4wild; 1067290000Sglebius#ifdef INCLUDE_IPV6_SUPPORT 1068290000Sglebius int v6wild; 1069290000Sglebius#endif 1070290000Sglebius sockaddr_u wildaddr; 1071290000Sglebius nic_rule_action action; 1072290000Sglebius struct interface * wildif; 1073290000Sglebius 1074182007Sroberto /* 1075290000Sglebius * silence "potentially uninitialized" warnings from VC9 1076290000Sglebius * failing to follow the logic. Ideally action could remain 1077290000Sglebius * uninitialized, and the memset be the first statement under 1078290000Sglebius * the first if (v4wild). 1079132451Sroberto */ 1080290000Sglebius action = ACTION_LISTEN; 1081290000Sglebius ZERO(wildaddr); 1082182007Sroberto 1083290000Sglebius#ifdef INCLUDE_IPV6_SUPPORT 1084290000Sglebius /* 1085290000Sglebius * create pseudo-interface with wildcard IPv6 address 1086290000Sglebius */ 1087290000Sglebius v6wild = ipv6_works; 1088290000Sglebius if (v6wild) { 1089290000Sglebius /* set wildaddr to the v6 wildcard address :: */ 1090290000Sglebius ZERO(wildaddr); 1091290000Sglebius AF(&wildaddr) = AF_INET6; 1092290000Sglebius SET_ADDR6N(&wildaddr, in6addr_any); 1093290000Sglebius SET_PORT(&wildaddr, port); 1094290000Sglebius SET_SCOPE(&wildaddr, 0); 1095182007Sroberto 1096290000Sglebius /* check for interface/nic rules affecting the wildcard */ 1097290000Sglebius action = interface_action(NULL, &wildaddr, 0); 1098290000Sglebius v6wild = (ACTION_IGNORE != action); 1099290000Sglebius } 1100290000Sglebius if (v6wild) { 1101290000Sglebius wildif = new_interface(NULL); 110254359Sroberto 1103290000Sglebius strlcpy(wildif->name, "v6wildcard", sizeof(wildif->name)); 1104290000Sglebius memcpy(&wildif->sin, &wildaddr, sizeof(wildif->sin)); 1105290000Sglebius wildif->family = AF_INET6; 1106290000Sglebius AF(&wildif->mask) = AF_INET6; 1107290000Sglebius SET_ONESMASK(&wildif->mask); 1108290000Sglebius 1109290000Sglebius wildif->flags = INT_UP | INT_WILDCARD; 1110290000Sglebius wildif->ignore_packets = (ACTION_DROP == action); 1111290000Sglebius 1112290000Sglebius wildif->fd = open_socket(&wildif->sin, 0, 1, wildif); 1113290000Sglebius 1114290000Sglebius if (wildif->fd != INVALID_SOCKET) { 1115290000Sglebius wildipv6 = wildif; 1116290000Sglebius any6_interface = wildif; 1117290000Sglebius add_addr_to_list(&wildif->sin, wildif); 1118290000Sglebius add_interface(wildif); 1119290000Sglebius log_listen_address(wildif); 1120182007Sroberto } else { 1121290000Sglebius msyslog(LOG_ERR, 1122290000Sglebius "unable to bind to wildcard address %s - another process may be running - EXITING", 1123290000Sglebius stoa(&wildif->sin)); 1124182007Sroberto exit(1); 1125182007Sroberto } 1126290000Sglebius DPRINT_INTERFACE(2, (wildif, "created ", "\n")); 1127182007Sroberto } 1128290000Sglebius#endif 1129182007Sroberto 113054359Sroberto /* 1131290000Sglebius * create pseudo-interface with wildcard IPv4 address 113254359Sroberto */ 1133290000Sglebius v4wild = ipv4_works; 1134290000Sglebius if (v4wild) { 1135290000Sglebius /* set wildaddr to the v4 wildcard address 0.0.0.0 */ 1136290000Sglebius AF(&wildaddr) = AF_INET; 1137290000Sglebius SET_ADDR4N(&wildaddr, INADDR_ANY); 1138290000Sglebius SET_PORT(&wildaddr, port); 1139182007Sroberto 1140290000Sglebius /* check for interface/nic rules affecting the wildcard */ 1141290000Sglebius action = interface_action(NULL, &wildaddr, 0); 1142290000Sglebius v4wild = (ACTION_IGNORE != action); 1143290000Sglebius } 1144290000Sglebius if (v4wild) { 1145290000Sglebius wildif = new_interface(NULL); 1146182007Sroberto 1147290000Sglebius strlcpy(wildif->name, "v4wildcard", sizeof(wildif->name)); 1148290000Sglebius memcpy(&wildif->sin, &wildaddr, sizeof(wildif->sin)); 1149290000Sglebius wildif->family = AF_INET; 1150290000Sglebius AF(&wildif->mask) = AF_INET; 1151290000Sglebius SET_ONESMASK(&wildif->mask); 1152182007Sroberto 1153290000Sglebius wildif->flags = INT_BROADCAST | INT_UP | INT_WILDCARD; 1154290000Sglebius wildif->ignore_packets = (ACTION_DROP == action); 1155290000Sglebius#if defined(MCAST) 1156290000Sglebius /* 1157290000Sglebius * enable multicast reception on the broadcast socket 1158290000Sglebius */ 1159290000Sglebius AF(&wildif->bcast) = AF_INET; 1160290000Sglebius SET_ADDR4N(&wildif->bcast, INADDR_ANY); 1161290000Sglebius SET_PORT(&wildif->bcast, port); 1162290000Sglebius#endif /* MCAST */ 1163290000Sglebius wildif->fd = open_socket(&wildif->sin, 0, 1, wildif); 1164290000Sglebius 1165290000Sglebius if (wildif->fd != INVALID_SOCKET) { 1166290000Sglebius wildipv4 = wildif; 1167290000Sglebius any_interface = wildif; 1168290000Sglebius 1169290000Sglebius add_addr_to_list(&wildif->sin, wildif); 1170290000Sglebius add_interface(wildif); 1171290000Sglebius log_listen_address(wildif); 1172182007Sroberto } else { 1173290000Sglebius msyslog(LOG_ERR, 1174290000Sglebius "unable to bind to wildcard address %s - another process may be running - EXITING", 1175290000Sglebius stoa(&wildif->sin)); 1176182007Sroberto exit(1); 1177182007Sroberto } 1178290000Sglebius DPRINT_INTERFACE(2, (wildif, "created ", "\n")); 117954359Sroberto } 1180132451Sroberto} 118154359Sroberto 118254359Sroberto 1183290000Sglebius/* 1184290000Sglebius * add_nic_rule() -- insert a rule entry at the head of nic_rule_list. 1185290000Sglebius */ 1186290000Sglebiusvoid 1187290000Sglebiusadd_nic_rule( 1188290000Sglebius nic_rule_match match_type, 1189290000Sglebius const char * if_name, /* interface name or numeric address */ 1190290000Sglebius int prefixlen, 1191290000Sglebius nic_rule_action action 1192290000Sglebius ) 1193290000Sglebius{ 1194290000Sglebius nic_rule * rule; 1195290000Sglebius isc_boolean_t is_ip; 119654359Sroberto 1197290000Sglebius rule = emalloc_zero(sizeof(*rule)); 1198290000Sglebius rule->match_type = match_type; 1199290000Sglebius rule->prefixlen = prefixlen; 1200290000Sglebius rule->action = action; 120154359Sroberto 1202290000Sglebius if (MATCH_IFNAME == match_type) { 1203290000Sglebius REQUIRE(NULL != if_name); 1204290000Sglebius rule->if_name = estrdup(if_name); 1205290000Sglebius } else if (MATCH_IFADDR == match_type) { 1206290000Sglebius REQUIRE(NULL != if_name); 1207290000Sglebius /* set rule->addr */ 1208290000Sglebius is_ip = is_ip_address(if_name, AF_UNSPEC, &rule->addr); 1209290000Sglebius REQUIRE(is_ip); 1210290000Sglebius } else 1211290000Sglebius REQUIRE(NULL == if_name); 1212290000Sglebius 1213290000Sglebius LINK_SLIST(nic_rule_list, rule, next); 1214290000Sglebius} 1215290000Sglebius 1216290000Sglebius 1217290000Sglebius#ifdef DEBUG 1218290000Sglebiusstatic const char * 1219290000Sglebiusaction_text( 1220290000Sglebius nic_rule_action action 1221290000Sglebius ) 1222290000Sglebius{ 1223290000Sglebius const char *t; 1224290000Sglebius 1225290000Sglebius switch (action) { 1226290000Sglebius 1227290000Sglebius default: 1228290000Sglebius t = "ERROR"; /* quiet uninit warning */ 1229290000Sglebius DPRINTF(1, ("fatal: unknown nic_rule_action %d\n", 1230290000Sglebius action)); 1231290000Sglebius ENSURE(0); 1232290000Sglebius break; 1233290000Sglebius 1234290000Sglebius case ACTION_LISTEN: 1235290000Sglebius t = "listen"; 1236290000Sglebius break; 1237290000Sglebius 1238290000Sglebius case ACTION_IGNORE: 1239290000Sglebius t = "ignore"; 1240290000Sglebius break; 1241290000Sglebius 1242290000Sglebius case ACTION_DROP: 1243290000Sglebius t = "drop"; 1244290000Sglebius break; 1245290000Sglebius } 1246290000Sglebius 1247290000Sglebius return t; 1248290000Sglebius} 1249290000Sglebius#endif /* DEBUG */ 1250290000Sglebius 1251290000Sglebius 1252290000Sglebiusstatic nic_rule_action 1253290000Sglebiusinterface_action( 1254290000Sglebius char * if_name, 1255290000Sglebius sockaddr_u * if_addr, 1256290000Sglebius u_int32 if_flags 1257290000Sglebius ) 1258290000Sglebius{ 1259290000Sglebius nic_rule * rule; 1260290000Sglebius int isloopback; 1261290000Sglebius int iswildcard; 1262290000Sglebius 1263290000Sglebius DPRINTF(4, ("interface_action: interface %s ", 1264290000Sglebius (if_name != NULL) ? if_name : "wildcard")); 1265290000Sglebius 1266290000Sglebius iswildcard = is_wildcard_addr(if_addr); 1267290000Sglebius isloopback = !!(INT_LOOPBACK & if_flags); 1268290000Sglebius 1269182007Sroberto /* 1270290000Sglebius * Find any matching NIC rule from --interface / -I or ntp.conf 1271290000Sglebius * interface/nic rules. 1272132451Sroberto */ 1273290000Sglebius for (rule = nic_rule_list; rule != NULL; rule = rule->next) { 1274290000Sglebius 1275290000Sglebius switch (rule->match_type) { 1276290000Sglebius 1277290000Sglebius case MATCH_ALL: 1278290000Sglebius /* loopback and wildcard excluded from "all" */ 1279290000Sglebius if (isloopback || iswildcard) 1280290000Sglebius break; 1281290000Sglebius DPRINTF(4, ("nic all %s\n", 1282290000Sglebius action_text(rule->action))); 1283290000Sglebius return rule->action; 1284290000Sglebius 1285290000Sglebius case MATCH_IPV4: 1286290000Sglebius if (IS_IPV4(if_addr)) { 1287290000Sglebius DPRINTF(4, ("nic ipv4 %s\n", 1288290000Sglebius action_text(rule->action))); 1289290000Sglebius return rule->action; 1290290000Sglebius } 1291290000Sglebius break; 1292290000Sglebius 1293290000Sglebius case MATCH_IPV6: 1294290000Sglebius if (IS_IPV6(if_addr)) { 1295290000Sglebius DPRINTF(4, ("nic ipv6 %s\n", 1296290000Sglebius action_text(rule->action))); 1297290000Sglebius return rule->action; 1298290000Sglebius } 1299290000Sglebius break; 1300290000Sglebius 1301290000Sglebius case MATCH_WILDCARD: 1302290000Sglebius if (iswildcard) { 1303290000Sglebius DPRINTF(4, ("nic wildcard %s\n", 1304290000Sglebius action_text(rule->action))); 1305290000Sglebius return rule->action; 1306290000Sglebius } 1307290000Sglebius break; 1308290000Sglebius 1309290000Sglebius case MATCH_IFADDR: 1310290000Sglebius if (rule->prefixlen != -1) { 1311290000Sglebius if (addr_eqprefix(if_addr, &rule->addr, 1312290000Sglebius rule->prefixlen)) { 1313290000Sglebius 1314290000Sglebius DPRINTF(4, ("subnet address match - %s\n", 1315290000Sglebius action_text(rule->action))); 1316290000Sglebius return rule->action; 1317290000Sglebius } 1318290000Sglebius } else 1319290000Sglebius if (SOCK_EQ(if_addr, &rule->addr)) { 1320290000Sglebius 1321290000Sglebius DPRINTF(4, ("address match - %s\n", 1322290000Sglebius action_text(rule->action))); 1323290000Sglebius return rule->action; 1324290000Sglebius } 1325290000Sglebius break; 1326290000Sglebius 1327290000Sglebius case MATCH_IFNAME: 1328290000Sglebius if (if_name != NULL 1329290000Sglebius#if defined(HAVE_FNMATCH) && defined(FNM_CASEFOLD) 1330290000Sglebius && !fnmatch(rule->if_name, if_name, FNM_CASEFOLD) 1331290000Sglebius#else 1332290000Sglebius && !strcasecmp(if_name, rule->if_name) 1333290000Sglebius#endif 1334290000Sglebius ) { 1335290000Sglebius 1336290000Sglebius DPRINTF(4, ("interface name match - %s\n", 1337290000Sglebius action_text(rule->action))); 1338290000Sglebius return rule->action; 1339290000Sglebius } 1340290000Sglebius break; 1341290000Sglebius } 1342182007Sroberto } 1343182007Sroberto 1344182007Sroberto /* 1345290000Sglebius * Unless explicitly disabled such as with "nic ignore ::1" 1346290000Sglebius * listen on loopback addresses. Since ntpq and ntpdc query 1347290000Sglebius * "localhost" by default, which typically resolves to ::1 and 1348290000Sglebius * 127.0.0.1, it's useful to default to listening on both. 1349182007Sroberto */ 1350290000Sglebius if (isloopback) { 1351290000Sglebius DPRINTF(4, ("default loopback listen\n")); 1352290000Sglebius return ACTION_LISTEN; 1353182007Sroberto } 1354290000Sglebius 1355290000Sglebius /* 1356290000Sglebius * Treat wildcard addresses specially. If there is no explicit 1357290000Sglebius * "nic ... wildcard" or "nic ... 0.0.0.0" or "nic ... ::" rule 1358290000Sglebius * default to drop. 1359290000Sglebius */ 1360290000Sglebius if (iswildcard) { 1361290000Sglebius DPRINTF(4, ("default wildcard drop\n")); 1362290000Sglebius return ACTION_DROP; 1363182007Sroberto } 1364182007Sroberto 1365290000Sglebius /* 1366290000Sglebius * Check for "virtual IP" (colon in the interface name) after 1367290000Sglebius * the rules so that "ntpd --interface eth0:1 -novirtualips" 1368290000Sglebius * does indeed listen on eth0:1's addresses. 1369290000Sglebius */ 1370290000Sglebius if (!listen_to_virtual_ips && if_name != NULL 1371290000Sglebius && (strchr(if_name, ':') != NULL)) { 1372290000Sglebius 1373290000Sglebius DPRINTF(4, ("virtual ip - ignore\n")); 1374290000Sglebius return ACTION_IGNORE; 1375290000Sglebius } 1376290000Sglebius 1377290000Sglebius /* 1378290000Sglebius * If there are no --interface/-I command-line options and no 1379290000Sglebius * interface/nic rules in ntp.conf, the default action is to 1380290000Sglebius * listen. In the presence of rules from either, the default 1381290000Sglebius * is to ignore. This implements ntpd's traditional listen- 1382290000Sglebius * every default with no interface listen configuration, and 1383290000Sglebius * ensures a single -I eth0 or "nic listen eth0" means do not 1384290000Sglebius * listen on any other addresses. 1385290000Sglebius */ 1386290000Sglebius if (NULL == nic_rule_list) { 1387290000Sglebius DPRINTF(4, ("default listen\n")); 1388290000Sglebius return ACTION_LISTEN; 1389290000Sglebius } 1390290000Sglebius 1391290000Sglebius DPRINTF(4, ("implicit ignore\n")); 1392290000Sglebius return ACTION_IGNORE; 1393132451Sroberto} 139454359Sroberto 1395290000Sglebius 1396182007Srobertostatic void 1397290000Sglebiusconvert_isc_if( 1398290000Sglebius isc_interface_t *isc_if, 1399290000Sglebius endpt *itf, 1400290000Sglebius u_short port 1401290000Sglebius ) 1402182007Sroberto{ 1403290000Sglebius const u_char v6loop[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1404290000Sglebius 0, 0, 0, 0, 0, 0, 0, 1}; 1405182007Sroberto 1406290000Sglebius strlcpy(itf->name, isc_if->name, sizeof(itf->name)); 1407290000Sglebius itf->ifindex = isc_if->ifindex; 1408290000Sglebius itf->family = (u_short)isc_if->af; 1409290000Sglebius AF(&itf->sin) = itf->family; 1410290000Sglebius AF(&itf->mask) = itf->family; 1411290000Sglebius AF(&itf->bcast) = itf->family; 1412290000Sglebius SET_PORT(&itf->sin, port); 1413290000Sglebius SET_PORT(&itf->mask, port); 1414290000Sglebius SET_PORT(&itf->bcast, port); 141554359Sroberto 1416290000Sglebius if (IS_IPV4(&itf->sin)) { 1417290000Sglebius NSRCADR(&itf->sin) = isc_if->address.type.in.s_addr; 1418290000Sglebius NSRCADR(&itf->mask) = isc_if->netmask.type.in.s_addr; 1419290000Sglebius 1420290000Sglebius if (isc_if->flags & INTERFACE_F_BROADCAST) { 1421132451Sroberto itf->flags |= INT_BROADCAST; 1422290000Sglebius NSRCADR(&itf->bcast) = 1423290000Sglebius isc_if->broadcast.type.in.s_addr; 1424132451Sroberto } 142554359Sroberto } 1426182007Sroberto#ifdef INCLUDE_IPV6_SUPPORT 1427290000Sglebius else if (IS_IPV6(&itf->sin)) { 1428290000Sglebius SET_ADDR6N(&itf->sin, isc_if->address.type.in6); 1429290000Sglebius SET_ADDR6N(&itf->mask, isc_if->netmask.type.in6); 143054359Sroberto 1431290000Sglebius SET_SCOPE(&itf->sin, isc_if->address.zone); 143254359Sroberto } 1433182007Sroberto#endif /* INCLUDE_IPV6_SUPPORT */ 143454359Sroberto 1435132451Sroberto 1436182007Sroberto /* Process the rest of the flags */ 1437182007Sroberto 1438290000Sglebius itf->flags |= 1439290000Sglebius ((INTERFACE_F_UP & isc_if->flags) 1440290000Sglebius ? INT_UP : 0) 1441290000Sglebius | ((INTERFACE_F_LOOPBACK & isc_if->flags) 1442290000Sglebius ? INT_LOOPBACK : 0) 1443290000Sglebius | ((INTERFACE_F_POINTTOPOINT & isc_if->flags) 1444290000Sglebius ? INT_PPP : 0) 1445290000Sglebius | ((INTERFACE_F_MULTICAST & isc_if->flags) 1446290000Sglebius ? INT_MULTICAST : 0) 1447290000Sglebius | ((INTERFACE_F_PRIVACY & isc_if->flags) 1448290000Sglebius ? INT_PRIVACY : 0) 1449290000Sglebius ; 1450182007Sroberto 1451290000Sglebius /* 1452290000Sglebius * Clear the loopback flag if the address is not localhost. 1453290000Sglebius * http://bugs.ntp.org/1683 1454290000Sglebius */ 1455290000Sglebius if (INT_LOOPBACK & itf->flags) { 1456290000Sglebius if (AF_INET == itf->family) { 1457290000Sglebius if (127 != (SRCADR(&itf->sin) >> 24)) 1458290000Sglebius itf->flags &= ~INT_LOOPBACK; 1459290000Sglebius } else { 1460290000Sglebius if (memcmp(v6loop, NSRCADR6(&itf->sin), 1461290000Sglebius sizeof(NSRCADR6(&itf->sin)))) 1462290000Sglebius itf->flags &= ~INT_LOOPBACK; 1463290000Sglebius } 1464290000Sglebius } 1465132451Sroberto} 1466182007Sroberto 1467290000Sglebius 1468132451Sroberto/* 1469182007Sroberto * refresh_interface 1470182007Sroberto * 1471182007Sroberto * some OSes have been observed to keep 1472182007Sroberto * cached routes even when more specific routes 1473182007Sroberto * become available. 1474182007Sroberto * this can be mitigated by re-binding 1475182007Sroberto * the socket. 1476132451Sroberto */ 1477132451Srobertostatic int 1478290000Sglebiusrefresh_interface( 1479290000Sglebius struct interface * interface 1480290000Sglebius ) 1481182007Sroberto{ 1482182007Sroberto#ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES 1483290000Sglebius if (interface->fd != INVALID_SOCKET) { 1484290000Sglebius int bcast = (interface->flags & INT_BCASTXMIT) != 0; 1485290000Sglebius /* as we forcibly close() the socket remove the 1486290000Sglebius broadcast permission indication */ 1487290000Sglebius if (bcast) 1488290000Sglebius socket_broadcast_disable(interface, &interface->sin); 1489290000Sglebius 1490182007Sroberto close_and_delete_fd_from_list(interface->fd); 1491290000Sglebius 1492290000Sglebius /* create new socket picking up a new first hop binding 1493290000Sglebius at connect() time */ 1494182007Sroberto interface->fd = open_socket(&interface->sin, 1495290000Sglebius bcast, 0, interface); 1496182007Sroberto /* 1497290000Sglebius * reset TTL indication so TTL is is set again 1498182007Sroberto * next time around 1499182007Sroberto */ 1500182007Sroberto interface->last_ttl = 0; 1501290000Sglebius return (interface->fd != INVALID_SOCKET); 1502290000Sglebius } else 1503182007Sroberto return 0; /* invalid sockets are not refreshable */ 1504182007Sroberto#else /* !OS_MISSES_SPECIFIC_ROUTE_UPDATES */ 1505290000Sglebius return (interface->fd != INVALID_SOCKET); 1506182007Sroberto#endif /* !OS_MISSES_SPECIFIC_ROUTE_UPDATES */ 1507182007Sroberto} 1508182007Sroberto 1509182007Sroberto/* 1510182007Sroberto * interface_update - externally callable update function 1511182007Sroberto */ 1512182007Srobertovoid 1513290000Sglebiusinterface_update( 1514290000Sglebius interface_receiver_t receiver, 1515290000Sglebius void * data) 1516182007Sroberto{ 1517290000Sglebius int new_interface_found; 1518182007Sroberto 1519290000Sglebius if (disable_dynamic_updates) 1520290000Sglebius return; 1521182007Sroberto 1522290000Sglebius BLOCKIO(); 1523290000Sglebius new_interface_found = update_interfaces(NTP_PORT, receiver, data); 1524290000Sglebius UNBLOCKIO(); 1525290000Sglebius 1526290000Sglebius if (!new_interface_found) 1527290000Sglebius return; 1528290000Sglebius 1529182007Sroberto#ifdef DEBUG 1530290000Sglebius msyslog(LOG_DEBUG, "new interface(s) found: waking up resolver"); 1531182007Sroberto#endif 1532290000Sglebius interrupt_worker_sleep(); 1533182007Sroberto} 1534182007Sroberto 1535290000Sglebius 1536182007Sroberto/* 1537290000Sglebius * sau_from_netaddr() - convert network address on-wire formats. 1538290000Sglebius * Convert from libisc's isc_netaddr_t to NTP's sockaddr_u 1539182007Sroberto */ 1540290000Sglebiusvoid 1541290000Sglebiussau_from_netaddr( 1542290000Sglebius sockaddr_u *psau, 1543290000Sglebius const isc_netaddr_t *pna 1544290000Sglebius ) 1545290000Sglebius{ 1546290000Sglebius ZERO_SOCK(psau); 1547290000Sglebius AF(psau) = (u_short)pna->family; 1548290000Sglebius switch (pna->family) { 1549290000Sglebius 1550290000Sglebius case AF_INET: 1551290000Sglebius memcpy(&psau->sa4.sin_addr, &pna->type.in, 1552290000Sglebius sizeof(psau->sa4.sin_addr)); 1553290000Sglebius break; 1554290000Sglebius 1555290000Sglebius case AF_INET6: 1556290000Sglebius memcpy(&psau->sa6.sin6_addr, &pna->type.in6, 1557290000Sglebius sizeof(psau->sa6.sin6_addr)); 1558290000Sglebius break; 1559290000Sglebius } 1560290000Sglebius} 1561290000Sglebius 1562290000Sglebius 1563182007Srobertostatic int 1564290000Sglebiusis_wildcard_addr( 1565290000Sglebius const sockaddr_u *psau 1566290000Sglebius ) 1567182007Sroberto{ 1568290000Sglebius if (IS_IPV4(psau) && !NSRCADR(psau)) 1569182007Sroberto return 1; 1570182007Sroberto 1571182007Sroberto#ifdef INCLUDE_IPV6_SUPPORT 1572290000Sglebius if (IS_IPV6(psau) && S_ADDR6_EQ(psau, &in6addr_any)) 1573182007Sroberto return 1; 1574182007Sroberto#endif 1575182007Sroberto 1576182007Sroberto return 0; 1577182007Sroberto} 1578182007Sroberto 1579290000Sglebius 1580182007Sroberto#ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND 1581182007Sroberto/* 1582182007Sroberto * enable/disable re-use of wildcard address socket 1583182007Sroberto */ 1584182007Srobertostatic void 1585290000Sglebiusset_wildcard_reuse( 1586290000Sglebius u_short family, 1587290000Sglebius int on 1588290000Sglebius ) 1589182007Sroberto{ 1590290000Sglebius struct interface *any; 1591182007Sroberto SOCKET fd = INVALID_SOCKET; 1592182007Sroberto 1593290000Sglebius any = ANY_INTERFACE_BYFAM(family); 1594290000Sglebius if (any != NULL) 1595290000Sglebius fd = any->fd; 1596182007Sroberto 1597290000Sglebius if (fd != INVALID_SOCKET) { 1598290000Sglebius if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 1599290000Sglebius (char *)&on, sizeof(on))) 1600290000Sglebius msyslog(LOG_ERR, 1601290000Sglebius "set_wildcard_reuse: setsockopt(SO_REUSEADDR, %s) failed: %m", 1602290000Sglebius on ? "on" : "off"); 1603182007Sroberto 1604290000Sglebius DPRINTF(4, ("set SO_REUSEADDR to %s on %s\n", 1605290000Sglebius on ? "on" : "off", 1606290000Sglebius stoa(&any->sin))); 1607182007Sroberto } 1608182007Sroberto} 1609182007Sroberto#endif /* OS_NEEDS_REUSEADDR_FOR_IFADDRBIND */ 1610182007Sroberto 1611290000Sglebius 1612199995Sumestatic isc_boolean_t 1613290000Sglebiuscheck_flags6( 1614290000Sglebius sockaddr_u *psau, 1615290000Sglebius const char *name, 1616290000Sglebius u_int32 flags6 1617290000Sglebius ) 1618199995Sume{ 1619290000Sglebius#if defined(INCLUDE_IPV6_SUPPORT) && defined(SIOCGIFAFLAG_IN6) 1620199995Sume struct in6_ifreq ifr6; 1621199995Sume int fd; 1622199995Sume 1623290000Sglebius if (psau->sa.sa_family != AF_INET6) 1624199995Sume return ISC_FALSE; 1625199995Sume if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1626199995Sume return ISC_FALSE; 1627290000Sglebius ZERO(ifr6); 1628290000Sglebius memcpy(&ifr6.ifr_addr, &psau->sa6, sizeof(ifr6.ifr_addr)); 1629290000Sglebius strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); 1630199995Sume if (ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) < 0) { 1631199995Sume close(fd); 1632199995Sume return ISC_FALSE; 1633199995Sume } 1634199995Sume close(fd); 1635290000Sglebius if ((ifr6.ifr_ifru.ifru_flags6 & flags6) != 0) 1636199995Sume return ISC_TRUE; 1637290000Sglebius#endif /* INCLUDE_IPV6_SUPPORT && SIOCGIFAFLAG_IN6 */ 1638199995Sume return ISC_FALSE; 1639199995Sume} 1640199995Sume 1641290000Sglebiusstatic isc_boolean_t 1642290000Sglebiusis_anycast( 1643290000Sglebius sockaddr_u *psau, 1644290000Sglebius const char *name 1645290000Sglebius ) 1646290000Sglebius{ 1647290000Sglebius#ifdef IN6_IFF_ANYCAST 1648290000Sglebius return check_flags6(psau, name, IN6_IFF_ANYCAST); 1649290000Sglebius#else 1650290000Sglebius return ISC_FALSE; 1651290000Sglebius#endif 1652290000Sglebius} 1653290000Sglebius 1654290000Sglebiusstatic isc_boolean_t 1655290000Sglebiusis_valid( 1656290000Sglebius sockaddr_u *psau, 1657290000Sglebius const char *name 1658290000Sglebius ) 1659290000Sglebius{ 1660290000Sglebius u_int32 flags6; 1661290000Sglebius 1662290000Sglebius flags6 = 0; 1663290000Sglebius#ifdef IN6_IFF_DEPARTED 1664290000Sglebius flags6 |= IN6_IFF_DEPARTED; 1665290000Sglebius#endif 1666290000Sglebius#ifdef IN6_IFF_DETACHED 1667290000Sglebius flags6 |= IN6_IFF_DETACHED; 1668290000Sglebius#endif 1669290000Sglebius#ifdef IN6_IFF_TENTATIVE 1670290000Sglebius flags6 |= IN6_IFF_TENTATIVE; 1671290000Sglebius#endif 1672290000Sglebius return check_flags6(psau, name, flags6) ? ISC_FALSE : ISC_TRUE; 1673290000Sglebius} 1674290000Sglebius 1675182007Sroberto/* 1676182007Sroberto * update_interface strategy 1677182007Sroberto * 1678182007Sroberto * toggle configuration phase 1679182007Sroberto * 1680182007Sroberto * Phase 1: 1681182007Sroberto * forall currently existing interfaces 1682182007Sroberto * if address is known: 1683290000Sglebius * drop socket - rebind again 1684182007Sroberto * 1685182007Sroberto * if address is NOT known: 1686290000Sglebius * attempt to create a new interface entry 1687182007Sroberto * 1688182007Sroberto * Phase 2: 1689182007Sroberto * forall currently known non MCAST and WILDCARD interfaces 1690182007Sroberto * if interface does not match configuration phase (not seen in phase 1): 1691290000Sglebius * remove interface from known interface list 1692290000Sglebius * forall peers associated with this interface 1693290000Sglebius * disconnect peer from this interface 1694182007Sroberto * 1695182007Sroberto * Phase 3: 1696182007Sroberto * attempt to re-assign interfaces to peers 1697182007Sroberto * 1698182007Sroberto */ 1699182007Sroberto 1700182007Srobertostatic int 1701182007Srobertoupdate_interfaces( 1702290000Sglebius u_short port, 1703290000Sglebius interface_receiver_t receiver, 1704290000Sglebius void * data 1705132451Sroberto ) 170654359Sroberto{ 1707290000Sglebius isc_mem_t * mctx = (void *)-1; 1708290000Sglebius interface_info_t ifi; 1709290000Sglebius isc_interfaceiter_t * iter; 1710290000Sglebius isc_result_t result; 1711290000Sglebius isc_interface_t isc_if; 1712290000Sglebius int new_interface_found; 1713290000Sglebius unsigned int family; 1714290000Sglebius endpt enumep; 1715290000Sglebius endpt * ep; 1716290000Sglebius endpt * next_ep; 171754359Sroberto 1718290000Sglebius DPRINTF(3, ("update_interfaces(%d)\n", port)); 171954359Sroberto 1720182007Sroberto /* 1721182007Sroberto * phase one - scan interfaces 1722182007Sroberto * - create those that are not found 1723182007Sroberto * - update those that are found 1724182007Sroberto */ 1725132451Sroberto 1726290000Sglebius new_interface_found = FALSE; 1727290000Sglebius iter = NULL; 1728182007Sroberto result = isc_interfaceiter_create(mctx, &iter); 1729132451Sroberto 1730132451Sroberto if (result != ISC_R_SUCCESS) 1731182007Sroberto return 0; 1732132451Sroberto 1733290000Sglebius /* 1734290000Sglebius * Toggle system interface scan phase to find untouched 1735290000Sglebius * interfaces to be deleted. 1736290000Sglebius */ 1737290000Sglebius sys_interphase ^= 0x1; 1738290000Sglebius 1739132451Sroberto for (result = isc_interfaceiter_first(iter); 1740290000Sglebius ISC_R_SUCCESS == result; 1741290000Sglebius result = isc_interfaceiter_next(iter)) { 1742290000Sglebius 1743182007Sroberto result = isc_interfaceiter_current(iter, &isc_if); 174454359Sroberto 1745132451Sroberto if (result != ISC_R_SUCCESS) 1746132451Sroberto break; 174754359Sroberto 1748132451Sroberto /* See if we have a valid family to use */ 1749132451Sroberto family = isc_if.address.family; 1750290000Sglebius if (AF_INET != family && AF_INET6 != family) 175154359Sroberto continue; 1752290000Sglebius if (AF_INET == family && !ipv4_works) 175354359Sroberto continue; 1754290000Sglebius if (AF_INET6 == family && !ipv6_works) 175554359Sroberto continue; 175654359Sroberto 1757290000Sglebius /* create prototype */ 1758290000Sglebius init_interface(&enumep); 1759290000Sglebius 1760290000Sglebius convert_isc_if(&isc_if, &enumep, port); 1761290000Sglebius 1762290000Sglebius DPRINT_INTERFACE(4, (&enumep, "examining ", "\n")); 1763290000Sglebius 1764182007Sroberto /* 1765290000Sglebius * Check if and how we are going to use the interface. 1766182007Sroberto */ 1767290000Sglebius switch (interface_action(enumep.name, &enumep.sin, 1768290000Sglebius enumep.flags)) { 1769182007Sroberto 1770290000Sglebius case ACTION_IGNORE: 1771290000Sglebius DPRINTF(4, ("ignoring interface %s (%s) - by nic rules\n", 1772290000Sglebius enumep.name, stoa(&enumep.sin))); 1773290000Sglebius continue; 1774182007Sroberto 1775290000Sglebius case ACTION_LISTEN: 1776290000Sglebius DPRINTF(4, ("listen interface %s (%s) - by nic rules\n", 1777290000Sglebius enumep.name, stoa(&enumep.sin))); 1778290000Sglebius enumep.ignore_packets = ISC_FALSE; 1779290000Sglebius break; 1780290000Sglebius 1781290000Sglebius case ACTION_DROP: 1782290000Sglebius DPRINTF(4, ("drop on interface %s (%s) - by nic rules\n", 1783290000Sglebius enumep.name, stoa(&enumep.sin))); 1784290000Sglebius enumep.ignore_packets = ISC_TRUE; 1785290000Sglebius break; 178654359Sroberto } 1787182007Sroberto 1788290000Sglebius /* interfaces must be UP to be usable */ 1789290000Sglebius if (!(enumep.flags & INT_UP)) { 1790290000Sglebius DPRINTF(4, ("skipping interface %s (%s) - DOWN\n", 1791290000Sglebius enumep.name, stoa(&enumep.sin))); 1792182007Sroberto continue; 1793182007Sroberto } 1794182007Sroberto 1795182007Sroberto /* 1796182007Sroberto * skip any interfaces UP and bound to a wildcard 1797182007Sroberto * address - some dhcp clients produce that in the 1798182007Sroberto * wild 1799182007Sroberto */ 1800290000Sglebius if (is_wildcard_addr(&enumep.sin)) 1801182007Sroberto continue; 1802182007Sroberto 1803290000Sglebius if (is_anycast(&enumep.sin, isc_if.name)) 1804199995Sume continue; 1805199995Sume 1806182007Sroberto /* 1807290000Sglebius * skip any address that is an invalid state to be used 1808182007Sroberto */ 1809290000Sglebius if (!is_valid(&enumep.sin, isc_if.name)) 1810290000Sglebius continue; 1811290000Sglebius 1812290000Sglebius /* 1813290000Sglebius * map to local *address* in order to map all duplicate 1814290000Sglebius * interfaces to an endpt structure with the appropriate 1815290000Sglebius * socket. Our name space is (ip-address), NOT 1816290000Sglebius * (interface name, ip-address). 1817290000Sglebius */ 1818290000Sglebius ep = getinterface(&enumep.sin, INT_WILDCARD); 1819290000Sglebius 1820290000Sglebius if (ep != NULL && refresh_interface(ep)) { 1821182007Sroberto /* 1822290000Sglebius * found existing and up to date interface - 1823290000Sglebius * mark present. 1824182007Sroberto */ 1825290000Sglebius if (ep->phase != sys_interphase) { 1826290000Sglebius /* 1827290000Sglebius * On a new round we reset the name so 1828290000Sglebius * the interface name shows up again if 1829290000Sglebius * this address is no longer shared. 1830290000Sglebius * We reset ignore_packets from the 1831290000Sglebius * new prototype to respect any runtime 1832290000Sglebius * changes to the nic rules. 1833290000Sglebius */ 1834290000Sglebius strlcpy(ep->name, enumep.name, 1835290000Sglebius sizeof(ep->name)); 1836290000Sglebius ep->ignore_packets = 1837290000Sglebius enumep.ignore_packets; 1838290000Sglebius } else { 1839290000Sglebius /* name collision - rename interface */ 1840290000Sglebius strlcpy(ep->name, "*multiple*", 1841290000Sglebius sizeof(ep->name)); 1842290000Sglebius } 1843182007Sroberto 1844290000Sglebius DPRINT_INTERFACE(4, (ep, "updating ", 1845290000Sglebius " present\n")); 1846290000Sglebius 1847290000Sglebius if (ep->ignore_packets != 1848290000Sglebius enumep.ignore_packets) { 1849290000Sglebius /* 1850290000Sglebius * We have conflicting configurations 1851290000Sglebius * for the interface address. This is 1852290000Sglebius * caused by using -I <interfacename> 1853290000Sglebius * for an interface that shares its 1854290000Sglebius * address with other interfaces. We 1855290000Sglebius * can not disambiguate incoming 1856290000Sglebius * packets delivered to this socket 1857290000Sglebius * without extra syscalls/features. 1858290000Sglebius * These are not (commonly) available. 1859290000Sglebius * Note this is a more unusual 1860290000Sglebius * configuration where several 1861290000Sglebius * interfaces share an address but 1862290000Sglebius * filtering via interface name is 1863290000Sglebius * attempted. We resolve the 1864290000Sglebius * configuration conflict by disabling 1865290000Sglebius * the processing of received packets. 1866290000Sglebius * This leads to no service on the 1867290000Sglebius * interface address where the conflict 1868290000Sglebius * occurs. 1869290000Sglebius */ 1870290000Sglebius msyslog(LOG_ERR, 1871290000Sglebius "WARNING: conflicting enable configuration for interfaces %s and %s for address %s - unsupported configuration - address DISABLED", 1872290000Sglebius enumep.name, ep->name, 1873290000Sglebius stoa(&enumep.sin)); 1874290000Sglebius 1875290000Sglebius ep->ignore_packets = ISC_TRUE; 1876290000Sglebius } 1877290000Sglebius 1878290000Sglebius ep->phase = sys_interphase; 1879290000Sglebius 1880182007Sroberto ifi.action = IFS_EXISTS; 1881290000Sglebius ifi.ep = ep; 1882290000Sglebius if (receiver != NULL) 1883290000Sglebius (*receiver)(data, &ifi); 1884290000Sglebius } else { 1885182007Sroberto /* 1886290000Sglebius * This is new or refreshing failed - add to 1887290000Sglebius * our interface list. If refreshing failed we 1888290000Sglebius * will delete the interface structure in phase 1889290000Sglebius * 2 as the interface was not marked current. 1890290000Sglebius * We can bind to the address as the refresh 1891290000Sglebius * code already closed the offending socket 1892182007Sroberto */ 1893290000Sglebius ep = create_interface(port, &enumep); 1894182007Sroberto 1895290000Sglebius if (ep != NULL) { 1896182007Sroberto ifi.action = IFS_CREATED; 1897290000Sglebius ifi.ep = ep; 1898290000Sglebius if (receiver != NULL) 1899290000Sglebius (*receiver)(data, &ifi); 1900182007Sroberto 1901290000Sglebius new_interface_found = TRUE; 1902290000Sglebius DPRINT_INTERFACE(3, 1903290000Sglebius (ep, "updating ", 1904290000Sglebius " new - created\n")); 1905290000Sglebius } else { 1906290000Sglebius DPRINT_INTERFACE(3, 1907290000Sglebius (&enumep, "updating ", 1908290000Sglebius " new - creation FAILED")); 1909182007Sroberto 1910290000Sglebius msyslog(LOG_INFO, 1911290000Sglebius "failed to init interface for address %s", 1912290000Sglebius stoa(&enumep.sin)); 1913182007Sroberto continue; 1914182007Sroberto } 1915182007Sroberto } 191654359Sroberto } 1917182007Sroberto 1918132451Sroberto isc_interfaceiter_destroy(&iter); 191954359Sroberto 1920132451Sroberto /* 1921290000Sglebius * phase 2 - delete gone interfaces - reassigning peers to 1922290000Sglebius * other interfaces 1923132451Sroberto */ 1924290000Sglebius for (ep = ep_list; ep != NULL; ep = next_ep) { 1925290000Sglebius next_ep = ep->elink; 1926182007Sroberto 1927290000Sglebius /* 1928290000Sglebius * if phase does not match sys_phase this interface was 1929290000Sglebius * not enumerated during the last interface scan - so it 1930290000Sglebius * is gone and will be deleted here unless it did not 1931290000Sglebius * originate from interface enumeration (INT_WILDCARD, 1932290000Sglebius * INT_MCASTIF). 1933290000Sglebius */ 1934290000Sglebius if (((INT_WILDCARD | INT_MCASTIF) & ep->flags) || 1935290000Sglebius ep->phase == sys_interphase) 1936290000Sglebius continue; 1937182007Sroberto 1938290000Sglebius DPRINT_INTERFACE(3, (ep, "updating ", 1939290000Sglebius "GONE - deleting\n")); 1940290000Sglebius remove_interface(ep); 1941182007Sroberto 1942290000Sglebius ifi.action = IFS_DELETED; 1943290000Sglebius ifi.ep = ep; 1944290000Sglebius if (receiver != NULL) 1945290000Sglebius (*receiver)(data, &ifi); 1946182007Sroberto 1947290000Sglebius /* disconnect peers from deleted endpt. */ 1948290000Sglebius while (ep->peers != NULL) 1949290000Sglebius set_peerdstadr(ep->peers, NULL); 1950182007Sroberto 1951290000Sglebius /* 1952290000Sglebius * update globals in case we lose 1953290000Sglebius * a loopback interface 1954290000Sglebius */ 1955290000Sglebius if (ep == loopback_interface) 1956290000Sglebius loopback_interface = NULL; 1957290000Sglebius 1958290000Sglebius delete_interface(ep); 1959290000Sglebius } 1960290000Sglebius 1961290000Sglebius /* 1962290000Sglebius * phase 3 - re-configure as the world has possibly changed 1963290000Sglebius * 1964290000Sglebius * never ever make this conditional again - it is needed to track 1965290000Sglebius * routing updates. see bug #2506 1966290000Sglebius */ 1967290000Sglebius refresh_all_peerinterfaces(); 1968290000Sglebius 1969290000Sglebius if (broadcast_client_enabled) 1970290000Sglebius io_setbclient(); 1971290000Sglebius 1972290000Sglebius if (sys_bclient) 1973290000Sglebius io_setbclient(); 1974290000Sglebius 1975290000Sglebius#ifdef MCAST 1976290000Sglebius /* 1977290000Sglebius * Check multicast interfaces and try to join multicast groups if 1978290000Sglebius * not joined yet. 1979290000Sglebius */ 1980290000Sglebius for (ep = ep_list; ep != NULL; ep = ep->elink) { 1981290000Sglebius remaddr_t *entry; 1982290000Sglebius 1983290000Sglebius if (!(INT_MCASTIF & ep->flags) || (INT_MCASTOPEN & ep->flags)) 1984290000Sglebius continue; 1985290000Sglebius 1986290000Sglebius /* Find remote address that was linked to this interface */ 1987290000Sglebius for (entry = remoteaddr_list; 1988290000Sglebius entry != NULL; 1989290000Sglebius entry = entry->link) { 1990290000Sglebius if (entry->ep == ep) { 1991290000Sglebius if (socket_multicast_enable(ep, &entry->addr)) { 1992290000Sglebius msyslog(LOG_INFO, 1993290000Sglebius "Joined %s socket to multicast group %s", 1994290000Sglebius stoa(&ep->sin), 1995290000Sglebius stoa(&entry->addr)); 1996182007Sroberto } 1997290000Sglebius break; 1998182007Sroberto } 199954359Sroberto } 200054359Sroberto } 2001290000Sglebius#endif /* MCAST */ 200254359Sroberto 2003182007Sroberto return new_interface_found; 2004182007Sroberto} 200554359Sroberto 2006182007Sroberto 2007182007Sroberto/* 2008182007Sroberto * create_sockets - create a socket for each interface plus a default 2009182007Sroberto * socket for when we don't know where to send 2010182007Sroberto */ 2011182007Srobertostatic int 2012182007Srobertocreate_sockets( 2013182007Sroberto u_short port 2014182007Sroberto ) 2015182007Sroberto{ 2016182007Sroberto#ifndef HAVE_IO_COMPLETION_PORT 201754359Sroberto /* 2018182007Sroberto * I/O Completion Ports don't care about the select and FD_SET 201954359Sroberto */ 2020182007Sroberto maxactivefd = 0; 2021182007Sroberto FD_ZERO(&activefds); 2022182007Sroberto#endif 2023132451Sroberto 2024290000Sglebius DPRINTF(2, ("create_sockets(%d)\n", port)); 2025132451Sroberto 2026182007Sroberto create_wildcards(port); 2027182007Sroberto 2028182007Sroberto update_interfaces(port, NULL, NULL); 2029290000Sglebius 2030132451Sroberto /* 2031182007Sroberto * Now that we have opened all the sockets, turn off the reuse 2032182007Sroberto * flag for security. 2033132451Sroberto */ 2034182007Sroberto set_reuseaddr(0); 2035132451Sroberto 2036182007Sroberto DPRINTF(2, ("create_sockets: Total interfaces = %d\n", ninterfaces)); 2037132451Sroberto 203854359Sroberto return ninterfaces; 203954359Sroberto} 204054359Sroberto 204154359Sroberto/* 2042182007Sroberto * create_interface - create a new interface for a given prototype 2043182007Sroberto * binding the socket. 204454359Sroberto */ 2045182007Srobertostatic struct interface * 2046182007Srobertocreate_interface( 2047290000Sglebius u_short port, 2048290000Sglebius struct interface * protot 2049290000Sglebius ) 205054359Sroberto{ 2051290000Sglebius sockaddr_u resmask; 2052290000Sglebius endpt * iface; 2053290000Sglebius#if defined(MCAST) && defined(MULTICAST_NONEWSOCKET) 2054290000Sglebius remaddr_t * entry; 2055290000Sglebius remaddr_t * next_entry; 2056290000Sglebius#endif 2057290000Sglebius DPRINTF(2, ("create_interface(%s#%d)\n", stoa(&protot->sin), 2058290000Sglebius port)); 205954359Sroberto 2060290000Sglebius /* build an interface */ 2061290000Sglebius iface = new_interface(protot); 2062132451Sroberto 2063182007Sroberto /* 2064182007Sroberto * create socket 2065182007Sroberto */ 2066290000Sglebius iface->fd = open_socket(&iface->sin, 0, 0, iface); 206782498Sroberto 2068290000Sglebius if (iface->fd != INVALID_SOCKET) 2069290000Sglebius log_listen_address(iface); 207082498Sroberto 2071290000Sglebius if ((INT_BROADCAST & iface->flags) 2072290000Sglebius && iface->bfd != INVALID_SOCKET) 2073290000Sglebius msyslog(LOG_INFO, "Listening on broadcast address %s#%d", 2074290000Sglebius stoa((&iface->bcast)), port); 2075182007Sroberto 2076290000Sglebius if (INVALID_SOCKET == iface->fd 2077290000Sglebius && INVALID_SOCKET == iface->bfd) { 2078182007Sroberto msyslog(LOG_ERR, "unable to create socket on %s (%d) for %s#%d", 2079290000Sglebius iface->name, 2080290000Sglebius iface->ifnum, 2081290000Sglebius stoa((&iface->sin)), 2082290000Sglebius port); 2083290000Sglebius delete_interface(iface); 2084182007Sroberto return NULL; 208554359Sroberto } 2086290000Sglebius 2087290000Sglebius /* 2088290000Sglebius * Blacklist our own addresses, no use talking to ourself 2089182007Sroberto */ 2090290000Sglebius SET_HOSTMASK(&resmask, AF(&iface->sin)); 2091290000Sglebius hack_restrict(RESTRICT_FLAGS, &iface->sin, &resmask, 2092290000Sglebius RESM_NTPONLY | RESM_INTERFACE, RES_IGNORE, 0); 2093290000Sglebius 2094182007Sroberto /* 2095182007Sroberto * set globals with the first found 2096182007Sroberto * loopback interface of the appropriate class 2097182007Sroberto */ 2098290000Sglebius if (NULL == loopback_interface && AF_INET == iface->family 2099290000Sglebius && (INT_LOOPBACK & iface->flags)) 2100290000Sglebius loopback_interface = iface; 2101182007Sroberto 2102182007Sroberto /* 2103182007Sroberto * put into our interface list 2104182007Sroberto */ 2105290000Sglebius add_addr_to_list(&iface->sin, iface); 2106290000Sglebius add_interface(iface); 2107182007Sroberto 2108290000Sglebius#if defined(MCAST) && defined(MULTICAST_NONEWSOCKET) 2109290000Sglebius /* 2110290000Sglebius * Join any previously-configured compatible multicast groups. 2111290000Sglebius */ 2112290000Sglebius if (INT_MULTICAST & iface->flags && 2113290000Sglebius !((INT_LOOPBACK | INT_WILDCARD) & iface->flags) && 2114290000Sglebius !iface->ignore_packets) { 2115290000Sglebius for (entry = remoteaddr_list; 2116290000Sglebius entry != NULL; 2117290000Sglebius entry = next_entry) { 2118290000Sglebius next_entry = entry->link; 2119290000Sglebius if (AF(&iface->sin) != AF(&entry->addr) || 2120290000Sglebius !IS_MCAST(&entry->addr)) 2121290000Sglebius continue; 2122290000Sglebius if (socket_multicast_enable(iface, 2123290000Sglebius &entry->addr)) 2124290000Sglebius msyslog(LOG_INFO, 2125290000Sglebius "Joined %s socket to multicast group %s", 2126290000Sglebius stoa(&iface->sin), 2127290000Sglebius stoa(&entry->addr)); 2128290000Sglebius else 2129290000Sglebius msyslog(LOG_ERR, 2130290000Sglebius "Failed to join %s socket to multicast group %s", 2131290000Sglebius stoa(&iface->sin), 2132290000Sglebius stoa(&entry->addr)); 2133290000Sglebius } 2134290000Sglebius } 2135290000Sglebius#endif /* MCAST && MCAST_NONEWSOCKET */ 2136290000Sglebius 2137290000Sglebius DPRINT_INTERFACE(2, (iface, "created ", "\n")); 2138290000Sglebius return iface; 213954359Sroberto} 214054359Sroberto 2141200576Sroberto 2142200576Sroberto#ifdef SO_EXCLUSIVEADDRUSE 2143200576Srobertostatic void 2144290000Sglebiusset_excladdruse( 2145290000Sglebius SOCKET fd 2146290000Sglebius ) 2147200576Sroberto{ 2148200576Sroberto int one = 1; 2149200576Sroberto int failed; 2150290000Sglebius#ifdef SYS_WINNT 2151290000Sglebius DWORD err; 2152290000Sglebius#endif 2153200576Sroberto 2154200576Sroberto failed = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, 2155200576Sroberto (char *)&one, sizeof(one)); 2156200576Sroberto 2157290000Sglebius if (!failed) 2158290000Sglebius return; 2159290000Sglebius 2160290000Sglebius#ifdef SYS_WINNT 2161290000Sglebius /* 2162290000Sglebius * Prior to Windows XP setting SO_EXCLUSIVEADDRUSE can fail with 2163290000Sglebius * error WSAINVAL depending on service pack level and whether 2164290000Sglebius * the user account is in the Administrators group. Do not 2165290000Sglebius * complain if it fails that way on versions prior to XP (5.1). 2166290000Sglebius */ 2167290000Sglebius err = GetLastError(); 2168290000Sglebius 2169290000Sglebius if (isc_win32os_versioncheck(5, 1, 0, 0) < 0 /* < 5.1/XP */ 2170290000Sglebius && WSAEINVAL == err) 2171290000Sglebius return; 2172290000Sglebius 2173290000Sglebius SetLastError(err); 2174290000Sglebius#endif 2175290000Sglebius msyslog(LOG_ERR, 2176290000Sglebius "setsockopt(%d, SO_EXCLUSIVEADDRUSE, on): %m", 2177290000Sglebius (int)fd); 2178200576Sroberto} 2179200576Sroberto#endif /* SO_EXCLUSIVEADDRUSE */ 2180200576Sroberto 2181200576Sroberto 2182132451Sroberto/* 2183132451Sroberto * set_reuseaddr() - set/clear REUSEADDR on all sockets 2184132451Sroberto * NB possible hole - should we be doing this on broadcast 2185132451Sroberto * fd's also? 2186132451Sroberto */ 2187132451Srobertostatic void 2188290000Sglebiusset_reuseaddr( 2189290000Sglebius int flag 2190290000Sglebius ) 2191290000Sglebius{ 2192200576Sroberto#ifndef SO_EXCLUSIVEADDRUSE 2193290000Sglebius endpt *ep; 2194200576Sroberto 2195290000Sglebius for (ep = ep_list; ep != NULL; ep = ep->elink) { 2196290000Sglebius if (ep->flags & INT_WILDCARD) 2197290000Sglebius continue; 2198200576Sroberto 2199132451Sroberto /* 2200290000Sglebius * if ep->fd is INVALID_SOCKET, we might have a adapter 2201132451Sroberto * configured but not present 2202132451Sroberto */ 2203290000Sglebius DPRINTF(4, ("setting SO_REUSEADDR on %.16s@%s to %s\n", 2204290000Sglebius ep->name, stoa(&ep->sin), 2205290000Sglebius flag ? "on" : "off")); 2206290000Sglebius 2207290000Sglebius if (ep->fd != INVALID_SOCKET) { 2208290000Sglebius if (setsockopt(ep->fd, SOL_SOCKET, SO_REUSEADDR, 2209290000Sglebius (char *)&flag, sizeof(flag))) { 2210290000Sglebius msyslog(LOG_ERR, "set_reuseaddr: setsockopt(%s, SO_REUSEADDR, %s) failed: %m", 2211290000Sglebius stoa(&ep->sin), flag ? "on" : "off"); 2212132451Sroberto } 2213132451Sroberto } 2214132451Sroberto } 2215200576Sroberto#endif /* ! SO_EXCLUSIVEADDRUSE */ 2216132451Sroberto} 2217132451Sroberto 2218182007Sroberto/* 2219182007Sroberto * This is just a wrapper around an internal function so we can 2220182007Sroberto * make other changes as necessary later on 2221182007Sroberto */ 2222182007Srobertovoid 2223290000Sglebiusenable_broadcast( 2224290000Sglebius struct interface * iface, 2225290000Sglebius sockaddr_u * baddr 2226290000Sglebius ) 2227182007Sroberto{ 2228290000Sglebius#ifdef OPEN_BCAST_SOCKET 2229182007Sroberto socket_broadcast_enable(iface, iface->fd, baddr); 2230182007Sroberto#endif 2231182007Sroberto} 2232132451Sroberto 2233290000Sglebius#ifdef OPEN_BCAST_SOCKET 223454359Sroberto/* 2235182007Sroberto * Enable a broadcast address to a given socket 2236290000Sglebius * The socket is in the ep_list all we need to do is enable 2237182007Sroberto * broadcasting. It is not this function's job to select the socket 223854359Sroberto */ 2239182007Srobertostatic isc_boolean_t 2240290000Sglebiussocket_broadcast_enable( 2241290000Sglebius struct interface * iface, 2242290000Sglebius SOCKET fd, 2243290000Sglebius sockaddr_u * baddr 2244290000Sglebius ) 2245182007Sroberto{ 2246182007Sroberto#ifdef SO_BROADCAST 2247182007Sroberto int on = 1; 2248182007Sroberto 2249290000Sglebius if (IS_IPV4(baddr)) { 2250182007Sroberto /* if this interface can support broadcast, set SO_BROADCAST */ 2251182007Sroberto if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, 2252182007Sroberto (char *)&on, sizeof(on))) 2253290000Sglebius msyslog(LOG_ERR, 2254290000Sglebius "setsockopt(SO_BROADCAST) enable failure on address %s: %m", 2255290000Sglebius stoa(baddr)); 2256290000Sglebius else 2257290000Sglebius DPRINTF(2, ("Broadcast enabled on socket %d for address %s\n", 2258290000Sglebius fd, stoa(baddr))); 2259182007Sroberto } 2260290000Sglebius iface->flags |= INT_BCASTXMIT; 2261182007Sroberto return ISC_TRUE; 2262182007Sroberto#else 2263182007Sroberto return ISC_FALSE; 2264182007Sroberto#endif /* SO_BROADCAST */ 2265182007Sroberto} 2266182007Sroberto 2267290000Sglebius#ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES 2268182007Sroberto/* 2269182007Sroberto * Remove a broadcast address from a given socket 2270290000Sglebius * The socket is in the ep_list all we need to do is disable 2271182007Sroberto * broadcasting. It is not this function's job to select the socket 2272182007Sroberto */ 2273182007Srobertostatic isc_boolean_t 2274290000Sglebiussocket_broadcast_disable( 2275290000Sglebius struct interface * iface, 2276290000Sglebius sockaddr_u * baddr 2277290000Sglebius ) 2278182007Sroberto{ 2279182007Sroberto#ifdef SO_BROADCAST 2280182007Sroberto int off = 0; /* This seems to be OK as an int */ 2281182007Sroberto 2282290000Sglebius if (IS_IPV4(baddr) && setsockopt(iface->fd, SOL_SOCKET, 2283290000Sglebius SO_BROADCAST, (char *)&off, sizeof(off))) 2284290000Sglebius msyslog(LOG_ERR, 2285290000Sglebius "setsockopt(SO_BROADCAST) disable failure on address %s: %m", 2286290000Sglebius stoa(baddr)); 2287290000Sglebius 2288290000Sglebius iface->flags &= ~INT_BCASTXMIT; 2289182007Sroberto return ISC_TRUE; 2290182007Sroberto#else 2291182007Sroberto return ISC_FALSE; 2292182007Sroberto#endif /* SO_BROADCAST */ 2293182007Sroberto} 2294290000Sglebius#endif /* OS_MISSES_SPECIFIC_ROUTE_UPDATES */ 2295182007Sroberto 2296182007Sroberto#endif /* OPEN_BCAST_SOCKET */ 2297290000Sglebius 2298182007Sroberto/* 2299290000Sglebius * return the broadcast client flag value 2300290000Sglebius */ 2301290000Sglebiusisc_boolean_t 2302290000Sglebiusget_broadcastclient_flag(void) 2303290000Sglebius{ 2304290000Sglebius return (broadcast_client_enabled); 2305290000Sglebius} 2306294904Sdelphij 2307290000Sglebius/* 2308182007Sroberto * Check to see if the address is a multicast address 2309182007Sroberto */ 2310182007Srobertostatic isc_boolean_t 2311290000Sglebiusaddr_ismulticast( 2312290000Sglebius sockaddr_u *maddr 2313290000Sglebius ) 2314182007Sroberto{ 2315290000Sglebius isc_boolean_t result; 2316182007Sroberto 2317290000Sglebius#ifndef INCLUDE_IPV6_MULTICAST_SUPPORT 2318182007Sroberto /* 2319290000Sglebius * If we don't have IPV6 support any IPV6 addr is not multicast 2320182007Sroberto */ 2321290000Sglebius if (IS_IPV6(maddr)) 2322290000Sglebius result = ISC_FALSE; 2323290000Sglebius else 2324290000Sglebius#endif 2325290000Sglebius result = IS_MCAST(maddr); 2326290000Sglebius 2327290000Sglebius if (!result) 2328290000Sglebius DPRINTF(4, ("address %s is not multicast\n", 2329290000Sglebius stoa(maddr))); 2330290000Sglebius 2331290000Sglebius return result; 2332182007Sroberto} 2333182007Sroberto 2334182007Sroberto/* 2335182007Sroberto * Multicast servers need to set the appropriate Multicast interface 2336182007Sroberto * socket option in order for it to know which interface to use for 2337182007Sroberto * send the multicast packet. 2338182007Sroberto */ 233954359Srobertovoid 2340290000Sglebiusenable_multicast_if( 2341290000Sglebius struct interface * iface, 2342290000Sglebius sockaddr_u * maddr 2343290000Sglebius ) 234454359Sroberto{ 234554359Sroberto#ifdef MCAST 2346222444Sbz#ifdef IP_MULTICAST_LOOP 2347290000Sglebius TYPEOF_IP_MULTICAST_LOOP off = 0; 2348222444Sbz#endif 2349290000Sglebius#if defined(INCLUDE_IPV6_MULTICAST_SUPPORT) && defined(IPV6_MULTICAST_LOOP) 2350290000Sglebius u_int off6 = 0; 2351222444Sbz#endif 235254359Sroberto 2353290000Sglebius REQUIRE(AF(maddr) == AF(&iface->sin)); 2354290000Sglebius 2355290000Sglebius switch (AF(&iface->sin)) { 2356290000Sglebius 2357182007Sroberto case AF_INET: 2358182007Sroberto#ifdef IP_MULTICAST_LOOP 2359182007Sroberto /* 2360290000Sglebius * Don't send back to itself, but allow failure to set 2361182007Sroberto */ 2362290000Sglebius if (setsockopt(iface->fd, IPPROTO_IP, 2363290000Sglebius IP_MULTICAST_LOOP, 2364290000Sglebius SETSOCKOPT_ARG_CAST &off, 2365290000Sglebius sizeof(off))) { 2366290000Sglebius 2367290000Sglebius msyslog(LOG_ERR, 2368290000Sglebius "setsockopt IP_MULTICAST_LOOP failed: %m on socket %d, addr %s for multicast address %s", 2369290000Sglebius iface->fd, stoa(&iface->sin), 2370290000Sglebius stoa(maddr)); 2371132451Sroberto } 2372182007Sroberto#endif 2373182007Sroberto break; 2374132451Sroberto 2375182007Sroberto case AF_INET6: 2376182007Sroberto#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT 2377182007Sroberto#ifdef IPV6_MULTICAST_LOOP 2378132451Sroberto /* 2379290000Sglebius * Don't send back to itself, but allow failure to set 2380182007Sroberto */ 2381290000Sglebius if (setsockopt(iface->fd, IPPROTO_IPV6, 2382290000Sglebius IPV6_MULTICAST_LOOP, 2383290000Sglebius (char *) &off6, sizeof(off6))) { 2384290000Sglebius 2385290000Sglebius msyslog(LOG_ERR, 2386290000Sglebius "setsockopt IPV6_MULTICAST_LOOP failed: %m on socket %d, addr %s for multicast address %s", 2387290000Sglebius iface->fd, stoa(&iface->sin), 2388290000Sglebius stoa(maddr)); 2389182007Sroberto } 2390132451Sroberto#endif 2391182007Sroberto break; 2392182007Sroberto#else 2393182007Sroberto return; 2394182007Sroberto#endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */ 2395182007Sroberto } 2396182007Sroberto return; 2397182007Sroberto#endif 2398182007Sroberto} 2399132451Sroberto 2400182007Sroberto/* 2401182007Sroberto * Add a multicast address to a given socket 2402290000Sglebius * The socket is in the ep_list all we need to do is enable 2403182007Sroberto * multicasting. It is not this function's job to select the socket 2404182007Sroberto */ 2405290000Sglebius#if defined(MCAST) 2406182007Srobertostatic isc_boolean_t 2407290000Sglebiussocket_multicast_enable( 2408290000Sglebius endpt * iface, 2409290000Sglebius sockaddr_u * maddr 2410290000Sglebius ) 2411182007Sroberto{ 2412290000Sglebius struct ip_mreq mreq; 2413290000Sglebius# ifdef INCLUDE_IPV6_MULTICAST_SUPPORT 2414290000Sglebius struct ipv6_mreq mreq6; 2415290000Sglebius# endif 2416290000Sglebius switch (AF(maddr)) { 2417182007Sroberto 2418182007Sroberto case AF_INET: 2419290000Sglebius ZERO(mreq); 2420290000Sglebius mreq.imr_multiaddr = SOCK_ADDR4(maddr); 2421132451Sroberto mreq.imr_interface.s_addr = htonl(INADDR_ANY); 2422290000Sglebius if (setsockopt(iface->fd, 2423290000Sglebius IPPROTO_IP, 2424290000Sglebius IP_ADD_MEMBERSHIP, 2425290000Sglebius (char *)&mreq, 2426290000Sglebius sizeof(mreq))) { 2427290000Sglebius DPRINTF(2, ( 2428290000Sglebius "setsockopt IP_ADD_MEMBERSHIP failed: %m on socket %d, addr %s for %x / %x (%s)", 2429290000Sglebius iface->fd, stoa(&iface->sin), 2430290000Sglebius mreq.imr_multiaddr.s_addr, 2431290000Sglebius mreq.imr_interface.s_addr, 2432290000Sglebius stoa(maddr))); 2433182007Sroberto return ISC_FALSE; 2434182007Sroberto } 2435182007Sroberto DPRINTF(4, ("Added IPv4 multicast membership on socket %d, addr %s for %x / %x (%s)\n", 2436182007Sroberto iface->fd, stoa(&iface->sin), 2437182007Sroberto mreq.imr_multiaddr.s_addr, 2438182007Sroberto mreq.imr_interface.s_addr, stoa(maddr))); 2439182007Sroberto break; 2440132451Sroberto 2441182007Sroberto case AF_INET6: 2442290000Sglebius# ifdef INCLUDE_IPV6_MULTICAST_SUPPORT 2443182007Sroberto /* 2444290000Sglebius * Enable reception of multicast packets. 2445290000Sglebius * If the address is link-local we can get the 2446290000Sglebius * interface index from the scope id. Don't do this 2447290000Sglebius * for other types of multicast addresses. For now let 2448290000Sglebius * the kernel figure it out. 2449182007Sroberto */ 2450290000Sglebius ZERO(mreq6); 2451290000Sglebius mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr); 2452290000Sglebius mreq6.ipv6mr_interface = iface->ifindex; 2453182007Sroberto 2454290000Sglebius if (setsockopt(iface->fd, IPPROTO_IPV6, 2455290000Sglebius IPV6_JOIN_GROUP, (char *)&mreq6, 2456290000Sglebius sizeof(mreq6))) { 2457290000Sglebius DPRINTF(2, ( 2458290000Sglebius "setsockopt IPV6_JOIN_GROUP failed: %m on socket %d, addr %s for interface %u (%s)", 2459290000Sglebius iface->fd, stoa(&iface->sin), 2460290000Sglebius mreq6.ipv6mr_interface, stoa(maddr))); 2461182007Sroberto return ISC_FALSE; 2462182007Sroberto } 2463290000Sglebius DPRINTF(4, ("Added IPv6 multicast group on socket %d, addr %s for interface %u (%s)\n", 2464182007Sroberto iface->fd, stoa(&iface->sin), 2465182007Sroberto mreq6.ipv6mr_interface, stoa(maddr))); 2466290000Sglebius# else 2467182007Sroberto return ISC_FALSE; 2468290000Sglebius# endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */ 2469182007Sroberto } 2470182007Sroberto iface->flags |= INT_MCASTOPEN; 2471182007Sroberto iface->num_mcast++; 2472290000Sglebius 2473182007Sroberto return ISC_TRUE; 2474182007Sroberto} 2475290000Sglebius#endif /* MCAST */ 247654359Sroberto 2477290000Sglebius 2478182007Sroberto/* 2479182007Sroberto * Remove a multicast address from a given socket 2480290000Sglebius * The socket is in the ep_list all we need to do is disable 2481182007Sroberto * multicasting. It is not this function's job to select the socket 2482182007Sroberto */ 2483290000Sglebius#ifdef MCAST 2484182007Srobertostatic isc_boolean_t 2485290000Sglebiussocket_multicast_disable( 2486290000Sglebius struct interface * iface, 2487290000Sglebius sockaddr_u * maddr 2488290000Sglebius ) 2489182007Sroberto{ 2490290000Sglebius# ifdef INCLUDE_IPV6_MULTICAST_SUPPORT 2491182007Sroberto struct ipv6_mreq mreq6; 2492290000Sglebius# endif 2493182007Sroberto struct ip_mreq mreq; 2494182007Sroberto 2495290000Sglebius ZERO(mreq); 2496290000Sglebius 2497182007Sroberto if (find_addr_in_list(maddr) == NULL) { 2498290000Sglebius DPRINTF(4, ("socket_multicast_disable(%s): not found\n", 2499290000Sglebius stoa(maddr))); 2500182007Sroberto return ISC_TRUE; 2501182007Sroberto } 2502182007Sroberto 2503290000Sglebius switch (AF(maddr)) { 2504290000Sglebius 2505182007Sroberto case AF_INET: 2506290000Sglebius mreq.imr_multiaddr = SOCK_ADDR4(maddr); 2507290000Sglebius mreq.imr_interface = SOCK_ADDR4(&iface->sin); 2508290000Sglebius if (setsockopt(iface->fd, IPPROTO_IP, 2509290000Sglebius IP_DROP_MEMBERSHIP, (char *)&mreq, 2510290000Sglebius sizeof(mreq))) { 2511290000Sglebius 2512290000Sglebius msyslog(LOG_ERR, 2513290000Sglebius "setsockopt IP_DROP_MEMBERSHIP failed: %m on socket %d, addr %s for %x / %x (%s)", 2514290000Sglebius iface->fd, stoa(&iface->sin), 2515290000Sglebius SRCADR(maddr), SRCADR(&iface->sin), 2516290000Sglebius stoa(maddr)); 2517182007Sroberto return ISC_FALSE; 2518132451Sroberto } 2519182007Sroberto break; 2520182007Sroberto case AF_INET6: 2521290000Sglebius# ifdef INCLUDE_IPV6_MULTICAST_SUPPORT 2522132451Sroberto /* 2523182007Sroberto * Disable reception of multicast packets 2524290000Sglebius * If the address is link-local we can get the 2525290000Sglebius * interface index from the scope id. Don't do this 2526290000Sglebius * for other types of multicast addresses. For now let 2527290000Sglebius * the kernel figure it out. 2528132451Sroberto */ 2529290000Sglebius mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr); 2530290000Sglebius mreq6.ipv6mr_interface = iface->ifindex; 2531182007Sroberto 2532290000Sglebius if (setsockopt(iface->fd, IPPROTO_IPV6, 2533290000Sglebius IPV6_LEAVE_GROUP, (char *)&mreq6, 2534290000Sglebius sizeof(mreq6))) { 2535290000Sglebius 2536290000Sglebius msyslog(LOG_ERR, 2537290000Sglebius "setsockopt IPV6_LEAVE_GROUP failure: %m on socket %d, addr %s for %d (%s)", 2538290000Sglebius iface->fd, stoa(&iface->sin), 2539290000Sglebius iface->ifindex, stoa(maddr)); 2540182007Sroberto return ISC_FALSE; 2541132451Sroberto } 2542182007Sroberto break; 2543290000Sglebius# else 2544182007Sroberto return ISC_FALSE; 2545290000Sglebius# endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */ 2546290000Sglebius } 2547132451Sroberto 2548182007Sroberto iface->num_mcast--; 2549290000Sglebius if (!iface->num_mcast) 2550182007Sroberto iface->flags &= ~INT_MCASTOPEN; 2551290000Sglebius 2552182007Sroberto return ISC_TRUE; 2553182007Sroberto} 2554290000Sglebius#endif /* MCAST */ 2555182007Sroberto 2556182007Sroberto/* 2557182007Sroberto * io_setbclient - open the broadcast client sockets 2558182007Sroberto */ 2559182007Srobertovoid 2560182007Srobertoio_setbclient(void) 2561182007Sroberto{ 2562290000Sglebius#ifdef OPEN_BCAST_SOCKET 2563290000Sglebius struct interface * interf; 2564290000Sglebius int nif; 2565182007Sroberto 2566290000Sglebius nif = 0; 2567182007Sroberto set_reuseaddr(1); 2568182007Sroberto 2569290000Sglebius for (interf = ep_list; 2570182007Sroberto interf != NULL; 2571290000Sglebius interf = interf->elink) { 2572290000Sglebius 2573290000Sglebius if (interf->flags & (INT_WILDCARD | INT_LOOPBACK)) 2574290000Sglebius continue; 2575290000Sglebius 2576182007Sroberto /* use only allowed addresses */ 2577290000Sglebius if (interf->ignore_packets) 2578182007Sroberto continue; 2579182007Sroberto 2580290000Sglebius /* Need a broadcast-capable interface */ 2581182007Sroberto if (!(interf->flags & INT_BROADCAST)) 2582182007Sroberto continue; 2583182007Sroberto 2584290000Sglebius /* Only IPv4 addresses are valid for broadcast */ 2585298770Sdelphij REQUIRE(IS_IPV4(&interf->bcast)); 2586182007Sroberto 2587182007Sroberto /* Do we already have the broadcast address open? */ 2588182007Sroberto if (interf->flags & INT_BCASTOPEN) { 2589290000Sglebius /* 2590290000Sglebius * account for already open interfaces to avoid 2591290000Sglebius * misleading warning below 2592290000Sglebius */ 2593182007Sroberto nif++; 2594182007Sroberto continue; 2595182007Sroberto } 2596182007Sroberto 2597132451Sroberto /* 2598182007Sroberto * Try to open the broadcast address 2599132451Sroberto */ 2600182007Sroberto interf->family = AF_INET; 2601290000Sglebius interf->bfd = open_socket(&interf->bcast, 1, 0, interf); 2602132451Sroberto 2603290000Sglebius /* 2604290000Sglebius * If we succeeded then we use it otherwise enable 2605290000Sglebius * broadcast on the interface address 2606182007Sroberto */ 2607290000Sglebius if (interf->bfd != INVALID_SOCKET) { 2608182007Sroberto nif++; 2609290000Sglebius interf->flags |= INT_BCASTOPEN; 2610290000Sglebius msyslog(LOG_INFO, 2611290000Sglebius "Listen for broadcasts to %s on interface #%d %s", 2612290000Sglebius stoa(&interf->bcast), interf->ifnum, interf->name); 2613298770Sdelphij } else switch (errno) { 2614298770Sdelphij /* Silently ignore EADDRINUSE as we probably 2615298770Sdelphij * opened the socket already for an address in 2616298770Sdelphij * the same network */ 2617298770Sdelphij case EADDRINUSE: 2618298770Sdelphij /* Some systems cannot bind a socket to a broadcast 2619298770Sdelphij * address, as that is not a valid host address. */ 2620298770Sdelphij case EADDRNOTAVAIL: 2621298770Sdelphij# ifdef SYS_WINNT /*TODO: use for other systems, too? */ 2622298770Sdelphij /* avoid recurrence here -- if we already have a 2623298770Sdelphij * regular socket, it's quite useless to try this 2624298770Sdelphij * again. 2625298770Sdelphij */ 2626298770Sdelphij if (interf->fd != INVALID_SOCKET) { 2627298770Sdelphij interf->flags |= INT_BCASTOPEN; 2628298770Sdelphij nif++; 2629298770Sdelphij } 2630298770Sdelphij# endif 2631298770Sdelphij break; 2632298770Sdelphij 2633298770Sdelphij default: 2634298770Sdelphij msyslog(LOG_INFO, 2635298770Sdelphij "failed to listen for broadcasts to %s on interface #%d %s", 2636298770Sdelphij stoa(&interf->bcast), interf->ifnum, interf->name); 2637298770Sdelphij break; 2638182007Sroberto } 263954359Sroberto } 2640182007Sroberto set_reuseaddr(0); 2641290000Sglebius if (nif > 0) { 2642290000Sglebius broadcast_client_enabled = ISC_TRUE; 2643290000Sglebius DPRINTF(1, ("io_setbclient: listening to %d broadcast addresses\n", nif)); 2644290000Sglebius } 2645290000Sglebius else if (!nif) { 2646290000Sglebius broadcast_client_enabled = ISC_FALSE; 2647290000Sglebius msyslog(LOG_ERR, 2648290000Sglebius "Unable to listen for broadcasts, no broadcast interfaces available"); 2649290000Sglebius } 2650182007Sroberto#else 2651290000Sglebius msyslog(LOG_ERR, 2652290000Sglebius "io_setbclient: Broadcast Client disabled by build"); 2653290000Sglebius#endif /* OPEN_BCAST_SOCKET */ 265454359Sroberto} 265554359Sroberto 265654359Sroberto/* 265754359Sroberto * io_unsetbclient - close the broadcast client sockets 265854359Sroberto */ 265954359Srobertovoid 266054359Srobertoio_unsetbclient(void) 266154359Sroberto{ 2662290000Sglebius endpt *ep; 266354359Sroberto 2664290000Sglebius for (ep = ep_list; ep != NULL; ep = ep->elink) { 2665290000Sglebius if (INT_WILDCARD & ep->flags) 2666290000Sglebius continue; 2667290000Sglebius if (!(INT_BCASTOPEN & ep->flags)) 2668290000Sglebius continue; 2669290000Sglebius 2670290000Sglebius if (ep->bfd != INVALID_SOCKET) { 2671290000Sglebius /* destroy broadcast listening socket */ 2672290000Sglebius msyslog(LOG_INFO, 2673290000Sglebius "stop listening for broadcasts to %s on interface #%d %s", 2674290000Sglebius stoa(&ep->bcast), ep->ifnum, ep->name); 2675298770Sdelphij# ifdef HAVE_IO_COMPLETION_PORT 2676298770Sdelphij io_completion_port_remove_socket(ep->bfd, ep); 2677298770Sdelphij# endif 2678290000Sglebius close_and_delete_fd_from_list(ep->bfd); 2679290000Sglebius ep->bfd = INVALID_SOCKET; 2680290000Sglebius } 2681298770Sdelphij ep->flags &= ~INT_BCASTOPEN; 268254359Sroberto } 2683290000Sglebius broadcast_client_enabled = ISC_FALSE; 268454359Sroberto} 268554359Sroberto 2686182007Sroberto/* 2687182007Sroberto * io_multicast_add() - add multicast group address 2688182007Sroberto */ 2689182007Srobertovoid 2690182007Srobertoio_multicast_add( 2691290000Sglebius sockaddr_u *addr 2692182007Sroberto ) 2693182007Sroberto{ 2694182007Sroberto#ifdef MCAST 2695290000Sglebius endpt * ep; 2696290000Sglebius endpt * one_ep; 2697290000Sglebius 2698182007Sroberto /* 2699182007Sroberto * Check to see if this is a multicast address 2700182007Sroberto */ 2701290000Sglebius if (!addr_ismulticast(addr)) 2702182007Sroberto return; 270354359Sroberto 2704182007Sroberto /* If we already have it we can just return */ 2705290000Sglebius if (NULL != find_flagged_addr_in_list(addr, INT_MCASTOPEN)) { 2706290000Sglebius msyslog(LOG_INFO, 2707290000Sglebius "Duplicate request found for multicast address %s", 2708290000Sglebius stoa(addr)); 2709182007Sroberto return; 2710182007Sroberto } 2711182007Sroberto 2712290000Sglebius# ifndef MULTICAST_NONEWSOCKET 2713290000Sglebius ep = new_interface(NULL); 2714290000Sglebius 2715182007Sroberto /* 2716182007Sroberto * Open a new socket for the multicast address 2717182007Sroberto */ 2718290000Sglebius ep->sin = *addr; 2719290000Sglebius SET_PORT(&ep->sin, NTP_PORT); 2720290000Sglebius ep->family = AF(&ep->sin); 2721290000Sglebius AF(&ep->mask) = ep->family; 2722290000Sglebius SET_ONESMASK(&ep->mask); 2723182007Sroberto 2724182007Sroberto set_reuseaddr(1); 2725290000Sglebius ep->bfd = INVALID_SOCKET; 2726290000Sglebius ep->fd = open_socket(&ep->sin, 0, 0, ep); 2727290000Sglebius if (ep->fd != INVALID_SOCKET) { 2728290000Sglebius ep->ignore_packets = ISC_FALSE; 2729290000Sglebius ep->flags |= INT_MCASTIF; 2730182007Sroberto 2731290000Sglebius strlcpy(ep->name, "multicast", sizeof(ep->name)); 2732290000Sglebius DPRINT_INTERFACE(2, (ep, "multicast add ", "\n")); 2733290000Sglebius add_interface(ep); 2734290000Sglebius log_listen_address(ep); 2735290000Sglebius } else { 2736290000Sglebius /* bind failed, re-use wildcard interface */ 2737290000Sglebius delete_interface(ep); 2738182007Sroberto 2739290000Sglebius if (IS_IPV4(addr)) 2740290000Sglebius ep = wildipv4; 2741290000Sglebius else if (IS_IPV6(addr)) 2742290000Sglebius ep = wildipv6; 2743290000Sglebius else 2744290000Sglebius ep = NULL; 2745290000Sglebius 2746290000Sglebius if (ep != NULL) { 2747182007Sroberto /* HACK ! -- stuff in an address */ 2748290000Sglebius /* because we don't bind addr? DH */ 2749290000Sglebius ep->bcast = *addr; 2750290000Sglebius msyslog(LOG_ERR, 2751290000Sglebius "multicast address %s using wildcard interface #%d %s", 2752290000Sglebius stoa(addr), ep->ifnum, ep->name); 2753182007Sroberto } else { 2754290000Sglebius msyslog(LOG_ERR, 2755290000Sglebius "No multicast socket available to use for address %s", 2756290000Sglebius stoa(addr)); 2757182007Sroberto return; 2758182007Sroberto } 2759182007Sroberto } 2760290000Sglebius { /* in place of the { following for in #else clause */ 2761290000Sglebius one_ep = ep; 2762290000Sglebius# else /* MULTICAST_NONEWSOCKET follows */ 2763182007Sroberto /* 2764290000Sglebius * For the case where we can't use a separate socket (Windows) 2765290000Sglebius * join each applicable endpoint socket to the group address. 2766182007Sroberto */ 2767290000Sglebius if (IS_IPV4(addr)) 2768290000Sglebius one_ep = wildipv4; 2769290000Sglebius else 2770290000Sglebius one_ep = wildipv6; 2771290000Sglebius for (ep = ep_list; ep != NULL; ep = ep->elink) { 2772290000Sglebius if (ep->ignore_packets || AF(&ep->sin) != AF(addr) || 2773290000Sglebius !(INT_MULTICAST & ep->flags) || 2774290000Sglebius (INT_LOOPBACK | INT_WILDCARD) & ep->flags) 2775290000Sglebius continue; 2776290000Sglebius one_ep = ep; 2777290000Sglebius# endif /* MULTICAST_NONEWSOCKET */ 2778290000Sglebius if (socket_multicast_enable(ep, addr)) 2779290000Sglebius msyslog(LOG_INFO, 2780290000Sglebius "Joined %s socket to multicast group %s", 2781290000Sglebius stoa(&ep->sin), 2782290000Sglebius stoa(addr)); 2783182007Sroberto } 2784182007Sroberto 2785290000Sglebius add_addr_to_list(addr, one_ep); 2786290000Sglebius#else /* !MCAST follows*/ 2787290000Sglebius msyslog(LOG_ERR, 2788290000Sglebius "Can not add multicast address %s: no multicast support", 2789290000Sglebius stoa(addr)); 2790182007Sroberto#endif 2791182007Sroberto return; 2792182007Sroberto} 2793182007Sroberto 2794290000Sglebius 279554359Sroberto/* 279654359Sroberto * io_multicast_del() - delete multicast group address 279754359Sroberto */ 279854359Srobertovoid 279954359Srobertoio_multicast_del( 2800290000Sglebius sockaddr_u * addr 280154359Sroberto ) 280254359Sroberto{ 280354359Sroberto#ifdef MCAST 2804290000Sglebius endpt *iface; 280554359Sroberto 2806182007Sroberto /* 2807182007Sroberto * Check to see if this is a multicast address 2808182007Sroberto */ 2809290000Sglebius if (!addr_ismulticast(addr)) { 2810290000Sglebius msyslog(LOG_ERR, "invalid multicast address %s", 2811290000Sglebius stoa(addr)); 2812182007Sroberto return; 2813182007Sroberto } 2814132451Sroberto 2815290000Sglebius /* 2816290000Sglebius * Disable reception of multicast packets 2817290000Sglebius */ 2818290000Sglebius while ((iface = find_flagged_addr_in_list(addr, INT_MCASTOPEN)) 2819290000Sglebius != NULL) 2820290000Sglebius socket_multicast_disable(iface, addr); 2821132451Sroberto 2822290000Sglebius delete_addr_from_list(addr); 2823182007Sroberto 282454359Sroberto#else /* not MCAST */ 2825290000Sglebius msyslog(LOG_ERR, 2826290000Sglebius "Can not delete multicast address %s: no multicast support", 2827290000Sglebius stoa(addr)); 282854359Sroberto#endif /* not MCAST */ 282954359Sroberto} 283054359Sroberto 283154359Sroberto 283254359Sroberto/* 283354359Sroberto * open_socket - open a socket, returning the file descriptor 283454359Sroberto */ 2835132451Sroberto 2836132451Srobertostatic SOCKET 283754359Srobertoopen_socket( 2838290000Sglebius sockaddr_u * addr, 2839290000Sglebius int bcast, 2840290000Sglebius int turn_off_reuse, 2841290000Sglebius endpt * interf 284254359Sroberto ) 284354359Sroberto{ 2844290000Sglebius SOCKET fd; 2845290000Sglebius int errval; 2846200576Sroberto /* 2847290000Sglebius * int is OK for REUSEADR per 2848200576Sroberto * http://www.kohala.com/start/mcast.api.txt 2849200576Sroberto */ 2850290000Sglebius int on = 1; 2851290000Sglebius int off = 0; 2852200576Sroberto 2853290000Sglebius if (IS_IPV6(addr) && !ipv6_works) 2854290000Sglebius return INVALID_SOCKET; 285554359Sroberto 285654359Sroberto /* create a datagram (UDP) socket */ 2857290000Sglebius fd = socket(AF(addr), SOCK_DGRAM, 0); 2858200576Sroberto if (INVALID_SOCKET == fd) { 2859290000Sglebius errval = socket_errno(); 2860290000Sglebius msyslog(LOG_ERR, 2861290000Sglebius "socket(AF_INET%s, SOCK_DGRAM, 0) failed on address %s: %m", 2862290000Sglebius IS_IPV6(addr) ? "6" : "", stoa(addr)); 2863200576Sroberto 2864290000Sglebius if (errval == EPROTONOSUPPORT || 2865200576Sroberto errval == EAFNOSUPPORT || 2866132451Sroberto errval == EPFNOSUPPORT) 2867132451Sroberto return (INVALID_SOCKET); 2868290000Sglebius 2869290000Sglebius errno = errval; 2870290000Sglebius msyslog(LOG_ERR, 2871290000Sglebius "unexpected socket() error %m code %d (not EPROTONOSUPPORT nor EAFNOSUPPORT nor EPFNOSUPPORT) - exiting", 2872290000Sglebius errno); 287354359Sroberto exit(1); 287454359Sroberto } 2875200576Sroberto 2876182007Sroberto#ifdef SYS_WINNT 2877200576Sroberto connection_reset_fix(fd, addr); 2878200576Sroberto#endif 2879182007Sroberto /* 2880182007Sroberto * Fixup the file descriptor for some systems 2881182007Sroberto * See bug #530 for details of the issue. 2882182007Sroberto */ 2883182007Sroberto fd = move_fd(fd); 2884182007Sroberto 2885182007Sroberto /* 2886182007Sroberto * set SO_REUSEADDR since we will be binding the same port 2887200576Sroberto * number on each interface according to turn_off_reuse. 2888200576Sroberto * This is undesirable on Windows versions starting with 2889200576Sroberto * Windows XP (numeric version 5.1). 2890182007Sroberto */ 2891200576Sroberto#ifdef SYS_WINNT 2892200576Sroberto if (isc_win32os_versioncheck(5, 1, 0, 0) < 0) /* before 5.1 */ 2893200576Sroberto#endif 2894200576Sroberto if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 2895290000Sglebius (char *)((turn_off_reuse) 2896290000Sglebius ? &off 2897290000Sglebius : &on), 2898200576Sroberto sizeof(on))) { 2899182007Sroberto 2900290000Sglebius msyslog(LOG_ERR, 2901290000Sglebius "setsockopt SO_REUSEADDR %s fails for address %s: %m", 2902290000Sglebius (turn_off_reuse) 2903290000Sglebius ? "off" 2904290000Sglebius : "on", 2905290000Sglebius stoa(addr)); 2906200576Sroberto closesocket(fd); 2907200576Sroberto return INVALID_SOCKET; 2908200576Sroberto } 2909200576Sroberto#ifdef SO_EXCLUSIVEADDRUSE 2910200576Sroberto /* 2911200576Sroberto * setting SO_EXCLUSIVEADDRUSE on the wildcard we open 2912200576Sroberto * first will cause more specific binds to fail. 2913200576Sroberto */ 2914200576Sroberto if (!(interf->flags & INT_WILDCARD)) 2915200576Sroberto set_excladdruse(fd); 2916200576Sroberto#endif 2917182007Sroberto 2918182007Sroberto /* 2919182007Sroberto * IPv4 specific options go here 2920182007Sroberto */ 2921290000Sglebius if (IS_IPV4(addr)) { 2922290000Sglebius#if defined(IPPROTO_IP) && defined(IP_TOS) 2923290000Sglebius if (setsockopt(fd, IPPROTO_IP, IP_TOS, (char*)&qos, 2924290000Sglebius sizeof(qos))) 2925290000Sglebius msyslog(LOG_ERR, 2926290000Sglebius "setsockopt IP_TOS (%02x) fails on address %s: %m", 2927290000Sglebius qos, stoa(addr)); 2928290000Sglebius#endif /* IPPROTO_IP && IP_TOS */ 2929290000Sglebius if (bcast) 2930290000Sglebius socket_broadcast_enable(interf, fd, addr); 2931182007Sroberto } 2932132451Sroberto 2933182007Sroberto /* 2934182007Sroberto * IPv6 specific options go here 2935182007Sroberto */ 2936290000Sglebius if (IS_IPV6(addr)) { 2937290000Sglebius#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) 2938290000Sglebius if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, (char*)&qos, 2939290000Sglebius sizeof(qos))) 2940290000Sglebius msyslog(LOG_ERR, 2941290000Sglebius "setsockopt IPV6_TCLASS (%02x) fails on address %s: %m", 2942290000Sglebius qos, stoa(addr)); 2943290000Sglebius#endif /* IPPROTO_IPV6 && IPV6_TCLASS */ 2944290000Sglebius#ifdef IPV6_V6ONLY 2945290000Sglebius if (isc_net_probe_ipv6only() == ISC_R_SUCCESS 2946290000Sglebius && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, 2947290000Sglebius (char*)&on, sizeof(on))) 2948290000Sglebius msyslog(LOG_ERR, 2949290000Sglebius "setsockopt IPV6_V6ONLY on fails on address %s: %m", 2950132451Sroberto stoa(addr)); 2951290000Sglebius#endif 2952290000Sglebius#ifdef IPV6_BINDV6ONLY 2953290000Sglebius if (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDV6ONLY, 2954290000Sglebius (char*)&on, sizeof(on))) 2955290000Sglebius msyslog(LOG_ERR, 2956290000Sglebius "setsockopt IPV6_BINDV6ONLY on fails on address %s: %m", 2957290000Sglebius stoa(addr)); 2958290000Sglebius#endif 2959182007Sroberto } 2960132451Sroberto 2961182007Sroberto#ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND 2962182007Sroberto /* 2963182007Sroberto * some OSes don't allow binding to more specific 2964182007Sroberto * addresses if a wildcard address already bound 2965182007Sroberto * to the port and SO_REUSEADDR is not set 2966182007Sroberto */ 2967290000Sglebius if (!is_wildcard_addr(addr)) 2968290000Sglebius set_wildcard_reuse(AF(addr), 1); 2969182007Sroberto#endif 297056746Sroberto 297154359Sroberto /* 297254359Sroberto * bind the local address. 297354359Sroberto */ 2974290000Sglebius errval = bind(fd, &addr->sa, SOCKLEN(addr)); 2975132451Sroberto 2976182007Sroberto#ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND 2977290000Sglebius if (!is_wildcard_addr(addr)) 2978290000Sglebius set_wildcard_reuse(AF(addr), 0); 2979182007Sroberto#endif 2980132451Sroberto 2981182007Sroberto if (errval < 0) { 298254359Sroberto /* 2983182007Sroberto * Don't log this under all conditions 298454359Sroberto */ 2985182007Sroberto if (turn_off_reuse == 0 2986182007Sroberto#ifdef DEBUG 2987182007Sroberto || debug > 1 2988182007Sroberto#endif 2989290000Sglebius ) { 2990290000Sglebius msyslog(LOG_ERR, 2991290000Sglebius "bind(%d) AF_INET%s %s#%d%s flags 0x%x failed: %m", 2992290000Sglebius fd, IS_IPV6(addr) ? "6" : "", 2993290000Sglebius stoa(addr), SRCPORT(addr), 2994290000Sglebius IS_MCAST(addr) ? " (multicast)" : "", 2995290000Sglebius interf->flags); 2996132451Sroberto } 2997182007Sroberto 2998182007Sroberto closesocket(fd); 2999290000Sglebius 3000132451Sroberto return INVALID_SOCKET; 300154359Sroberto } 3002182007Sroberto 3003182007Sroberto#ifdef HAVE_TIMESTAMP 3004182007Sroberto { 3005182007Sroberto if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, 3006182007Sroberto (char*)&on, sizeof(on))) 3007290000Sglebius msyslog(LOG_DEBUG, 3008290000Sglebius "setsockopt SO_TIMESTAMP on fails on address %s: %m", 3009290000Sglebius stoa(addr)); 3010182007Sroberto else 3011290000Sglebius DPRINTF(4, ("setsockopt SO_TIMESTAMP enabled on fd %d address %s\n", 3012290000Sglebius fd, stoa(addr))); 3013290000Sglebius } 3014182007Sroberto#endif 3015290000Sglebius#ifdef HAVE_TIMESTAMPNS 3016290000Sglebius { 3017290000Sglebius if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS, 3018290000Sglebius (char*)&on, sizeof(on))) 3019290000Sglebius msyslog(LOG_DEBUG, 3020290000Sglebius "setsockopt SO_TIMESTAMPNS on fails on address %s: %m", 3021290000Sglebius stoa(addr)); 3022290000Sglebius else 3023290000Sglebius DPRINTF(4, ("setsockopt SO_TIMESTAMPNS enabled on fd %d address %s\n", 3024290000Sglebius fd, stoa(addr))); 3025290000Sglebius } 3026182007Sroberto#endif 3027290000Sglebius#ifdef HAVE_BINTIME 3028290000Sglebius { 3029290000Sglebius if (setsockopt(fd, SOL_SOCKET, SO_BINTIME, 3030290000Sglebius (char*)&on, sizeof(on))) 3031290000Sglebius msyslog(LOG_DEBUG, 3032290000Sglebius "setsockopt SO_BINTIME on fails on address %s: %m", 3033290000Sglebius stoa(addr)); 3034290000Sglebius else 3035290000Sglebius DPRINTF(4, ("setsockopt SO_BINTIME enabled on fd %d address %s\n", 3036290000Sglebius fd, stoa(addr))); 3037290000Sglebius } 3038290000Sglebius#endif 3039132451Sroberto 3040290000Sglebius DPRINTF(4, ("bind(%d) AF_INET%s, addr %s%%%d#%d, flags 0x%x\n", 3041290000Sglebius fd, IS_IPV6(addr) ? "6" : "", stoa(addr), 3042290000Sglebius SCOPE(addr), SRCPORT(addr), interf->flags)); 3043290000Sglebius 3044290000Sglebius make_socket_nonblocking(fd); 3045290000Sglebius 304654359Sroberto#ifdef HAVE_SIGNALED_IO 304754359Sroberto init_socket_sig(fd); 304854359Sroberto#endif /* not HAVE_SIGNALED_IO */ 304954359Sroberto 3050182007Sroberto add_fd_to_list(fd, FD_TYPE_SOCKET); 305154359Sroberto 305254359Sroberto#if !defined(SYS_WINNT) && !defined(VMS) 3053182007Sroberto DPRINTF(4, ("flags for fd %d: 0x%x\n", fd, 3054182007Sroberto fcntl(fd, F_GETFL, 0))); 305554359Sroberto#endif /* SYS_WINNT || VMS */ 305654359Sroberto 3057298770Sdelphij#if defined(HAVE_IO_COMPLETION_PORT) 305854359Sroberto/* 3059182007Sroberto * Add the socket to the completion port 306054359Sroberto */ 3061298770Sdelphij if (!io_completion_port_add_socket(fd, interf, bcast)) { 3062182007Sroberto msyslog(LOG_ERR, "unable to set up io completion port - EXITING"); 3063182007Sroberto exit(1); 306454359Sroberto } 3065132451Sroberto#endif 3066182007Sroberto return fd; 306754359Sroberto} 306854359Sroberto 3069290000Sglebius 3070290000Sglebius 307154359Sroberto/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 307254359Sroberto/* 307354359Sroberto * sendpkt - send a packet to the specified destination. Maintain a 307454359Sroberto * send error cache so that only the first consecutive error for a 307554359Sroberto * destination is logged. 307654359Sroberto */ 307754359Srobertovoid 307854359Srobertosendpkt( 3079290000Sglebius sockaddr_u * dest, 3080290000Sglebius struct interface * ep, 3081290000Sglebius int ttl, 3082290000Sglebius struct pkt * pkt, 3083290000Sglebius int len 308454359Sroberto ) 308554359Sroberto{ 3086290000Sglebius endpt * src; 3087290000Sglebius int ismcast; 3088290000Sglebius int cc; 3089290000Sglebius int rc; 3090290000Sglebius u_char cttl; 309154359Sroberto 3092290000Sglebius ismcast = IS_MCAST(dest); 3093290000Sglebius if (!ismcast) 3094290000Sglebius src = ep; 3095290000Sglebius else 3096290000Sglebius src = (IS_IPV4(dest)) 3097290000Sglebius ? mc4_list 3098290000Sglebius : mc6_list; 309954359Sroberto 3100290000Sglebius if (NULL == src) { 3101290000Sglebius /* 3102290000Sglebius * unbound peer - drop request and wait for better 3103290000Sglebius * network conditions 3104290000Sglebius */ 3105290000Sglebius DPRINTF(2, ("%ssendpkt(dst=%s, ttl=%d, len=%d): no interface - IGNORED\n", 3106290000Sglebius ismcast ? "\tMCAST\t***** " : "", 3107290000Sglebius stoa(dest), ttl, len)); 3108290000Sglebius return; 3109290000Sglebius } 3110132451Sroberto 3111290000Sglebius do { 3112290000Sglebius DPRINTF(2, ("%ssendpkt(%d, dst=%s, src=%s, ttl=%d, len=%d)\n", 3113290000Sglebius ismcast ? "\tMCAST\t***** " : "", src->fd, 3114290000Sglebius stoa(dest), stoa(&src->sin), ttl, len)); 311554359Sroberto#ifdef MCAST 311682498Sroberto /* 3117290000Sglebius * for the moment we use the bcast option to set multicast ttl 3118182007Sroberto */ 3119290000Sglebius if (ismcast && ttl > 0 && ttl != src->last_ttl) { 312054359Sroberto /* 3121290000Sglebius * set the multicast ttl for outgoing packets 312254359Sroberto */ 3123290000Sglebius switch (AF(&src->sin)) { 3124132451Sroberto 3125132451Sroberto case AF_INET : 3126290000Sglebius cttl = (u_char)ttl; 3127290000Sglebius rc = setsockopt(src->fd, IPPROTO_IP, 3128290000Sglebius IP_MULTICAST_TTL, 3129290000Sglebius (void *)&cttl, 3130290000Sglebius sizeof(cttl)); 3131132451Sroberto break; 3132132451Sroberto 3133290000Sglebius# ifdef INCLUDE_IPV6_SUPPORT 3134132451Sroberto case AF_INET6 : 3135290000Sglebius rc = setsockopt(src->fd, IPPROTO_IPV6, 3136290000Sglebius IPV6_MULTICAST_HOPS, 3137290000Sglebius (void *)&ttl, 3138290000Sglebius sizeof(ttl)); 3139290000Sglebius break; 3140290000Sglebius# endif /* INCLUDE_IPV6_SUPPORT */ 3141132451Sroberto 3142290000Sglebius default: 3143290000Sglebius rc = 0; 3144132451Sroberto } 3145132451Sroberto 3146290000Sglebius if (!rc) 3147290000Sglebius src->last_ttl = ttl; 3148290000Sglebius else 3149290000Sglebius msyslog(LOG_ERR, 3150290000Sglebius "setsockopt IP_MULTICAST_TTL/IPV6_MULTICAST_HOPS fails on address %s: %m", 3151290000Sglebius stoa(&src->sin)); 315254359Sroberto } 3153290000Sglebius#endif /* MCAST */ 3154290000Sglebius 3155290000Sglebius#ifdef SIM 3156290000Sglebius cc = simulate_server(dest, src, pkt); 3157298770Sdelphij#elif defined(HAVE_IO_COMPLETION_PORT) 3158298770Sdelphij cc = io_completion_port_sendto(src, src->fd, pkt, 3159298770Sdelphij (size_t)len, (sockaddr_u *)&dest->sa); 3160290000Sglebius#else 3161290000Sglebius cc = sendto(src->fd, (char *)pkt, (u_int)len, 0, 3162290000Sglebius &dest->sa, SOCKLEN(dest)); 3163290000Sglebius#endif 3164290000Sglebius if (cc == -1) { 3165290000Sglebius src->notsent++; 3166290000Sglebius packets_notsent++; 3167290000Sglebius } else { 3168290000Sglebius src->sent++; 3169290000Sglebius packets_sent++; 317054359Sroberto } 3171290000Sglebius if (ismcast) 3172290000Sglebius src = src->mclink; 3173290000Sglebius } while (ismcast && src != NULL); 317454359Sroberto} 317554359Sroberto 3176290000Sglebius 3177298770Sdelphij#if !defined(HAVE_IO_COMPLETION_PORT) 3178298770Sdelphij#if !defined(HAVE_SIGNALED_IO) 317954359Sroberto/* 318054359Sroberto * fdbits - generate ascii representation of fd_set (FAU debug support) 318154359Sroberto * HFDF format - highest fd first. 318254359Sroberto */ 318354359Srobertostatic char * 318454359Srobertofdbits( 3185294904Sdelphij int count, 3186294904Sdelphij const fd_set* set 318754359Sroberto ) 318854359Sroberto{ 318954359Sroberto static char buffer[256]; 319054359Sroberto char * buf = buffer; 319154359Sroberto 3192290000Sglebius count = min(count, 255); 319354359Sroberto 3194290000Sglebius while (count >= 0) { 319554359Sroberto *buf++ = FD_ISSET(count, set) ? '#' : '-'; 319654359Sroberto count--; 319754359Sroberto } 319854359Sroberto *buf = '\0'; 319954359Sroberto 320054359Sroberto return buffer; 320154359Sroberto} 3202294904Sdelphij#endif 320354359Sroberto 3204290000Sglebius#ifdef REFCLOCK 320554359Sroberto/* 3206182007Sroberto * Routine to read the refclock packets for a specific interface 3207182007Sroberto * Return the number of bytes read. That way we know if we should 3208182007Sroberto * read it again or go on to the next one if no bytes returned 320954359Sroberto */ 3210182007Srobertostatic inline int 3211290000Sglebiusread_refclock_packet( 3212290000Sglebius SOCKET fd, 3213290000Sglebius struct refclockio * rp, 3214290000Sglebius l_fp ts 3215290000Sglebius ) 321654359Sroberto{ 3217290000Sglebius u_int read_count; 3218290000Sglebius int buflen; 3219290000Sglebius int saved_errno; 3220290000Sglebius int consumed; 3221290000Sglebius struct recvbuf * rb; 322254359Sroberto 3223182007Sroberto rb = get_free_recv_buffer(); 322454359Sroberto 3225290000Sglebius if (NULL == rb) { 322654359Sroberto /* 3227182007Sroberto * No buffer space available - just drop the packet 322854359Sroberto */ 3229182007Sroberto char buf[RX_BUFF_SIZE]; 323054359Sroberto 3231182007Sroberto buflen = read(fd, buf, sizeof buf); 3232182007Sroberto packets_dropped++; 3233182007Sroberto return (buflen); 3234182007Sroberto } 323554359Sroberto 3236290000Sglebius /* TALOS-CAN-0064: avoid signed/unsigned clashes that can lead 3237290000Sglebius * to buffer overrun and memory corruption 3238290000Sglebius */ 3239294904Sdelphij if (rp->datalen <= 0 || (size_t)rp->datalen > sizeof(rb->recv_space)) 3240290000Sglebius read_count = sizeof(rb->recv_space); 3241290000Sglebius else 3242290000Sglebius read_count = (u_int)rp->datalen; 3243290000Sglebius do { 3244290000Sglebius buflen = read(fd, (char *)&rb->recv_space, read_count); 3245290000Sglebius } while (buflen < 0 && EINTR == errno); 3246182007Sroberto 3247290000Sglebius if (buflen <= 0) { 3248290000Sglebius saved_errno = errno; 3249182007Sroberto freerecvbuf(rb); 3250290000Sglebius errno = saved_errno; 3251290000Sglebius return buflen; 3252182007Sroberto } 3253182007Sroberto 3254182007Sroberto /* 3255182007Sroberto * Got one. Mark how and when it got here, 3256182007Sroberto * put it on the full list and do bookkeeping. 3257182007Sroberto */ 3258182007Sroberto rb->recv_length = buflen; 3259290000Sglebius rb->recv_peer = rp->srcclock; 3260182007Sroberto rb->dstadr = 0; 3261182007Sroberto rb->fd = fd; 3262182007Sroberto rb->recv_time = ts; 3263182007Sroberto rb->receiver = rp->clock_recv; 3264182007Sroberto 3265290000Sglebius consumed = indicate_refclock_packet(rp, rb); 3266290000Sglebius if (!consumed) { 3267290000Sglebius rp->recvcount++; 3268290000Sglebius packets_received++; 3269182007Sroberto } 327054359Sroberto 3271290000Sglebius return buflen; 3272182007Sroberto} 3273290000Sglebius#endif /* REFCLOCK */ 327454359Sroberto 3275290000Sglebius 3276290000Sglebius#ifdef HAVE_PACKET_TIMESTAMP 3277182007Sroberto/* 3278182007Sroberto * extract timestamps from control message buffer 3279182007Sroberto */ 3280182007Srobertostatic l_fp 3281290000Sglebiusfetch_timestamp( 3282290000Sglebius struct recvbuf * rb, 3283290000Sglebius struct msghdr * msghdr, 3284290000Sglebius l_fp ts 3285290000Sglebius ) 3286182007Sroberto{ 3287290000Sglebius struct cmsghdr * cmsghdr; 3288290000Sglebius unsigned long ticks; 3289290000Sglebius double fuzz; 3290290000Sglebius l_fp lfpfuzz; 3291290000Sglebius l_fp nts; 3292290000Sglebius#ifdef DEBUG_TIMING 3293290000Sglebius l_fp dts; 3294290000Sglebius#endif 329554359Sroberto 3296182007Sroberto cmsghdr = CMSG_FIRSTHDR(msghdr); 3297182007Sroberto while (cmsghdr != NULL) { 3298182007Sroberto switch (cmsghdr->cmsg_type) 3299182007Sroberto { 3300290000Sglebius#ifdef HAVE_BINTIME 3301290000Sglebius case SCM_BINTIME: 3302290000Sglebius#endif /* HAVE_BINTIME */ 3303290000Sglebius#ifdef HAVE_TIMESTAMPNS 3304290000Sglebius case SCM_TIMESTAMPNS: 3305290000Sglebius#endif /* HAVE_TIMESTAMPNS */ 3306290000Sglebius#ifdef HAVE_TIMESTAMP 3307182007Sroberto case SCM_TIMESTAMP: 3308290000Sglebius#endif /* HAVE_TIMESTAMP */ 3309290000Sglebius#if defined(HAVE_BINTIME) || defined (HAVE_TIMESTAMPNS) || defined(HAVE_TIMESTAMP) 3310290000Sglebius switch (cmsghdr->cmsg_type) 3311182007Sroberto { 3312290000Sglebius#ifdef HAVE_BINTIME 3313290000Sglebius case SCM_BINTIME: 3314301301Sdelphij { 3315301301Sdelphij struct bintime pbt; 3316301301Sdelphij memcpy(&pbt, CMSG_DATA(cmsghdr), sizeof(pbt)); 3317301301Sdelphij /* 3318301301Sdelphij * bintime documentation is at http://phk.freebsd.dk/pubs/timecounter.pdf 3319301301Sdelphij */ 3320301301Sdelphij nts.l_i = pbt.sec + JAN_1970; 3321301301Sdelphij nts.l_uf = (u_int32)(pbt.frac >> 32); 3322301301Sdelphij if (sys_tick > measured_tick && 3323301301Sdelphij sys_tick > 1e-9) { 3324301301Sdelphij ticks = (unsigned long)(nts.l_uf / (unsigned long)(sys_tick * FRAC)); 3325301301Sdelphij nts.l_uf = (unsigned long)(ticks * (unsigned long)(sys_tick * FRAC)); 3326301301Sdelphij } 3327301301Sdelphij DPRINTF(4, ("fetch_timestamp: system bintime network time stamp: %ld.%09lu\n", 3328301301Sdelphij pbt.sec, (unsigned long)((nts.l_uf / FRAC) * 1e9))); 3329290000Sglebius } 3330290000Sglebius break; 3331290000Sglebius#endif /* HAVE_BINTIME */ 3332290000Sglebius#ifdef HAVE_TIMESTAMPNS 3333290000Sglebius case SCM_TIMESTAMPNS: 3334301301Sdelphij { 3335301301Sdelphij struct timespec pts; 3336301301Sdelphij memcpy(&pts, CMSG_DATA(cmsghdr), sizeof(pts)); 3337301301Sdelphij if (sys_tick > measured_tick && 3338301301Sdelphij sys_tick > 1e-9) { 3339301301Sdelphij ticks = (unsigned long)((pts.tv_nsec * 1e-9) / 3340301301Sdelphij sys_tick); 3341301301Sdelphij pts.tv_nsec = (long)(ticks * 1e9 * 3342301301Sdelphij sys_tick); 3343301301Sdelphij } 3344301301Sdelphij DPRINTF(4, ("fetch_timestamp: system nsec network time stamp: %ld.%09ld\n", 3345301301Sdelphij pts.tv_sec, pts.tv_nsec)); 3346301301Sdelphij nts = tspec_stamp_to_lfp(pts); 3347290000Sglebius } 3348290000Sglebius break; 3349290000Sglebius#endif /* HAVE_TIMESTAMPNS */ 3350290000Sglebius#ifdef HAVE_TIMESTAMP 3351290000Sglebius case SCM_TIMESTAMP: 3352301301Sdelphij { 3353301301Sdelphij struct timeval ptv; 3354301301Sdelphij memcpy(&ptv, CMSG_DATA(cmsghdr), sizeof(ptv)); 3355301301Sdelphij if (sys_tick > measured_tick && 3356301301Sdelphij sys_tick > 1e-6) { 3357301301Sdelphij ticks = (unsigned long)((ptv.tv_usec * 1e-6) / 3358301301Sdelphij sys_tick); 3359301301Sdelphij ptv.tv_usec = (long)(ticks * 1e6 * 3360301301Sdelphij sys_tick); 3361301301Sdelphij } 3362301301Sdelphij DPRINTF(4, ("fetch_timestamp: system usec network time stamp: %jd.%06ld\n", 3363301301Sdelphij (intmax_t)ptv.tv_sec, (long)ptv.tv_usec)); 3364301301Sdelphij nts = tval_stamp_to_lfp(ptv); 3365290000Sglebius } 3366290000Sglebius break; 3367290000Sglebius#endif /* HAVE_TIMESTAMP */ 3368182007Sroberto } 3369290000Sglebius fuzz = ntp_random() * 2. / FRAC * sys_fuzz; 3370290000Sglebius DTOLFP(fuzz, &lfpfuzz); 3371290000Sglebius L_ADD(&nts, &lfpfuzz); 3372290000Sglebius#ifdef DEBUG_TIMING 3373290000Sglebius dts = ts; 3374290000Sglebius L_SUB(&dts, &nts); 3375290000Sglebius collect_timing(rb, "input processing delay", 1, 3376290000Sglebius &dts); 3377290000Sglebius DPRINTF(4, ("fetch_timestamp: timestamp delta: %s (incl. fuzz)\n", 3378290000Sglebius lfptoa(&dts, 9))); 3379290000Sglebius#endif /* DEBUG_TIMING */ 3380182007Sroberto ts = nts; /* network time stamp */ 3381182007Sroberto break; 3382290000Sglebius#endif /* HAVE_BINTIME || HAVE_TIMESTAMPNS || HAVE_TIMESTAMP */ 3383290000Sglebius 3384182007Sroberto default: 3385290000Sglebius DPRINTF(4, ("fetch_timestamp: skipping control message 0x%x\n", 3386290000Sglebius cmsghdr->cmsg_type)); 3387182007Sroberto } 3388182007Sroberto cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr); 3389182007Sroberto } 3390182007Sroberto return ts; 3391182007Sroberto} 3392290000Sglebius#endif /* HAVE_PACKET_TIMESTAMP */ 339354359Sroberto 3394290000Sglebius 3395182007Sroberto/* 3396182007Sroberto * Routine to read the network NTP packets for a specific interface 3397182007Sroberto * Return the number of bytes read. That way we know if we should 3398182007Sroberto * read it again or go on to the next one if no bytes returned 3399182007Sroberto */ 3400182007Srobertostatic inline int 3401290000Sglebiusread_network_packet( 3402290000Sglebius SOCKET fd, 3403290000Sglebius struct interface * itf, 3404290000Sglebius l_fp ts 3405290000Sglebius ) 3406182007Sroberto{ 3407182007Sroberto GETSOCKNAME_SOCKLEN_TYPE fromlen; 3408182007Sroberto int buflen; 3409182007Sroberto register struct recvbuf *rb; 3410290000Sglebius#ifdef HAVE_PACKET_TIMESTAMP 3411182007Sroberto struct msghdr msghdr; 3412182007Sroberto struct iovec iovec; 3413290000Sglebius char control[CMSG_BUFSIZE]; 341454359Sroberto#endif 341554359Sroberto 3416182007Sroberto /* 3417182007Sroberto * Get a buffer and read the frame. If we 3418182007Sroberto * haven't got a buffer, or this is received 3419182007Sroberto * on a disallowed socket, just dump the 3420182007Sroberto * packet. 3421182007Sroberto */ 342254359Sroberto 3423182007Sroberto rb = get_free_recv_buffer(); 3424290000Sglebius if (NULL == rb || itf->ignore_packets) { 3425290000Sglebius char buf[RX_BUFF_SIZE]; 3426290000Sglebius sockaddr_u from; 342754359Sroberto 3428182007Sroberto if (rb != NULL) 3429182007Sroberto freerecvbuf(rb); 343054359Sroberto 3431182007Sroberto fromlen = sizeof(from); 3432182007Sroberto buflen = recvfrom(fd, buf, sizeof(buf), 0, 3433290000Sglebius &from.sa, &fromlen); 3434182007Sroberto DPRINTF(4, ("%s on (%lu) fd=%d from %s\n", 3435290000Sglebius (itf->ignore_packets) 3436290000Sglebius ? "ignore" 3437290000Sglebius : "drop", 3438290000Sglebius free_recvbuffs(), fd, stoa(&from))); 3439290000Sglebius if (itf->ignore_packets) 3440182007Sroberto packets_ignored++; 344154359Sroberto else 3442182007Sroberto packets_dropped++; 3443182007Sroberto return (buflen); 344454359Sroberto } 344554359Sroberto 3446290000Sglebius fromlen = sizeof(rb->recv_srcadr); 344754359Sroberto 3448290000Sglebius#ifndef HAVE_PACKET_TIMESTAMP 3449290000Sglebius rb->recv_length = recvfrom(fd, (char *)&rb->recv_space, 3450290000Sglebius sizeof(rb->recv_space), 0, 3451290000Sglebius &rb->recv_srcadr.sa, &fromlen); 3452182007Sroberto#else 3453290000Sglebius iovec.iov_base = &rb->recv_space; 3454182007Sroberto iovec.iov_len = sizeof(rb->recv_space); 3455290000Sglebius msghdr.msg_name = &rb->recv_srcadr; 3456290000Sglebius msghdr.msg_namelen = fromlen; 3457182007Sroberto msghdr.msg_iov = &iovec; 3458182007Sroberto msghdr.msg_iovlen = 1; 3459182007Sroberto msghdr.msg_control = (void *)&control; 3460182007Sroberto msghdr.msg_controllen = sizeof(control); 3461182007Sroberto msghdr.msg_flags = 0; 3462182007Sroberto rb->recv_length = recvmsg(fd, &msghdr, 0); 346354359Sroberto#endif 3464182007Sroberto 3465182007Sroberto buflen = rb->recv_length; 3466182007Sroberto 3467290000Sglebius if (buflen == 0 || (buflen == -1 && 3468290000Sglebius (EWOULDBLOCK == errno 346954359Sroberto#ifdef EAGAIN 3470290000Sglebius || EAGAIN == errno 347154359Sroberto#endif 3472290000Sglebius ))) { 347354359Sroberto freerecvbuf(rb); 3474182007Sroberto return (buflen); 3475290000Sglebius } else if (buflen < 0) { 3476290000Sglebius msyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m", 3477290000Sglebius stoa(&rb->recv_srcadr), fd); 3478290000Sglebius DPRINTF(5, ("read_network_packet: fd=%d dropped (bad recvfrom)\n", 3479290000Sglebius fd)); 348054359Sroberto freerecvbuf(rb); 3481182007Sroberto return (buflen); 348254359Sroberto } 3483182007Sroberto 3484290000Sglebius DPRINTF(3, ("read_network_packet: fd=%d length %d from %s\n", 3485290000Sglebius fd, buflen, stoa(&rb->recv_srcadr))); 3486290000Sglebius 3487298770Sdelphij#ifdef ENABLE_BUG3020_FIX 3488298770Sdelphij if (ISREFCLOCKADR(&rb->recv_srcadr)) { 3489298770Sdelphij msyslog(LOG_ERR, "recvfrom(%s) fd=%d: refclock srcadr on a network interface!", 3490298770Sdelphij stoa(&rb->recv_srcadr), fd); 3491298770Sdelphij DPRINTF(1, ("read_network_packet: fd=%d dropped (refclock srcadr))\n", 3492298770Sdelphij fd)); 3493298770Sdelphij packets_dropped++; 3494298770Sdelphij freerecvbuf(rb); 3495298770Sdelphij return (buflen); 3496298770Sdelphij } 3497298770Sdelphij#endif 3498298770Sdelphij 3499290000Sglebius /* 3500290000Sglebius ** Bug 2672: Some OSes (MacOSX and Linux) don't block spoofed ::1 3501290000Sglebius */ 3502290000Sglebius 3503290000Sglebius if (AF_INET6 == itf->family) { 3504290000Sglebius DPRINTF(2, ("Got an IPv6 packet, from <%s> (%d) to <%s> (%d)\n", 3505290000Sglebius stoa(&rb->recv_srcadr), 3506290000Sglebius IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&rb->recv_srcadr)), 3507290000Sglebius stoa(&itf->sin), 3508290000Sglebius !IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&itf->sin)) 3509290000Sglebius )); 3510290000Sglebius 3511290000Sglebius if ( IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&rb->recv_srcadr)) 3512290000Sglebius && !IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&itf->sin)) 3513290000Sglebius ) { 3514290000Sglebius packets_dropped++; 3515290000Sglebius DPRINTF(2, ("DROPPING that packet\n")); 3516290000Sglebius freerecvbuf(rb); 3517290000Sglebius return buflen; 3518290000Sglebius } 3519290000Sglebius DPRINTF(2, ("processing that packet\n")); 3520182007Sroberto } 352154359Sroberto 352254359Sroberto /* 352354359Sroberto * Got one. Mark how and when it got here, 352454359Sroberto * put it on the full list and do bookkeeping. 352554359Sroberto */ 3526182007Sroberto rb->dstadr = itf; 352754359Sroberto rb->fd = fd; 3528290000Sglebius#ifdef HAVE_PACKET_TIMESTAMP 3529290000Sglebius /* pick up a network time stamp if possible */ 3530290000Sglebius ts = fetch_timestamp(rb, &msghdr, ts); 3531182007Sroberto#endif 353254359Sroberto rb->recv_time = ts; 353354359Sroberto rb->receiver = receive; 353454359Sroberto 353554359Sroberto add_full_recv_buffer(rb); 3536132451Sroberto 3537182007Sroberto itf->received++; 353854359Sroberto packets_received++; 3539182007Sroberto return (buflen); 3540182007Sroberto} 354154359Sroberto 3542182007Sroberto/* 3543290000Sglebius * attempt to handle io (select()/signaled IO) 3544290000Sglebius */ 3545290000Sglebiusvoid 3546290000Sglebiusio_handler(void) 3547290000Sglebius{ 3548290000Sglebius# ifndef HAVE_SIGNALED_IO 3549290000Sglebius fd_set rdfdes; 3550290000Sglebius int nfound; 3551290000Sglebius 3552290000Sglebius /* 3553290000Sglebius * Use select() on all on all input fd's for unlimited 3554290000Sglebius * time. select() will terminate on SIGALARM or on the 3555290000Sglebius * reception of input. Using select() means we can't do 3556290000Sglebius * robust signal handling and we get a potential race 3557290000Sglebius * between checking for alarms and doing the select(). 3558290000Sglebius * Mostly harmless, I think. 3559290000Sglebius */ 3560290000Sglebius /* 3561290000Sglebius * On VMS, I suspect that select() can't be interrupted 3562290000Sglebius * by a "signal" either, so I take the easy way out and 3563290000Sglebius * have select() time out after one second. 3564290000Sglebius * System clock updates really aren't time-critical, 3565290000Sglebius * and - lacking a hardware reference clock - I have 3566290000Sglebius * yet to learn about anything else that is. 3567290000Sglebius */ 3568294904Sdelphij ++handler_calls; 3569290000Sglebius rdfdes = activefds; 3570290000Sglebius# if !defined(VMS) && !defined(SYS_VXWORKS) 3571290000Sglebius nfound = select(maxactivefd + 1, &rdfdes, NULL, 3572290000Sglebius NULL, NULL); 3573290000Sglebius# else /* VMS, VxWorks */ 3574290000Sglebius /* make select() wake up after one second */ 3575290000Sglebius { 3576290000Sglebius struct timeval t1; 3577294904Sdelphij t1.tv_sec = 1; 3578290000Sglebius t1.tv_usec = 0; 3579290000Sglebius nfound = select(maxactivefd + 1, 3580290000Sglebius &rdfdes, NULL, NULL, 3581290000Sglebius &t1); 3582290000Sglebius } 3583290000Sglebius# endif /* VMS, VxWorks */ 3584294904Sdelphij if (nfound < 0 && sanitize_fdset(errno)) { 3585294904Sdelphij struct timeval t1; 3586294904Sdelphij t1.tv_sec = 0; 3587294904Sdelphij t1.tv_usec = 0; 3588294904Sdelphij rdfdes = activefds; 3589294904Sdelphij nfound = select(maxactivefd + 1, 3590294904Sdelphij &rdfdes, NULL, NULL, 3591294904Sdelphij &t1); 3592294904Sdelphij } 3593294904Sdelphij 3594290000Sglebius if (nfound > 0) { 3595290000Sglebius l_fp ts; 3596290000Sglebius 3597290000Sglebius get_systime(&ts); 3598290000Sglebius 3599294904Sdelphij input_handler_scan(&ts, &rdfdes); 3600290000Sglebius } else if (nfound == -1 && errno != EINTR) { 3601290000Sglebius msyslog(LOG_ERR, "select() error: %m"); 3602290000Sglebius } 3603290000Sglebius# ifdef DEBUG 3604290000Sglebius else if (debug > 4) { 3605290000Sglebius msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound); 3606290000Sglebius } else { 3607290000Sglebius DPRINTF(3, ("select() returned %d: %m\n", nfound)); 3608290000Sglebius } 3609290000Sglebius# endif /* DEBUG */ 3610290000Sglebius# else /* HAVE_SIGNALED_IO */ 3611290000Sglebius wait_for_signal(); 3612290000Sglebius# endif /* HAVE_SIGNALED_IO */ 3613290000Sglebius} 3614290000Sglebius 3615294904Sdelphij#ifdef HAVE_SIGNALED_IO 3616290000Sglebius/* 3617182007Sroberto * input_handler - receive packets asynchronously 3618294904Sdelphij * 3619294904Sdelphij * ALWAYS IN SIGNAL HANDLER CONTEXT -- only async-safe functions allowed! 3620182007Sroberto */ 3621294904Sdelphijstatic RETSIGTYPE 3622182007Srobertoinput_handler( 3623290000Sglebius l_fp * cts 3624182007Sroberto ) 3625182007Sroberto{ 3626294904Sdelphij int n; 3627294904Sdelphij struct timeval tvzero; 3628294904Sdelphij fd_set fds; 3629294904Sdelphij 3630294904Sdelphij ++handler_calls; 3631294904Sdelphij 3632294904Sdelphij /* 3633294904Sdelphij * Do a poll to see who has data 3634294904Sdelphij */ 3635294904Sdelphij 3636294904Sdelphij fds = activefds; 3637294904Sdelphij tvzero.tv_sec = tvzero.tv_usec = 0; 3638294904Sdelphij 3639294904Sdelphij n = select(maxactivefd + 1, &fds, NULL, NULL, &tvzero); 3640294904Sdelphij if (n < 0 && sanitize_fdset(errno)) { 3641294904Sdelphij fds = activefds; 3642294904Sdelphij tvzero.tv_sec = tvzero.tv_usec = 0; 3643294904Sdelphij n = select(maxactivefd + 1, &fds, NULL, NULL, &tvzero); 3644294904Sdelphij } 3645294904Sdelphij if (n > 0) 3646294904Sdelphij input_handler_scan(cts, &fds); 3647294904Sdelphij} 3648294904Sdelphij#endif /* HAVE_SIGNALED_IO */ 3649294904Sdelphij 3650294904Sdelphij 3651294904Sdelphij/* 3652294904Sdelphij * Try to sanitize the global FD set 3653294904Sdelphij * 3654294904Sdelphij * SIGNAL HANDLER CONTEXT if HAVE_SIGNALED_IO, ordinary userspace otherwise 3655294904Sdelphij */ 3656294904Sdelphijstatic int/*BOOL*/ 3657294904Sdelphijsanitize_fdset( 3658294904Sdelphij int errc 3659294904Sdelphij ) 3660294904Sdelphij{ 3661294904Sdelphij int j, b, maxscan; 3662294904Sdelphij 3663294904Sdelphij# ifndef HAVE_SIGNALED_IO 3664294904Sdelphij /* 3665294904Sdelphij * extended FAU debugging output 3666294904Sdelphij */ 3667294904Sdelphij if (errc != EINTR) { 3668294904Sdelphij msyslog(LOG_ERR, 3669294904Sdelphij "select(%d, %s, 0L, 0L, &0.0) error: %m", 3670294904Sdelphij maxactivefd + 1, 3671294904Sdelphij fdbits(maxactivefd, &activefds)); 3672294904Sdelphij } 3673294904Sdelphij# endif 3674294904Sdelphij 3675294904Sdelphij if (errc != EBADF) 3676294904Sdelphij return FALSE; 3677294904Sdelphij 3678294904Sdelphij /* if we have oviously bad FDs, try to sanitize the FD set. */ 3679294904Sdelphij for (j = 0, maxscan = 0; j <= maxactivefd; j++) { 3680294904Sdelphij if (FD_ISSET(j, &activefds)) { 3681294904Sdelphij if (-1 != read(j, &b, 0)) { 3682294904Sdelphij maxscan = j; 3683294904Sdelphij continue; 3684294904Sdelphij } 3685294904Sdelphij# ifndef HAVE_SIGNALED_IO 3686294904Sdelphij msyslog(LOG_ERR, 3687294904Sdelphij "Removing bad file descriptor %d from select set", 3688294904Sdelphij j); 3689294904Sdelphij# endif 3690294904Sdelphij FD_CLR(j, &activefds); 3691294904Sdelphij } 3692294904Sdelphij } 3693294904Sdelphij if (maxactivefd != maxscan) 3694294904Sdelphij maxactivefd = maxscan; 3695294904Sdelphij return TRUE; 3696294904Sdelphij} 3697294904Sdelphij 3698294904Sdelphij/* 3699294904Sdelphij * scan the known FDs (clocks, servers, ...) for presence in a 'fd_set'. 3700294904Sdelphij * 3701294904Sdelphij * SIGNAL HANDLER CONTEXT if HAVE_SIGNALED_IO, ordinary userspace otherwise 3702294904Sdelphij */ 3703294904Sdelphijstatic void 3704294904Sdelphijinput_handler_scan( 3705294904Sdelphij const l_fp * cts, 3706294904Sdelphij const fd_set * pfds 3707294904Sdelphij ) 3708294904Sdelphij{ 3709290000Sglebius int buflen; 3710290000Sglebius u_int idx; 3711290000Sglebius int doing; 3712290000Sglebius SOCKET fd; 3713290000Sglebius blocking_child *c; 3714290000Sglebius l_fp ts; /* Timestamp at BOselect() gob */ 3715294904Sdelphij 3716294904Sdelphij#if defined(DEBUG_TIMING) 3717290000Sglebius l_fp ts_e; /* Timestamp at EOselect() gob */ 3718182007Sroberto#endif 3719290000Sglebius endpt * ep; 3720290000Sglebius#ifdef REFCLOCK 3721290000Sglebius struct refclockio *rp; 3722290000Sglebius int saved_errno; 3723290000Sglebius const char * clk; 3724182007Sroberto#endif 3725290000Sglebius#ifdef HAS_ROUTING_SOCKET 3726290000Sglebius struct asyncio_reader * asyncio_reader; 3727290000Sglebius struct asyncio_reader * next_asyncio_reader; 3728290000Sglebius#endif 3729182007Sroberto 3730294904Sdelphij ++handler_pkts; 3731182007Sroberto ts = *cts; 3732182007Sroberto 3733294904Sdelphij#ifdef REFCLOCK 3734182007Sroberto /* 3735294904Sdelphij * Check out the reference clocks first, if any 3736182007Sroberto */ 3737294904Sdelphij 3738294904Sdelphij for (rp = refio; rp != NULL; rp = rp->next) { 3739294904Sdelphij fd = rp->fd; 3740294904Sdelphij 3741294904Sdelphij if (!FD_ISSET(fd, pfds)) 3742294904Sdelphij continue; 3743294904Sdelphij buflen = read_refclock_packet(fd, rp, ts); 374454359Sroberto /* 3745294904Sdelphij * The first read must succeed after select() indicates 3746294904Sdelphij * readability, or we've reached a permanent EOF. 3747294904Sdelphij * http://bugs.ntp.org/1732 reported ntpd munching CPU 3748294904Sdelphij * after a USB GPS was unplugged because select was 3749294904Sdelphij * indicating EOF but ntpd didn't remove the descriptor 3750294904Sdelphij * from the activefds set. 375154359Sroberto */ 3752294904Sdelphij if (buflen < 0 && EAGAIN != errno) { 3753294904Sdelphij saved_errno = errno; 3754294904Sdelphij clk = refnumtoa(&rp->srcclock->srcadr); 3755294904Sdelphij errno = saved_errno; 3756294904Sdelphij msyslog(LOG_ERR, "%s read: %m", clk); 3757294904Sdelphij maintain_activefds(fd, TRUE); 3758294904Sdelphij } else if (0 == buflen) { 3759294904Sdelphij clk = refnumtoa(&rp->srcclock->srcadr); 3760294904Sdelphij msyslog(LOG_ERR, "%s read EOF", clk); 3761294904Sdelphij maintain_activefds(fd, TRUE); 3762294904Sdelphij } else { 3763294904Sdelphij /* drain any remaining refclock input */ 3764294904Sdelphij do { 3765294904Sdelphij buflen = read_refclock_packet(fd, rp, ts); 3766294904Sdelphij } while (buflen > 0); 3767182007Sroberto } 3768182007Sroberto } 3769182007Sroberto#endif /* REFCLOCK */ 377054359Sroberto 3771182007Sroberto /* 3772182007Sroberto * Loop through the interfaces looking for data to read. 3773182007Sroberto */ 3774290000Sglebius for (ep = ep_list; ep != NULL; ep = ep->elink) { 3775290000Sglebius for (doing = 0; doing < 2; doing++) { 3776290000Sglebius if (!doing) { 3777290000Sglebius fd = ep->fd; 3778290000Sglebius } else { 3779290000Sglebius if (!(ep->flags & INT_BCASTOPEN)) 3780290000Sglebius break; 3781290000Sglebius fd = ep->bfd; 378254359Sroberto } 3783290000Sglebius if (fd < 0) 3784290000Sglebius continue; 3785294904Sdelphij if (FD_ISSET(fd, pfds)) 3786182007Sroberto do { 3787290000Sglebius buflen = read_network_packet( 3788290000Sglebius fd, ep, ts); 3789182007Sroberto } while (buflen > 0); 3790290000Sglebius /* Check more interfaces */ 379154359Sroberto } 379254359Sroberto } 3793182007Sroberto 3794182007Sroberto#ifdef HAS_ROUTING_SOCKET 3795182007Sroberto /* 3796182007Sroberto * scan list of asyncio readers - currently only used for routing sockets 3797182007Sroberto */ 3798290000Sglebius asyncio_reader = asyncio_reader_list; 3799182007Sroberto 3800290000Sglebius while (asyncio_reader != NULL) { 3801290000Sglebius /* callback may unlink and free asyncio_reader */ 3802290000Sglebius next_asyncio_reader = asyncio_reader->link; 3803294904Sdelphij if (FD_ISSET(asyncio_reader->fd, pfds)) 3804290000Sglebius (*asyncio_reader->receiver)(asyncio_reader); 3805290000Sglebius asyncio_reader = next_asyncio_reader; 3806182007Sroberto } 3807182007Sroberto#endif /* HAS_ROUTING_SOCKET */ 3808290000Sglebius 3809182007Sroberto /* 3810290000Sglebius * Check for a response from a blocking child 3811182007Sroberto */ 3812290000Sglebius for (idx = 0; idx < blocking_children_alloc; idx++) { 3813290000Sglebius c = blocking_children[idx]; 3814290000Sglebius if (NULL == c || -1 == c->resp_read_pipe) 3815290000Sglebius continue; 3816294904Sdelphij if (FD_ISSET(c->resp_read_pipe, pfds)) { 3817294904Sdelphij ++c->resp_ready_seen; 3818294904Sdelphij ++blocking_child_ready_seen; 3819290000Sglebius } 3820290000Sglebius } 3821182007Sroberto 3822290000Sglebius /* We've done our work */ 3823294904Sdelphij#if defined(DEBUG_TIMING) 3824182007Sroberto get_systime(&ts_e); 3825182007Sroberto /* 3826182007Sroberto * (ts_e - ts) is the amount of time we spent 3827182007Sroberto * processing this gob of file descriptors. Log 3828182007Sroberto * it. 3829182007Sroberto */ 3830182007Sroberto L_SUB(&ts_e, &ts); 3831182007Sroberto collect_timing(NULL, "input handler", 1, &ts_e); 3832182007Sroberto if (debug > 3) 3833290000Sglebius msyslog(LOG_DEBUG, 3834290000Sglebius "input_handler: Processed a gob of fd's in %s msec", 3835290000Sglebius lfptoms(&ts_e, 6)); 3836290000Sglebius#endif /* DEBUG_TIMING */ 383754359Sroberto} 3838298770Sdelphij#endif /* !HAVE_IO_COMPLETION_PORT */ 383954359Sroberto 3840290000Sglebius/* 3841290000Sglebius * find an interface suitable for the src address 3842290000Sglebius */ 3843290000Sglebiusendpt * 3844290000Sglebiusselect_peerinterface( 3845290000Sglebius struct peer * peer, 3846290000Sglebius sockaddr_u * srcadr, 3847290000Sglebius endpt * dstadr 3848290000Sglebius ) 3849290000Sglebius{ 3850290000Sglebius endpt *ep; 3851290000Sglebius#ifndef SIM 3852290000Sglebius endpt *wild; 3853290000Sglebius 3854290000Sglebius wild = ANY_INTERFACE_CHOOSE(srcadr); 3855290000Sglebius 3856290000Sglebius /* 3857290000Sglebius * Initialize the peer structure and dance the interface jig. 3858290000Sglebius * Reference clocks step the loopback waltz, the others 3859290000Sglebius * squaredance around the interface list looking for a buddy. If 3860290000Sglebius * the dance peters out, there is always the wildcard interface. 3861290000Sglebius * This might happen in some systems and would preclude proper 3862290000Sglebius * operation with public key cryptography. 3863290000Sglebius */ 3864290000Sglebius if (ISREFCLOCKADR(srcadr)) { 3865290000Sglebius ep = loopback_interface; 3866290000Sglebius } else if (peer->cast_flags & 3867290000Sglebius (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) { 3868290000Sglebius ep = findbcastinter(srcadr); 3869290000Sglebius if (ep != NULL) 3870290000Sglebius DPRINTF(4, ("Found *-cast interface %s for address %s\n", 3871290000Sglebius stoa(&ep->sin), stoa(srcadr))); 3872290000Sglebius else 3873290000Sglebius DPRINTF(4, ("No *-cast local address found for address %s\n", 3874290000Sglebius stoa(srcadr))); 3875290000Sglebius } else { 3876290000Sglebius ep = dstadr; 3877290000Sglebius if (NULL == ep) 3878290000Sglebius ep = wild; 3879290000Sglebius } 3880290000Sglebius /* 3881290000Sglebius * If it is a multicast address, findbcastinter() may not find 3882290000Sglebius * it. For unicast, we get to find the interface when dstadr is 3883290000Sglebius * given to us as the wildcard (ANY_INTERFACE_CHOOSE). Either 3884290000Sglebius * way, try a little harder. 3885290000Sglebius */ 3886290000Sglebius if (wild == ep) 3887290000Sglebius ep = findinterface(srcadr); 3888290000Sglebius /* 3889290000Sglebius * we do not bind to the wildcard interfaces for output 3890290000Sglebius * as our (network) source address would be undefined and 3891290000Sglebius * crypto will not work without knowing the own transmit address 3892290000Sglebius */ 3893290000Sglebius if (ep != NULL && INT_WILDCARD & ep->flags) 3894290000Sglebius if (!accept_wildcard_if_for_winnt) 3895290000Sglebius ep = NULL; 3896290000Sglebius#else /* SIM follows */ 3897290000Sglebius ep = loopback_interface; 389854359Sroberto#endif 3899182007Sroberto 3900290000Sglebius return ep; 3901290000Sglebius} 3902290000Sglebius 3903290000Sglebius 390454359Sroberto/* 3905182007Sroberto * findinterface - find local interface corresponding to address 390654359Sroberto */ 3907290000Sglebiusendpt * 390854359Srobertofindinterface( 3909290000Sglebius sockaddr_u *addr 391054359Sroberto ) 391154359Sroberto{ 3912290000Sglebius endpt *iface; 3913182007Sroberto 3914290000Sglebius iface = findlocalinterface(addr, INT_WILDCARD, 0); 3915290000Sglebius 3916290000Sglebius if (NULL == iface) { 3917182007Sroberto DPRINTF(4, ("Found no interface for address %s - returning wildcard\n", 3918182007Sroberto stoa(addr))); 3919182007Sroberto 3920290000Sglebius iface = ANY_INTERFACE_CHOOSE(addr); 3921290000Sglebius } else 3922182007Sroberto DPRINTF(4, ("Found interface #%d %s for address %s\n", 3923290000Sglebius iface->ifnum, iface->name, stoa(addr))); 3924182007Sroberto 3925290000Sglebius return iface; 3926182007Sroberto} 3927182007Sroberto 3928182007Sroberto/* 3929290000Sglebius * findlocalinterface - find local interface corresponding to addr, 3930290000Sglebius * which does not have any of flags set. If bast is nonzero, addr is 3931290000Sglebius * a broadcast address. 3932182007Sroberto * 3933182007Sroberto * This code attempts to find the local sending address for an outgoing 3934182007Sroberto * address by connecting a new socket to destinationaddress:NTP_PORT 3935182007Sroberto * and reading the sockname of the resulting connect. 3936182007Sroberto * the complicated sequence simulates the routing table lookup 3937182007Sroberto * for to first hop without duplicating any of the routing logic into 3938182007Sroberto * ntpd. preferably we would have used an API call - but its not there - 3939182007Sroberto * so this is the best we can do here short of duplicating to entire routing 3940182007Sroberto * logic in ntpd which would be a silly and really unportable thing to do. 3941182007Sroberto * 3942182007Sroberto */ 3943290000Sglebiusstatic endpt * 3944182007Srobertofindlocalinterface( 3945290000Sglebius sockaddr_u * addr, 3946290000Sglebius int flags, 3947290000Sglebius int bcast 3948182007Sroberto ) 3949182007Sroberto{ 3950290000Sglebius GETSOCKNAME_SOCKLEN_TYPE sockaddrlen; 3951290000Sglebius endpt * iface; 3952290000Sglebius sockaddr_u saddr; 3953290000Sglebius SOCKET s; 3954290000Sglebius int rtn; 3955290000Sglebius int on; 3956182007Sroberto 3957182007Sroberto DPRINTF(4, ("Finding interface for addr %s in list of addresses\n", 3958200576Sroberto stoa(addr))); 3959182007Sroberto 3960290000Sglebius s = socket(AF(addr), SOCK_DGRAM, 0); 3961290000Sglebius if (INVALID_SOCKET == s) 3962182007Sroberto return NULL; 3963132451Sroberto 3964290000Sglebius /* 3965290000Sglebius * If we are looking for broadcast interface we need to set this 3966290000Sglebius * socket to allow broadcast 3967290000Sglebius */ 3968290000Sglebius if (bcast) { 3969290000Sglebius on = 1; 3970290000Sglebius if (SOCKET_ERROR == setsockopt(s, SOL_SOCKET, 3971290000Sglebius SO_BROADCAST, 3972290000Sglebius (char *)&on, 3973290000Sglebius sizeof(on))) { 3974290000Sglebius closesocket(s); 3975290000Sglebius return NULL; 3976290000Sglebius } 3977290000Sglebius } 3978290000Sglebius 3979290000Sglebius rtn = connect(s, &addr->sa, SOCKLEN(addr)); 3980290000Sglebius if (SOCKET_ERROR == rtn) { 3981132451Sroberto closesocket(s); 3982182007Sroberto return NULL; 3983132451Sroberto } 398482498Sroberto 3985290000Sglebius sockaddrlen = sizeof(saddr); 3986290000Sglebius rtn = getsockname(s, &saddr.sa, &sockaddrlen); 3987132451Sroberto closesocket(s); 3988290000Sglebius if (SOCKET_ERROR == rtn) 3989182007Sroberto return NULL; 399082498Sroberto 3991290000Sglebius DPRINTF(4, ("findlocalinterface: kernel maps %s to %s\n", 3992290000Sglebius stoa(addr), stoa(&saddr))); 3993290000Sglebius 3994182007Sroberto iface = getinterface(&saddr, flags); 3995182007Sroberto 3996290000Sglebius /* 3997290000Sglebius * if we didn't find an exact match on saddr, find the closest 3998290000Sglebius * available local address. This handles the case of the 3999290000Sglebius * address suggested by the kernel being excluded by nic rules 4000290000Sglebius * or the user's -I and -L options to ntpd. 4001290000Sglebius * See http://bugs.ntp.org/1184 and http://bugs.ntp.org/1683 4002290000Sglebius * for more background. 4003290000Sglebius */ 4004290000Sglebius if (NULL == iface || iface->ignore_packets) 4005290000Sglebius iface = findclosestinterface(&saddr, 4006290000Sglebius flags | INT_LOOPBACK); 4007290000Sglebius 4008290000Sglebius /* Don't use an interface which will ignore replies */ 4009290000Sglebius if (iface != NULL && iface->ignore_packets) 4010290000Sglebius iface = NULL; 4011290000Sglebius 4012290000Sglebius return iface; 401354359Sroberto} 401454359Sroberto 4015290000Sglebius 401654359Sroberto/* 4017290000Sglebius * findclosestinterface 4018290000Sglebius * 4019290000Sglebius * If there are -I/--interface or -L/novirtualips command-line options, 4020290000Sglebius * or "nic" or "interface" rules in ntp.conf, findlocalinterface() may 4021290000Sglebius * find the kernel's preferred local address for a given peer address is 4022290000Sglebius * administratively unavailable to ntpd, and punt to this routine's more 4023290000Sglebius * expensive search. 4024290000Sglebius * 4025290000Sglebius * Find the numerically closest local address to the one connect() 4026290000Sglebius * suggested. This matches an address on the same subnet first, as 4027290000Sglebius * needed by Bug 1184, and provides a consistent choice if there are 4028290000Sglebius * multiple feasible local addresses, regardless of the order ntpd 4029290000Sglebius * enumerated them. 4030182007Sroberto */ 4031290000Sglebiusendpt * 4032290000Sglebiusfindclosestinterface( 4033290000Sglebius sockaddr_u * addr, 4034290000Sglebius int flags 4035290000Sglebius ) 4036182007Sroberto{ 4037290000Sglebius endpt * ep; 4038290000Sglebius endpt * winner; 4039290000Sglebius sockaddr_u addr_dist; 4040290000Sglebius sockaddr_u min_dist; 4041182007Sroberto 4042290000Sglebius ZERO_SOCK(&min_dist); 4043290000Sglebius winner = NULL; 4044290000Sglebius 4045290000Sglebius for (ep = ep_list; ep != NULL; ep = ep->elink) { 4046290000Sglebius if (ep->ignore_packets || 4047290000Sglebius AF(addr) != ep->family || 4048290000Sglebius flags & ep->flags) 4049290000Sglebius continue; 4050290000Sglebius 4051290000Sglebius calc_addr_distance(&addr_dist, addr, &ep->sin); 4052290000Sglebius if (NULL == winner || 4053290000Sglebius -1 == cmp_addr_distance(&addr_dist, &min_dist)) { 4054290000Sglebius min_dist = addr_dist; 4055290000Sglebius winner = ep; 4056290000Sglebius } 4057182007Sroberto } 4058290000Sglebius if (NULL == winner) 4059290000Sglebius DPRINTF(4, ("findclosestinterface(%s) failed\n", 4060290000Sglebius stoa(addr))); 4061182007Sroberto else 4062290000Sglebius DPRINTF(4, ("findclosestinterface(%s) -> %s\n", 4063290000Sglebius stoa(addr), stoa(&winner->sin))); 4064290000Sglebius 4065290000Sglebius return winner; 4066182007Sroberto} 4067182007Sroberto 4068290000Sglebius 4069182007Sroberto/* 4070290000Sglebius * calc_addr_distance - calculate the distance between two addresses, 4071290000Sglebius * the absolute value of the difference between 4072290000Sglebius * the addresses numerically, stored as an address. 4073182007Sroberto */ 4074290000Sglebiusstatic void 4075290000Sglebiuscalc_addr_distance( 4076290000Sglebius sockaddr_u * dist, 4077290000Sglebius const sockaddr_u * a1, 4078290000Sglebius const sockaddr_u * a2 4079182007Sroberto ) 4080182007Sroberto{ 4081290000Sglebius u_int32 a1val; 4082290000Sglebius u_int32 a2val; 4083290000Sglebius u_int32 v4dist; 4084290000Sglebius int found_greater; 4085290000Sglebius int a1_greater; 4086290000Sglebius int i; 4087182007Sroberto 4088290000Sglebius REQUIRE(AF(a1) == AF(a2)); 4089182007Sroberto 4090290000Sglebius ZERO_SOCK(dist); 4091290000Sglebius AF(dist) = AF(a1); 4092290000Sglebius 4093290000Sglebius /* v4 can be done a bit simpler */ 4094290000Sglebius if (IS_IPV4(a1)) { 4095290000Sglebius a1val = SRCADR(a1); 4096290000Sglebius a2val = SRCADR(a2); 4097290000Sglebius v4dist = (a1val > a2val) 4098290000Sglebius ? a1val - a2val 4099290000Sglebius : a2val - a1val; 4100290000Sglebius SET_ADDR4(dist, v4dist); 4101290000Sglebius 4102290000Sglebius return; 4103182007Sroberto } 4104182007Sroberto 4105290000Sglebius found_greater = FALSE; 4106290000Sglebius a1_greater = FALSE; /* suppress pot. uninit. warning */ 4107290000Sglebius for (i = 0; i < (int)sizeof(NSRCADR6(a1)); i++) { 4108290000Sglebius if (!found_greater && 4109290000Sglebius NSRCADR6(a1)[i] != NSRCADR6(a2)[i]) { 4110290000Sglebius found_greater = TRUE; 4111290000Sglebius a1_greater = (NSRCADR6(a1)[i] > NSRCADR6(a2)[i]); 4112182007Sroberto } 4113290000Sglebius if (!found_greater) { 4114290000Sglebius NSRCADR6(dist)[i] = 0; 4115290000Sglebius } else { 4116290000Sglebius if (a1_greater) 4117290000Sglebius NSRCADR6(dist)[i] = NSRCADR6(a1)[i] - 4118290000Sglebius NSRCADR6(a2)[i]; 4119290000Sglebius else 4120290000Sglebius NSRCADR6(dist)[i] = NSRCADR6(a2)[i] - 4121290000Sglebius NSRCADR6(a1)[i]; 4122182007Sroberto } 4123182007Sroberto } 4124290000Sglebius} 4125182007Sroberto 4126182007Sroberto 4127290000Sglebius/* 4128290000Sglebius * cmp_addr_distance - compare two address distances, returning -1, 0, 4129290000Sglebius * 1 to indicate their relationship. 4130290000Sglebius */ 4131290000Sglebiusstatic int 4132290000Sglebiuscmp_addr_distance( 4133290000Sglebius const sockaddr_u * d1, 4134290000Sglebius const sockaddr_u * d2 4135290000Sglebius ) 4136290000Sglebius{ 4137290000Sglebius int i; 4138182007Sroberto 4139290000Sglebius REQUIRE(AF(d1) == AF(d2)); 4140182007Sroberto 4141290000Sglebius if (IS_IPV4(d1)) { 4142290000Sglebius if (SRCADR(d1) < SRCADR(d2)) 4143290000Sglebius return -1; 4144290000Sglebius else if (SRCADR(d1) == SRCADR(d2)) 4145290000Sglebius return 0; 4146290000Sglebius else 4147290000Sglebius return 1; 4148290000Sglebius } 4149182007Sroberto 4150290000Sglebius for (i = 0; i < (int)sizeof(NSRCADR6(d1)); i++) { 4151290000Sglebius if (NSRCADR6(d1)[i] < NSRCADR6(d2)[i]) 4152290000Sglebius return -1; 4153290000Sglebius else if (NSRCADR6(d1)[i] > NSRCADR6(d2)[i]) 4154290000Sglebius return 1; 4155182007Sroberto } 4156290000Sglebius 4157290000Sglebius return 0; 4158182007Sroberto} 4159182007Sroberto 4160290000Sglebius 4161290000Sglebius 4162182007Sroberto/* 4163290000Sglebius * fetch an interface structure the matches the 4164290000Sglebius * address and has the given flags NOT set 4165290000Sglebius */ 4166290000Sglebiusendpt * 4167290000Sglebiusgetinterface( 4168290000Sglebius sockaddr_u * addr, 4169290000Sglebius u_int32 flags 4170290000Sglebius ) 4171290000Sglebius{ 4172290000Sglebius endpt *iface; 4173290000Sglebius 4174290000Sglebius iface = find_addr_in_list(addr); 4175290000Sglebius 4176290000Sglebius if (iface != NULL && (iface->flags & flags)) 4177290000Sglebius iface = NULL; 4178290000Sglebius 4179290000Sglebius return iface; 4180290000Sglebius} 4181290000Sglebius 4182290000Sglebius 4183290000Sglebius/* 418482498Sroberto * findbcastinter - find broadcast interface corresponding to address 418582498Sroberto */ 4186290000Sglebiusendpt * 418782498Srobertofindbcastinter( 4188290000Sglebius sockaddr_u *addr 418982498Sroberto ) 419082498Sroberto{ 4191290000Sglebius endpt * iface; 4192290000Sglebius 4193290000Sglebius iface = NULL; 4194106163Sroberto#if !defined(MPE) && (defined(SIOCGIFCONF) || defined(SYS_WINNT)) 4195182007Sroberto DPRINTF(4, ("Finding broadcast/multicast interface for addr %s in list of addresses\n", 4196182007Sroberto stoa(addr))); 419782498Sroberto 4198290000Sglebius iface = findlocalinterface(addr, INT_LOOPBACK | INT_WILDCARD, 4199290000Sglebius 1); 4200290000Sglebius if (iface != NULL) { 4201290000Sglebius DPRINTF(4, ("Easily found bcast-/mcast- interface index #%d %s\n", 4202290000Sglebius iface->ifnum, iface->name)); 4203290000Sglebius return iface; 4204182007Sroberto } 4205182007Sroberto 4206290000Sglebius /* 4207290000Sglebius * plan B - try to find something reasonable in our lists in 4208290000Sglebius * case kernel lookup doesn't help 4209290000Sglebius */ 4210290000Sglebius for (iface = ep_list; iface != NULL; iface = iface->elink) { 4211290000Sglebius if (iface->flags & INT_WILDCARD) 4212290000Sglebius continue; 4213182007Sroberto 4214182007Sroberto /* Don't bother with ignored interfaces */ 4215290000Sglebius if (iface->ignore_packets) 4216182007Sroberto continue; 4217290000Sglebius 421882498Sroberto /* 4219182007Sroberto * First look if this is the correct family 4220182007Sroberto */ 4221290000Sglebius if(AF(&iface->sin) != AF(addr)) 4222290000Sglebius continue; 4223182007Sroberto 4224182007Sroberto /* Skip the loopback addresses */ 4225290000Sglebius if (iface->flags & INT_LOOPBACK) 4226182007Sroberto continue; 4227182007Sroberto 4228132451Sroberto /* 4229290000Sglebius * If we are looking to match a multicast address and 4230290000Sglebius * this interface is one... 4231182007Sroberto */ 4232290000Sglebius if (addr_ismulticast(addr) 4233290000Sglebius && (iface->flags & INT_MULTICAST)) { 4234182007Sroberto#ifdef INCLUDE_IPV6_SUPPORT 4235290000Sglebius /* 4236290000Sglebius * ...it is the winner unless we're looking for 4237290000Sglebius * an interface to use for link-local multicast 4238290000Sglebius * and its address is not link-local. 4239290000Sglebius */ 4240290000Sglebius if (IS_IPV6(addr) 4241290000Sglebius && IN6_IS_ADDR_MC_LINKLOCAL(PSOCK_ADDR6(addr)) 4242290000Sglebius && !IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(&iface->sin))) 4243290000Sglebius continue; 4244182007Sroberto#endif 4245182007Sroberto break; 4246182007Sroberto } 4247182007Sroberto 4248182007Sroberto /* 424982498Sroberto * We match only those interfaces marked as 425082498Sroberto * broadcastable and either the explicit broadcast 425182498Sroberto * address or the network portion of the IP address. 425282498Sroberto * Sloppy. 425382498Sroberto */ 4254290000Sglebius if (IS_IPV4(addr)) { 4255290000Sglebius if (SOCK_EQ(&iface->bcast, addr)) 4256182007Sroberto break; 4257290000Sglebius 4258290000Sglebius if ((NSRCADR(&iface->sin) & NSRCADR(&iface->mask)) 4259290000Sglebius == (NSRCADR(addr) & NSRCADR(&iface->mask))) 4260182007Sroberto break; 4261132451Sroberto } 4262182007Sroberto#ifdef INCLUDE_IPV6_SUPPORT 4263290000Sglebius else if (IS_IPV6(addr)) { 4264290000Sglebius if (SOCK_EQ(&iface->bcast, addr)) 4265182007Sroberto break; 4266290000Sglebius 4267290000Sglebius if (SOCK_EQ(netof(&iface->sin), netof(addr))) 4268182007Sroberto break; 4269182007Sroberto } 4270182007Sroberto#endif 427182498Sroberto } 427282498Sroberto#endif /* SIOCGIFCONF */ 4273290000Sglebius if (NULL == iface) { 4274290000Sglebius DPRINTF(4, ("No bcast interface found for %s\n", 4275290000Sglebius stoa(addr))); 4276290000Sglebius iface = ANY_INTERFACE_CHOOSE(addr); 4277182007Sroberto } else { 4278290000Sglebius DPRINTF(4, ("Found bcast-/mcast- interface index #%d %s\n", 4279290000Sglebius iface->ifnum, iface->name)); 4280182007Sroberto } 4281290000Sglebius 4282290000Sglebius return iface; 428382498Sroberto} 428482498Sroberto 428582498Sroberto 428682498Sroberto/* 428754359Sroberto * io_clr_stats - clear I/O module statistics 428854359Sroberto */ 428954359Srobertovoid 429054359Srobertoio_clr_stats(void) 429154359Sroberto{ 429254359Sroberto packets_dropped = 0; 429354359Sroberto packets_ignored = 0; 429454359Sroberto packets_received = 0; 429554359Sroberto packets_sent = 0; 429654359Sroberto packets_notsent = 0; 429754359Sroberto 429854359Sroberto handler_calls = 0; 429954359Sroberto handler_pkts = 0; 430054359Sroberto io_timereset = current_time; 430154359Sroberto} 430254359Sroberto 430354359Sroberto 430454359Sroberto#ifdef REFCLOCK 430554359Sroberto/* 430654359Sroberto * io_addclock - add a reference clock to the list and arrange that we 430754359Sroberto * get SIGIO interrupts from it. 430854359Sroberto */ 430954359Srobertoint 431054359Srobertoio_addclock( 431154359Sroberto struct refclockio *rio 431254359Sroberto ) 431354359Sroberto{ 431454359Sroberto BLOCKIO(); 4315290000Sglebius 431654359Sroberto /* 431754359Sroberto * Stuff the I/O structure in the list and mark the descriptor 4318290000Sglebius * in use. There is a harmless (I hope) race condition here. 431954359Sroberto */ 4320290000Sglebius rio->active = TRUE; 432154359Sroberto 432254359Sroberto# ifdef HAVE_SIGNALED_IO 4323290000Sglebius if (init_clock_sig(rio)) { 432454359Sroberto UNBLOCKIO(); 432554359Sroberto return 0; 432654359Sroberto } 432754359Sroberto# elif defined(HAVE_IO_COMPLETION_PORT) 4328298770Sdelphij if (!io_completion_port_add_clock_io(rio)) { 432954359Sroberto UNBLOCKIO(); 433054359Sroberto return 0; 433154359Sroberto } 433254359Sroberto# endif 433354359Sroberto 4334132451Sroberto /* 4335182007Sroberto * enqueue 4336132451Sroberto */ 4337290000Sglebius LINK_SLIST(refio, rio, next); 4338182007Sroberto 4339290000Sglebius /* 4340182007Sroberto * register fd 4341182007Sroberto */ 4342182007Sroberto add_fd_to_list(rio->fd, FD_TYPE_FILE); 4343182007Sroberto 434454359Sroberto UNBLOCKIO(); 434554359Sroberto return 1; 434654359Sroberto} 434754359Sroberto 4348290000Sglebius 434954359Sroberto/* 435054359Sroberto * io_closeclock - close the clock in the I/O structure given 435154359Sroberto */ 435254359Srobertovoid 435354359Srobertoio_closeclock( 435454359Sroberto struct refclockio *rio 435554359Sroberto ) 435654359Sroberto{ 4357290000Sglebius struct refclockio *unlinked; 4358290000Sglebius 4359182007Sroberto BLOCKIO(); 4360290000Sglebius 436154359Sroberto /* 436254359Sroberto * Remove structure from the list 436354359Sroberto */ 4364290000Sglebius rio->active = FALSE; 4365290000Sglebius UNLINK_SLIST(unlinked, refio, rio, next, struct refclockio); 4366290000Sglebius if (NULL != unlinked) { 4367298770Sdelphij /* Close the descriptor. The order of operations is 4368298770Sdelphij * important here in case of async / overlapped IO: 4369298770Sdelphij * only after we have removed the clock from the 4370298770Sdelphij * IO completion port we can be sure no further 4371298770Sdelphij * input is queued. So... 4372298770Sdelphij * - we first disable feeding to the queu by removing 4373298770Sdelphij * the clock from the IO engine 4374298770Sdelphij * - close the file (which brings down any IO on it) 4375298770Sdelphij * - clear the buffer from results for this fd 4376290000Sglebius */ 4377298770Sdelphij# ifdef HAVE_IO_COMPLETION_PORT 4378298770Sdelphij io_completion_port_remove_clock_io(rio); 4379298770Sdelphij# endif 4380290000Sglebius close_and_delete_fd_from_list(rio->fd); 4381298770Sdelphij purge_recv_buffers_for_fd(rio->fd); 4382298770Sdelphij rio->fd = -1; 438354359Sroberto } 438454359Sroberto 4385182007Sroberto UNBLOCKIO(); 438654359Sroberto} 438754359Sroberto#endif /* REFCLOCK */ 438854359Sroberto 4389290000Sglebius 4390132451Sroberto/* 4391132451Sroberto * On NT a SOCKET is an unsigned int so we cannot possibly keep it in 4392132451Sroberto * an array. So we use one of the ISC_LIST functions to hold the 4393132451Sroberto * socket value and use that when we want to enumerate it. 4394290000Sglebius * 4395290000Sglebius * This routine is called by the forked intres child process to close 4396290000Sglebius * all open sockets. On Windows there's no need as intres runs in 4397290000Sglebius * the same process as a thread. 4398132451Sroberto */ 4399290000Sglebius#ifndef SYS_WINNT 4400132451Srobertovoid 4401290000Sglebiuskill_asyncio( 4402290000Sglebius int startfd 4403290000Sglebius ) 4404132451Sroberto{ 4405132451Sroberto BLOCKIO(); 4406132451Sroberto 4407290000Sglebius /* 4408290000Sglebius * In the child process we do not maintain activefds and 4409290000Sglebius * maxactivefd. Zeroing maxactivefd disables code which 4410290000Sglebius * maintains it in close_and_delete_fd_from_list(). 4411290000Sglebius */ 4412290000Sglebius maxactivefd = 0; 4413132451Sroberto 4414290000Sglebius while (fd_list != NULL) 4415290000Sglebius close_and_delete_fd_from_list(fd_list->fd); 4416290000Sglebius 4417182007Sroberto UNBLOCKIO(); 4418132451Sroberto} 4419290000Sglebius#endif /* !SYS_WINNT */ 4420182007Sroberto 4421290000Sglebius 4422132451Sroberto/* 4423132451Sroberto * Add and delete functions for the list of open sockets 4424132451Sroberto */ 4425182007Srobertostatic void 4426290000Sglebiusadd_fd_to_list( 4427290000Sglebius SOCKET fd, 4428290000Sglebius enum desc_type type 4429290000Sglebius ) 4430290000Sglebius{ 4431290000Sglebius vsock_t *lsock = emalloc(sizeof(*lsock)); 4432290000Sglebius 4433132451Sroberto lsock->fd = fd; 4434182007Sroberto lsock->type = type; 4435132451Sroberto 4436290000Sglebius LINK_SLIST(fd_list, lsock, link); 4437290000Sglebius maintain_activefds(fd, 0); 4438132451Sroberto} 4439132451Sroberto 4440290000Sglebius 4441182007Srobertostatic void 4442290000Sglebiusclose_and_delete_fd_from_list( 4443290000Sglebius SOCKET fd 4444290000Sglebius ) 4445290000Sglebius{ 4446290000Sglebius vsock_t *lsock; 4447182007Sroberto 4448290000Sglebius UNLINK_EXPR_SLIST(lsock, fd_list, fd == 4449290000Sglebius UNLINK_EXPR_SLIST_CURRENT()->fd, link, vsock_t); 4450132451Sroberto 4451290000Sglebius if (NULL == lsock) 4452290000Sglebius return; 4453182007Sroberto 4454290000Sglebius switch (lsock->type) { 4455182007Sroberto 4456290000Sglebius case FD_TYPE_SOCKET: 4457290000Sglebius closesocket(lsock->fd); 4458290000Sglebius break; 4459290000Sglebius 4460290000Sglebius case FD_TYPE_FILE: 4461293894Sglebius closeserial((int)lsock->fd); 4462290000Sglebius break; 4463290000Sglebius 4464290000Sglebius default: 4465290000Sglebius msyslog(LOG_ERR, 4466290000Sglebius "internal error - illegal descriptor type %d - EXITING", 4467290000Sglebius (int)lsock->type); 4468290000Sglebius exit(1); 4469132451Sroberto } 4470290000Sglebius 4471290000Sglebius free(lsock); 4472290000Sglebius /* 4473290000Sglebius * remove from activefds 4474290000Sglebius */ 4475290000Sglebius maintain_activefds(fd, 1); 4476132451Sroberto} 4477132451Sroberto 4478290000Sglebius 4479182007Srobertostatic void 4480290000Sglebiusadd_addr_to_list( 4481290000Sglebius sockaddr_u * addr, 4482290000Sglebius endpt * ep 4483290000Sglebius ) 4484290000Sglebius{ 4485290000Sglebius remaddr_t *laddr; 4486290000Sglebius 4487132451Sroberto#ifdef DEBUG 4488182007Sroberto if (find_addr_in_list(addr) == NULL) { 4489132451Sroberto#endif 4490182007Sroberto /* not there yet - add to list */ 4491290000Sglebius laddr = emalloc(sizeof(*laddr)); 4492290000Sglebius laddr->addr = *addr; 4493290000Sglebius laddr->ep = ep; 4494290000Sglebius 4495290000Sglebius LINK_SLIST(remoteaddr_list, laddr, link); 4496290000Sglebius 4497182007Sroberto DPRINTF(4, ("Added addr %s to list of addresses\n", 4498182007Sroberto stoa(addr))); 4499182007Sroberto#ifdef DEBUG 4500290000Sglebius } else 4501182007Sroberto DPRINTF(4, ("WARNING: Attempt to add duplicate addr %s to address list\n", 4502182007Sroberto stoa(addr))); 4503182007Sroberto#endif 4504182007Sroberto} 4505132451Sroberto 4506290000Sglebius 4507182007Srobertostatic void 4508290000Sglebiusdelete_addr_from_list( 4509290000Sglebius sockaddr_u *addr 4510290000Sglebius ) 4511290000Sglebius{ 4512290000Sglebius remaddr_t *unlinked; 4513132451Sroberto 4514290000Sglebius UNLINK_EXPR_SLIST(unlinked, remoteaddr_list, SOCK_EQ(addr, 4515290000Sglebius &(UNLINK_EXPR_SLIST_CURRENT()->addr)), link, remaddr_t); 4516132451Sroberto 4517290000Sglebius if (unlinked != NULL) { 4518290000Sglebius DPRINTF(4, ("Deleted addr %s from list of addresses\n", 4519290000Sglebius stoa(addr))); 4520290000Sglebius free(unlinked); 4521182007Sroberto } 4522182007Sroberto} 4523182007Sroberto 4524290000Sglebius 4525182007Srobertostatic void 4526290000Sglebiusdelete_interface_from_list( 4527290000Sglebius endpt *iface 4528290000Sglebius ) 4529290000Sglebius{ 4530290000Sglebius remaddr_t *unlinked; 4531182007Sroberto 4532290000Sglebius for (;;) { 4533290000Sglebius UNLINK_EXPR_SLIST(unlinked, remoteaddr_list, iface == 4534290000Sglebius UNLINK_EXPR_SLIST_CURRENT()->ep, link, 4535290000Sglebius remaddr_t); 4536290000Sglebius 4537290000Sglebius if (unlinked == NULL) 4538290000Sglebius break; 4539290000Sglebius DPRINTF(4, ("Deleted addr %s for interface #%d %s from list of addresses\n", 4540290000Sglebius stoa(&unlinked->addr), iface->ifnum, 4541290000Sglebius iface->name)); 4542290000Sglebius free(unlinked); 4543182007Sroberto } 4544182007Sroberto} 4545182007Sroberto 4546290000Sglebius 4547182007Srobertostatic struct interface * 4548290000Sglebiusfind_addr_in_list( 4549290000Sglebius sockaddr_u *addr 4550290000Sglebius ) 4551290000Sglebius{ 4552290000Sglebius remaddr_t *entry; 4553182007Sroberto 4554182007Sroberto DPRINTF(4, ("Searching for addr %s in list of addresses - ", 4555182007Sroberto stoa(addr))); 4556182007Sroberto 4557290000Sglebius for (entry = remoteaddr_list; 4558290000Sglebius entry != NULL; 4559290000Sglebius entry = entry->link) 4560290000Sglebius if (SOCK_EQ(&entry->addr, addr)) { 4561182007Sroberto DPRINTF(4, ("FOUND\n")); 4562290000Sglebius return entry->ep; 4563182007Sroberto } 4564290000Sglebius 4565182007Sroberto DPRINTF(4, ("NOT FOUND\n")); 4566290000Sglebius return NULL; 4567132451Sroberto} 4568132451Sroberto 4569290000Sglebius 4570182007Sroberto/* 4571290000Sglebius * Find the given address with the all given flags set in the list 4572182007Sroberto */ 4573290000Sglebiusstatic endpt * 4574290000Sglebiusfind_flagged_addr_in_list( 4575290000Sglebius sockaddr_u * addr, 4576290000Sglebius u_int32 flags 4577290000Sglebius ) 4578290000Sglebius{ 4579290000Sglebius remaddr_t *entry; 4580182007Sroberto 4581290000Sglebius DPRINTF(4, ("Finding addr %s with flags %d in list: ", 4582290000Sglebius stoa(addr), flags)); 4583132451Sroberto 4584290000Sglebius for (entry = remoteaddr_list; 4585290000Sglebius entry != NULL; 4586290000Sglebius entry = entry->link) 4587290000Sglebius 4588290000Sglebius if (SOCK_EQ(&entry->addr, addr) 4589290000Sglebius && (entry->ep->flags & flags) == flags) { 4590290000Sglebius 4591290000Sglebius DPRINTF(4, ("FOUND\n")); 4592290000Sglebius return entry->ep; 4593132451Sroberto } 4594290000Sglebius 4595290000Sglebius DPRINTF(4, ("NOT FOUND\n")); 4596290000Sglebius return NULL; 4597132451Sroberto} 4598182007Sroberto 4599290000Sglebius 4600290000Sglebiusconst char * 4601290000Sglebiuslocaladdrtoa( 4602290000Sglebius endpt *la 4603290000Sglebius ) 4604290000Sglebius{ 4605290000Sglebius return (NULL == la) 4606290000Sglebius ? "<null>" 4607290000Sglebius : stoa(&la->sin); 4608290000Sglebius} 4609290000Sglebius 4610290000Sglebius 4611182007Sroberto#ifdef HAS_ROUTING_SOCKET 4612290000Sglebius# ifndef UPDATE_GRACE 4613290000Sglebius# define UPDATE_GRACE 2 /* wait UPDATE_GRACE seconds before scanning */ 4614290000Sglebius# endif 4615182007Sroberto 4616182007Srobertostatic void 4617182007Srobertoprocess_routing_msgs(struct asyncio_reader *reader) 4618182007Sroberto{ 4619182007Sroberto char buffer[5120]; 4620290000Sglebius int cnt, msg_type; 4621290000Sglebius#ifdef HAVE_RTNETLINK 4622290000Sglebius struct nlmsghdr *nh; 4623290000Sglebius#else 4624290000Sglebius struct rt_msghdr rtm; 4625290000Sglebius char *p; 4626290000Sglebius#endif 4627182007Sroberto 4628182007Sroberto if (disable_dynamic_updates) { 4629182007Sroberto /* 4630290000Sglebius * discard ourselves if we are not needed any more 4631182007Sroberto * usually happens when running unprivileged 4632182007Sroberto */ 4633182007Sroberto remove_asyncio_reader(reader); 4634182007Sroberto delete_asyncio_reader(reader); 4635182007Sroberto return; 4636182007Sroberto } 4637182007Sroberto 4638182007Sroberto cnt = read(reader->fd, buffer, sizeof(buffer)); 4639290000Sglebius 4640182007Sroberto if (cnt < 0) { 4641290000Sglebius if (errno == ENOBUFS) { 4642290000Sglebius msyslog(LOG_ERR, 4643290000Sglebius "routing socket reports: %m"); 4644290000Sglebius } else { 4645290000Sglebius msyslog(LOG_ERR, 4646290000Sglebius "routing socket reports: %m - disabling"); 4647290000Sglebius remove_asyncio_reader(reader); 4648290000Sglebius delete_asyncio_reader(reader); 4649290000Sglebius } 4650182007Sroberto return; 4651182007Sroberto } 4652182007Sroberto 4653182007Sroberto /* 4654182007Sroberto * process routing message 4655182007Sroberto */ 4656290000Sglebius#ifdef HAVE_RTNETLINK 4657293894Sglebius for (nh = UA_PTR(struct nlmsghdr, buffer); 4658290000Sglebius NLMSG_OK(nh, cnt); 4659290000Sglebius nh = NLMSG_NEXT(nh, cnt)) { 4660290000Sglebius msg_type = nh->nlmsg_type; 4661290000Sglebius#else 4662290000Sglebius for (p = buffer; 4663290000Sglebius (p + sizeof(struct rt_msghdr)) <= (buffer + cnt); 4664290000Sglebius p += rtm.rtm_msglen) { 4665290000Sglebius memcpy(&rtm, p, sizeof(rtm)); 4666290000Sglebius if (rtm.rtm_version != RTM_VERSION) { 4667290000Sglebius msyslog(LOG_ERR, 4668290000Sglebius "version mismatch (got %d - expected %d) on routing socket - disabling", 4669290000Sglebius rtm.rtm_version, RTM_VERSION); 4670290000Sglebius 4671182007Sroberto remove_asyncio_reader(reader); 4672182007Sroberto delete_asyncio_reader(reader); 4673182007Sroberto return; 4674182007Sroberto } 4675290000Sglebius msg_type = rtm.rtm_type; 4676290000Sglebius#endif 4677290000Sglebius switch (msg_type) { 4678182007Sroberto#ifdef RTM_NEWADDR 4679182007Sroberto case RTM_NEWADDR: 4680182007Sroberto#endif 4681182007Sroberto#ifdef RTM_DELADDR 4682182007Sroberto case RTM_DELADDR: 4683182007Sroberto#endif 4684182007Sroberto#ifdef RTM_ADD 4685182007Sroberto case RTM_ADD: 4686182007Sroberto#endif 4687182007Sroberto#ifdef RTM_DELETE 4688182007Sroberto case RTM_DELETE: 4689182007Sroberto#endif 4690182007Sroberto#ifdef RTM_REDIRECT 4691182007Sroberto case RTM_REDIRECT: 4692182007Sroberto#endif 4693182007Sroberto#ifdef RTM_CHANGE 4694182007Sroberto case RTM_CHANGE: 4695182007Sroberto#endif 4696182007Sroberto#ifdef RTM_LOSING 4697182007Sroberto case RTM_LOSING: 4698182007Sroberto#endif 4699182007Sroberto#ifdef RTM_IFINFO 4700182007Sroberto case RTM_IFINFO: 4701182007Sroberto#endif 4702182007Sroberto#ifdef RTM_IFANNOUNCE 4703182007Sroberto case RTM_IFANNOUNCE: 4704182007Sroberto#endif 4705290000Sglebius#ifdef RTM_NEWLINK 4706290000Sglebius case RTM_NEWLINK: 4707290000Sglebius#endif 4708290000Sglebius#ifdef RTM_DELLINK 4709290000Sglebius case RTM_DELLINK: 4710290000Sglebius#endif 4711290000Sglebius#ifdef RTM_NEWROUTE 4712290000Sglebius case RTM_NEWROUTE: 4713290000Sglebius#endif 4714290000Sglebius#ifdef RTM_DELROUTE 4715290000Sglebius case RTM_DELROUTE: 4716290000Sglebius#endif 4717182007Sroberto /* 4718290000Sglebius * we are keen on new and deleted addresses and 4719290000Sglebius * if an interface goes up and down or routing 4720290000Sglebius * changes 4721182007Sroberto */ 4722290000Sglebius DPRINTF(3, ("routing message op = %d: scheduling interface update\n", 4723290000Sglebius msg_type)); 4724182007Sroberto timer_interfacetimeout(current_time + UPDATE_GRACE); 4725182007Sroberto break; 4726290000Sglebius#ifdef HAVE_RTNETLINK 4727290000Sglebius case NLMSG_DONE: 4728290000Sglebius /* end of multipart message */ 4729290000Sglebius return; 4730290000Sglebius#endif 4731182007Sroberto default: 4732182007Sroberto /* 4733182007Sroberto * the rest doesn't bother us. 4734182007Sroberto */ 4735290000Sglebius DPRINTF(4, ("routing message op = %d: ignored\n", 4736290000Sglebius msg_type)); 4737182007Sroberto break; 4738182007Sroberto } 4739182007Sroberto } 4740182007Sroberto} 4741182007Sroberto 4742182007Sroberto/* 4743182007Sroberto * set up routing notifications 4744182007Sroberto */ 4745182007Srobertostatic void 4746182007Srobertoinit_async_notifications() 4747182007Sroberto{ 4748182007Sroberto struct asyncio_reader *reader; 4749290000Sglebius#ifdef HAVE_RTNETLINK 4750290000Sglebius int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 4751290000Sglebius struct sockaddr_nl sa; 4752290000Sglebius#else 4753182007Sroberto int fd = socket(PF_ROUTE, SOCK_RAW, 0); 4754290000Sglebius#endif 4755290000Sglebius if (fd < 0) { 4756290000Sglebius msyslog(LOG_ERR, 4757290000Sglebius "unable to open routing socket (%m) - using polled interface update"); 4758290000Sglebius return; 4759290000Sglebius } 4760290000Sglebius 4761290000Sglebius fd = move_fd(fd); 4762290000Sglebius#ifdef HAVE_RTNETLINK 4763290000Sglebius ZERO(sa); 4764290000Sglebius sa.nl_family = PF_NETLINK; 4765290000Sglebius sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR 4766290000Sglebius | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_ROUTE 4767290000Sglebius | RTMGRP_IPV4_MROUTE | RTMGRP_IPV6_ROUTE 4768290000Sglebius | RTMGRP_IPV6_MROUTE; 4769290000Sglebius if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 4770290000Sglebius msyslog(LOG_ERR, 4771290000Sglebius "bind failed on routing socket (%m) - using polled interface update"); 4772290000Sglebius return; 4773290000Sglebius } 4774290000Sglebius#endif 4775290000Sglebius make_socket_nonblocking(fd); 4776182007Sroberto#if defined(HAVE_SIGNALED_IO) 4777290000Sglebius init_socket_sig(fd); 4778182007Sroberto#endif /* HAVE_SIGNALED_IO */ 4779182007Sroberto 4780290000Sglebius reader = new_asyncio_reader(); 4781290000Sglebius 4782290000Sglebius reader->fd = fd; 4783290000Sglebius reader->receiver = process_routing_msgs; 4784290000Sglebius 4785290000Sglebius add_asyncio_reader(reader, FD_TYPE_SOCKET); 4786290000Sglebius msyslog(LOG_INFO, 4787290000Sglebius "Listening on routing socket on fd #%d for interface updates", 4788290000Sglebius fd); 4789182007Sroberto} 4790182007Sroberto#else 4791290000Sglebius/* HAS_ROUTING_SOCKET not defined */ 4792182007Srobertostatic void 4793290000Sglebiusinit_async_notifications(void) 4794182007Sroberto{ 4795182007Sroberto} 4796182007Sroberto#endif 4797290000Sglebius 4798