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