xref: /netbsd/external/bsd/ntp/dist/ntpd/ntp_io.c (revision 1c24ec91)
1*1c24ec91Schristos /*	$NetBSD: ntp_io.c,v 1.25 2017/04/13 20:17:42 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * ntp_io.c - input/output routines for ntpd.	The socket-opening code
5abb0f93cSkardel  *		   was shamelessly stolen from ntpd.
6abb0f93cSkardel  */
7abb0f93cSkardel 
8abb0f93cSkardel #ifdef HAVE_CONFIG_H
9abb0f93cSkardel # include <config.h>
10abb0f93cSkardel #endif
11abb0f93cSkardel 
12abb0f93cSkardel #include <stdio.h>
13abb0f93cSkardel #include <signal.h>
14ad131110Schristos #ifdef HAVE_FNMATCH_H
15ad131110Schristos # include <fnmatch.h>
16ad131110Schristos # if !defined(FNM_CASEFOLD) && defined(FNM_IGNORECASE)
17ad131110Schristos #  define FNM_CASEFOLD FNM_IGNORECASE
18ad131110Schristos # endif
19ad131110Schristos #endif
20abb0f93cSkardel #ifdef HAVE_SYS_PARAM_H
21abb0f93cSkardel # include <sys/param.h>
22abb0f93cSkardel #endif
23abb0f93cSkardel #ifdef HAVE_SYS_IOCTL_H
24abb0f93cSkardel # include <sys/ioctl.h>
25abb0f93cSkardel #endif
26abb0f93cSkardel #ifdef HAVE_SYS_SOCKIO_H	/* UXPV: SIOC* #defines (Frank Vance <fvance@waii.com>) */
27abb0f93cSkardel # include <sys/sockio.h>
28abb0f93cSkardel #endif
29abb0f93cSkardel #ifdef HAVE_SYS_UIO_H
30abb0f93cSkardel # include <sys/uio.h>
31abb0f93cSkardel #endif
32abb0f93cSkardel 
33abb0f93cSkardel #include "ntp_machine.h"
34abb0f93cSkardel #include "ntpd.h"
35abb0f93cSkardel #include "ntp_io.h"
36abb0f93cSkardel #include "iosignal.h"
37abb0f93cSkardel #include "ntp_lists.h"
38abb0f93cSkardel #include "ntp_refclock.h"
39abb0f93cSkardel #include "ntp_stdlib.h"
40b3d6264cSchristos #include "ntp_worker.h"
41abb0f93cSkardel #include "ntp_request.h"
42abb0f93cSkardel #include "ntp_assert.h"
43b3d6264cSchristos #include "timevalops.h"
44b3d6264cSchristos #include "timespecops.h"
45abb0f93cSkardel #include "ntpd-opts.h"
46bd25f4c4Schristos #include "safecast.h"
47abb0f93cSkardel 
48abb0f93cSkardel /* Don't include ISC's version of IPv6 variables and structures */
49abb0f93cSkardel #define ISC_IPV6_H 1
50abb0f93cSkardel #include <isc/mem.h>
51abb0f93cSkardel #include <isc/interfaceiter.h>
52abb0f93cSkardel #include <isc/netaddr.h>
53abb0f93cSkardel #include <isc/result.h>
54abb0f93cSkardel #include <isc/sockaddr.h>
55abb0f93cSkardel 
56abb0f93cSkardel #ifdef SIM
57abb0f93cSkardel #include "ntpsim.h"
58abb0f93cSkardel #endif
59abb0f93cSkardel 
60abb0f93cSkardel #ifdef HAS_ROUTING_SOCKET
61abb0f93cSkardel # include <net/route.h>
62abb0f93cSkardel # ifdef HAVE_RTNETLINK
63abb0f93cSkardel #  include <linux/rtnetlink.h>
64abb0f93cSkardel # endif
65abb0f93cSkardel #endif
66abb0f93cSkardel 
67abb0f93cSkardel /*
68abb0f93cSkardel  * setsockopt does not always have the same arg declaration
69abb0f93cSkardel  * across all platforms. If it's not defined we make it empty
70abb0f93cSkardel  */
71abb0f93cSkardel 
72abb0f93cSkardel #ifndef SETSOCKOPT_ARG_CAST
73abb0f93cSkardel #define SETSOCKOPT_ARG_CAST
74abb0f93cSkardel #endif
75abb0f93cSkardel 
76abb0f93cSkardel extern int listen_to_virtual_ips;
77abb0f93cSkardel 
784e3b3909Schristos #ifndef IPTOS_DSCP_EF
794e3b3909Schristos #define IPTOS_DSCP_EF 0xb8
804e3b3909Schristos #endif
814e3b3909Schristos int qos = IPTOS_DSCP_EF;	/* QoS RFC3246 */
824e3b3909Schristos 
834e3b3909Schristos #ifdef LEAP_SMEAR
844e3b3909Schristos /* TODO burnicki: This should be moved to ntp_timer.c, but if we do so
854e3b3909Schristos  * we get a linker error. Since we're running out of time before the leap
864e3b3909Schristos  * second occurs, we let it here where it just works.
874e3b3909Schristos  */
884e3b3909Schristos int leap_smear_intv;
894e3b3909Schristos #endif
904e3b3909Schristos 
91abb0f93cSkardel /*
92abb0f93cSkardel  * NIC rule entry
93abb0f93cSkardel  */
94abb0f93cSkardel typedef struct nic_rule_tag nic_rule;
95abb0f93cSkardel 
96abb0f93cSkardel struct nic_rule_tag {
97abb0f93cSkardel 	nic_rule *	next;
98abb0f93cSkardel 	nic_rule_action	action;
99abb0f93cSkardel 	nic_rule_match	match_type;
100abb0f93cSkardel 	char *		if_name;
10145530cf1Skardel 	sockaddr_u	addr;
102abb0f93cSkardel 	int		prefixlen;
103abb0f93cSkardel };
104abb0f93cSkardel 
105abb0f93cSkardel /*
106abb0f93cSkardel  * NIC rule listhead.  Entries are added at the head so that the first
107abb0f93cSkardel  * match in the list is the last matching rule specified.
108abb0f93cSkardel  */
109abb0f93cSkardel nic_rule *nic_rule_list;
110abb0f93cSkardel 
111abb0f93cSkardel 
112b3d6264cSchristos #if defined(SO_BINTIME) && defined(SCM_BINTIME) && defined(CMSG_FIRSTHDR)
113b3d6264cSchristos #  define HAVE_PACKET_TIMESTAMP
114b3d6264cSchristos #  define HAVE_BINTIME
115b3d6264cSchristos #  ifdef BINTIME_CTLMSGBUF_SIZE
116b3d6264cSchristos #   define CMSG_BUFSIZE BINTIME_CTLMSGBUF_SIZE
117b3d6264cSchristos #  else
118b3d6264cSchristos #   define CMSG_BUFSIZE  1536 /* moderate default */
119b3d6264cSchristos #  endif
120b3d6264cSchristos #elif defined(SO_TIMESTAMPNS) && defined(SCM_TIMESTAMPNS) && defined(CMSG_FIRSTHDR)
121b3d6264cSchristos #  define HAVE_PACKET_TIMESTAMP
122b3d6264cSchristos #  define HAVE_TIMESTAMPNS
123b3d6264cSchristos #  ifdef TIMESTAMPNS_CTLMSGBUF_SIZE
124b3d6264cSchristos #   define CMSG_BUFSIZE TIMESTAMPNS_CTLMSGBUF_SIZE
125b3d6264cSchristos #  else
126b3d6264cSchristos #   define CMSG_BUFSIZE  1536 /* moderate default */
127b3d6264cSchristos #  endif
128b3d6264cSchristos #elif defined(SO_TIMESTAMP) && defined(SCM_TIMESTAMP) && defined(CMSG_FIRSTHDR)
129b3d6264cSchristos #  define HAVE_PACKET_TIMESTAMP
130abb0f93cSkardel #  define HAVE_TIMESTAMP
131b3d6264cSchristos #  ifdef TIMESTAMP_CTLMSGBUF_SIZE
132b3d6264cSchristos #   define CMSG_BUFSIZE TIMESTAMP_CTLMSGBUF_SIZE
133b3d6264cSchristos #  else
134b3d6264cSchristos #   define CMSG_BUFSIZE  1536 /* moderate default */
135abb0f93cSkardel #  endif
136abb0f93cSkardel #else
137abb0f93cSkardel /* fill in for old/other timestamp interfaces */
138abb0f93cSkardel #endif
139abb0f93cSkardel 
140abb0f93cSkardel #if defined(SYS_WINNT)
141b3d6264cSchristos #include "win32_io.h"
142abb0f93cSkardel #include <isc/win32os.h>
143b3d6264cSchristos #endif
144abb0f93cSkardel 
145abb0f93cSkardel /*
146abb0f93cSkardel  * We do asynchronous input using the SIGIO facility.  A number of
147abb0f93cSkardel  * recvbuf buffers are preallocated for input.	In the signal
148abb0f93cSkardel  * handler we poll to see which sockets are ready and read the
149abb0f93cSkardel  * packets from them into the recvbuf's along with a time stamp and
150abb0f93cSkardel  * an indication of the source host and the interface it was received
151abb0f93cSkardel  * through.  This allows us to get as accurate receive time stamps
152abb0f93cSkardel  * as possible independent of other processing going on.
153abb0f93cSkardel  *
154abb0f93cSkardel  * We watch the number of recvbufs available to the signal handler
155abb0f93cSkardel  * and allocate more when this number drops below the low water
156abb0f93cSkardel  * mark.  If the signal handler should run out of buffers in the
157abb0f93cSkardel  * interim it will drop incoming frames, the idea being that it is
158abb0f93cSkardel  * better to drop a packet than to be inaccurate.
159abb0f93cSkardel  */
160abb0f93cSkardel 
161abb0f93cSkardel 
162abb0f93cSkardel /*
163abb0f93cSkardel  * Other statistics of possible interest
164abb0f93cSkardel  */
165abb0f93cSkardel volatile u_long packets_dropped;	/* total number of packets dropped on reception */
166abb0f93cSkardel volatile u_long packets_ignored;	/* packets received on wild card interface */
167abb0f93cSkardel volatile u_long packets_received;	/* total number of packets received */
168abb0f93cSkardel 	 u_long packets_sent;		/* total number of packets sent */
169abb0f93cSkardel 	 u_long packets_notsent;	/* total number of packets which couldn't be sent */
170abb0f93cSkardel 
171abb0f93cSkardel volatile u_long handler_calls;	/* number of calls to interrupt handler */
172abb0f93cSkardel volatile u_long handler_pkts;	/* number of pkts received by handler */
173abb0f93cSkardel u_long io_timereset;		/* time counters were reset */
174abb0f93cSkardel 
175abb0f93cSkardel /*
176abb0f93cSkardel  * Interface stuff
177abb0f93cSkardel  */
17845530cf1Skardel endpt *	any_interface;		/* wildcard ipv4 interface */
17945530cf1Skardel endpt *	any6_interface;		/* wildcard ipv6 interface */
18045530cf1Skardel endpt *	loopback_interface;	/* loopback ipv4 interface */
181abb0f93cSkardel 
182abb0f93cSkardel isc_boolean_t broadcast_client_enabled;	/* is broadcast client enabled */
183b3d6264cSchristos u_int sys_ifnum;			/* next .ifnum to assign */
184abb0f93cSkardel int ninterfaces;			/* Total number of interfaces */
185abb0f93cSkardel 
186abb0f93cSkardel int disable_dynamic_updates;		/* scan interfaces once only */
187abb0f93cSkardel 
188abb0f93cSkardel #ifdef REFCLOCK
189abb0f93cSkardel /*
190abb0f93cSkardel  * Refclock stuff.	We keep a chain of structures with data concerning
191abb0f93cSkardel  * the guys we are doing I/O for.
192abb0f93cSkardel  */
193abb0f93cSkardel static	struct refclockio *refio;
194abb0f93cSkardel #endif /* REFCLOCK */
195abb0f93cSkardel 
196abb0f93cSkardel /*
197abb0f93cSkardel  * File descriptor masks etc. for call to select
198b3d6264cSchristos  * Not needed for I/O Completion Ports or anything outside this file
199abb0f93cSkardel  */
200b3d6264cSchristos static fd_set activefds;
201b3d6264cSchristos static int maxactivefd;
202b3d6264cSchristos 
203abb0f93cSkardel /*
204abb0f93cSkardel  * bit alternating value to detect verified interfaces during an update cycle
205abb0f93cSkardel  */
206abb0f93cSkardel static  u_short		sys_interphase = 0;
207abb0f93cSkardel 
20845530cf1Skardel static endpt *	new_interface(endpt *);
20945530cf1Skardel static void	add_interface(endpt *);
21045530cf1Skardel static int	update_interfaces(u_short, interface_receiver_t,
21145530cf1Skardel 				  void *);
21245530cf1Skardel static void	remove_interface(endpt *);
21345530cf1Skardel static endpt *	create_interface(u_short, endpt *);
214abb0f93cSkardel 
21545530cf1Skardel static int	is_wildcard_addr	(const sockaddr_u *);
216abb0f93cSkardel 
217abb0f93cSkardel /*
218abb0f93cSkardel  * Multicast functions
219abb0f93cSkardel  */
220abb0f93cSkardel static	isc_boolean_t	addr_ismulticast	(sockaddr_u *);
22145530cf1Skardel static	isc_boolean_t	is_anycast		(sockaddr_u *,
22245530cf1Skardel 						 const char *);
22345530cf1Skardel 
224abb0f93cSkardel /*
225abb0f93cSkardel  * Not all platforms support multicast
226abb0f93cSkardel  */
227abb0f93cSkardel #ifdef MCAST
22845530cf1Skardel static	isc_boolean_t	socket_multicast_enable	(endpt *, sockaddr_u *);
22945530cf1Skardel static	isc_boolean_t	socket_multicast_disable(endpt *, sockaddr_u *);
230abb0f93cSkardel #endif
231abb0f93cSkardel 
232abb0f93cSkardel #ifdef DEBUG
23345530cf1Skardel static void interface_dump	(const endpt *);
23445530cf1Skardel static void sockaddr_dump	(const sockaddr_u *);
235f40817b7Skardel static void print_interface	(const endpt *, const char *, const char *);
236abb0f93cSkardel #define DPRINT_INTERFACE(level, args) do { if (debug >= (level)) { print_interface args; } } while (0)
237abb0f93cSkardel #else
238abb0f93cSkardel #define DPRINT_INTERFACE(level, args) do {} while (0)
239abb0f93cSkardel #endif
240abb0f93cSkardel 
241abb0f93cSkardel typedef struct vsock vsock_t;
242abb0f93cSkardel enum desc_type { FD_TYPE_SOCKET, FD_TYPE_FILE };
243abb0f93cSkardel 
244abb0f93cSkardel struct vsock {
245abb0f93cSkardel 	vsock_t	*	link;
246abb0f93cSkardel 	SOCKET		fd;
247abb0f93cSkardel 	enum desc_type	type;
248abb0f93cSkardel };
249abb0f93cSkardel 
250abb0f93cSkardel vsock_t	*fd_list;
251abb0f93cSkardel 
252abb0f93cSkardel #if !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET)
253abb0f93cSkardel /*
254abb0f93cSkardel  * async notification processing (e. g. routing sockets)
255abb0f93cSkardel  */
256abb0f93cSkardel /*
257abb0f93cSkardel  * support for receiving data on fd that is not a refclock or a socket
258abb0f93cSkardel  * like e. g. routing sockets
259abb0f93cSkardel  */
260abb0f93cSkardel struct asyncio_reader {
261abb0f93cSkardel 	struct asyncio_reader *link;		    /* the list this is being kept in */
262abb0f93cSkardel 	SOCKET fd;				    /* fd to be read */
263abb0f93cSkardel 	void  *data;				    /* possibly local data */
264abb0f93cSkardel 	void (*receiver)(struct asyncio_reader *);  /* input handler */
265abb0f93cSkardel };
266abb0f93cSkardel 
267abb0f93cSkardel struct asyncio_reader *asyncio_reader_list;
268abb0f93cSkardel 
269abb0f93cSkardel static void delete_asyncio_reader (struct asyncio_reader *);
270abb0f93cSkardel static struct asyncio_reader *new_asyncio_reader (void);
271abb0f93cSkardel static void add_asyncio_reader (struct asyncio_reader *, enum desc_type);
272abb0f93cSkardel static void remove_asyncio_reader (struct asyncio_reader *);
273abb0f93cSkardel 
274abb0f93cSkardel #endif /* !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) */
275abb0f93cSkardel 
276abb0f93cSkardel static void init_async_notifications (void);
277abb0f93cSkardel 
27845530cf1Skardel static	int	addr_eqprefix	(const sockaddr_u *, const sockaddr_u *,
27945530cf1Skardel 				 int);
28045530cf1Skardel static int	addr_samesubnet	(const sockaddr_u *, const sockaddr_u *,
28145530cf1Skardel 				 const sockaddr_u *, const sockaddr_u *);
282abb0f93cSkardel static	int	create_sockets	(u_short);
28345530cf1Skardel static	SOCKET	open_socket	(sockaddr_u *, int, int, endpt *);
284abb0f93cSkardel static	void	set_reuseaddr	(int);
285abb0f93cSkardel static	isc_boolean_t	socket_broadcast_enable	 (struct interface *, SOCKET, sockaddr_u *);
286335f7552Schristos 
287335f7552Schristos #if !defined(HAVE_IO_COMPLETION_PORT) && !defined(HAVE_SIGNALED_IO)
288335f7552Schristos static	char *	fdbits		(int, const fd_set *);
289335f7552Schristos #endif
290ad131110Schristos #ifdef  OS_MISSES_SPECIFIC_ROUTE_UPDATES
291abb0f93cSkardel static	isc_boolean_t	socket_broadcast_disable (struct interface *, sockaddr_u *);
292ad131110Schristos #endif
293abb0f93cSkardel 
294abb0f93cSkardel typedef struct remaddr remaddr_t;
295abb0f93cSkardel 
296abb0f93cSkardel struct remaddr {
297abb0f93cSkardel 	remaddr_t *		link;
298abb0f93cSkardel 	sockaddr_u		addr;
29945530cf1Skardel 	endpt *			ep;
300abb0f93cSkardel };
301abb0f93cSkardel 
302abb0f93cSkardel remaddr_t *	remoteaddr_list;
30345530cf1Skardel endpt *		ep_list;	/* complete endpt list */
30445530cf1Skardel endpt *		mc4_list;	/* IPv4 mcast-capable unicast endpts */
30545530cf1Skardel endpt *		mc6_list;	/* IPv6 mcast-capable unicast endpts */
306abb0f93cSkardel 
30745530cf1Skardel static endpt *	wildipv4;
30845530cf1Skardel static endpt *	wildipv6;
309abb0f93cSkardel 
310b3d6264cSchristos #ifdef SYS_WINNT
311b3d6264cSchristos int accept_wildcard_if_for_winnt;
312b3d6264cSchristos #else
313b3d6264cSchristos const int accept_wildcard_if_for_winnt = FALSE;
314b3d6264cSchristos #endif
315b3d6264cSchristos 
31645530cf1Skardel static void	add_fd_to_list		(SOCKET, enum desc_type);
31745530cf1Skardel static endpt *	find_addr_in_list	(sockaddr_u *);
31845530cf1Skardel static endpt *	find_flagged_addr_in_list(sockaddr_u *, u_int32);
319abb0f93cSkardel static void	delete_addr_from_list	(sockaddr_u *);
32045530cf1Skardel static void	delete_interface_from_list(endpt *);
321abb0f93cSkardel static void	close_and_delete_fd_from_list(SOCKET);
32245530cf1Skardel static void	add_addr_to_list	(sockaddr_u *, endpt *);
323abb0f93cSkardel static void	create_wildcards	(u_short);
32445530cf1Skardel static endpt *	findlocalinterface	(sockaddr_u *, int, int);
32545530cf1Skardel static endpt *	findclosestinterface	(sockaddr_u *, int);
326abb0f93cSkardel #ifdef DEBUG
327abb0f93cSkardel static const char *	action_text	(nic_rule_action);
328abb0f93cSkardel #endif
32945530cf1Skardel static nic_rule_action	interface_action(char *, sockaddr_u *, u_int32);
330abb0f93cSkardel static void		convert_isc_if	(isc_interface_t *,
33145530cf1Skardel 					 endpt *, u_short);
33245530cf1Skardel static void		calc_addr_distance(sockaddr_u *,
33345530cf1Skardel 					   const sockaddr_u *,
33445530cf1Skardel 					   const sockaddr_u *);
33545530cf1Skardel static int		cmp_addr_distance(const sockaddr_u *,
33645530cf1Skardel 					  const sockaddr_u *);
337abb0f93cSkardel 
338abb0f93cSkardel /*
339abb0f93cSkardel  * Routines to read the ntp packets
340abb0f93cSkardel  */
341abb0f93cSkardel #if !defined(HAVE_IO_COMPLETION_PORT)
342abb0f93cSkardel static inline int	read_network_packet	(SOCKET, struct interface *, l_fp);
343b3d6264cSchristos static void		ntpd_addremove_io_fd	(int, int, int);
344335f7552Schristos static void 		input_handler_scan	(const l_fp*, const fd_set*);
345335f7552Schristos static int/*BOOL*/	sanitize_fdset		(int errc);
346b3d6264cSchristos #ifdef REFCLOCK
347abb0f93cSkardel static inline int	read_refclock_packet	(SOCKET, struct refclockio *, l_fp);
348abb0f93cSkardel #endif
349335f7552Schristos #ifdef HAVE_SIGNALED_IO
350335f7552Schristos static void 		input_handler		(l_fp*);
351b3d6264cSchristos #endif
352335f7552Schristos #endif
353abb0f93cSkardel 
354b3d6264cSchristos 
355b3d6264cSchristos #ifndef HAVE_IO_COMPLETION_PORT
356abb0f93cSkardel void
357b3d6264cSchristos maintain_activefds(
358b3d6264cSchristos 	int fd,
359b3d6264cSchristos 	int closing
360abb0f93cSkardel 	)
361abb0f93cSkardel {
362b3d6264cSchristos 	int i;
363abb0f93cSkardel 
364b3d6264cSchristos 	if (fd < 0 || fd >= FD_SETSIZE) {
365abb0f93cSkardel 		msyslog(LOG_ERR,
366b3d6264cSchristos 			"Too many sockets in use, FD_SETSIZE %d exceeded by fd %d",
367b3d6264cSchristos 			FD_SETSIZE, fd);
368b3d6264cSchristos 		exit(1);
369abb0f93cSkardel 	}
370abb0f93cSkardel 
371b3d6264cSchristos 	if (!closing) {
372b3d6264cSchristos 		FD_SET(fd, &activefds);
373b3d6264cSchristos 		maxactivefd = max(fd, maxactivefd);
374abb0f93cSkardel 	} else {
375b3d6264cSchristos 		FD_CLR(fd, &activefds);
376b3d6264cSchristos 		if (maxactivefd && fd == maxactivefd) {
377b3d6264cSchristos 			for (i = maxactivefd - 1; i >= 0; i--)
378b3d6264cSchristos 				if (FD_ISSET(i, &activefds)) {
379b3d6264cSchristos 					maxactivefd = i;
380b3d6264cSchristos 					break;
381abb0f93cSkardel 				}
38209f14f80Schristos 			INSIST(fd != maxactivefd);
383abb0f93cSkardel 		}
384b3d6264cSchristos 	}
385b3d6264cSchristos }
386b3d6264cSchristos #endif	/* !HAVE_IO_COMPLETION_PORT */
387b3d6264cSchristos 
388abb0f93cSkardel 
389abb0f93cSkardel #ifdef DEBUG_TIMING
390abb0f93cSkardel /*
391abb0f93cSkardel  * collect timing information for various processing
392b3d6264cSchristos  * paths. currently we only pass them on to the file
393abb0f93cSkardel  * for later processing. this could also do histogram
394abb0f93cSkardel  * based analysis in other to reduce the load (and skew)
395abb0f93cSkardel  * dur to the file output
396abb0f93cSkardel  */
397abb0f93cSkardel void
398abb0f93cSkardel collect_timing(struct recvbuf *rb, const char *tag, int count, l_fp *dts)
399abb0f93cSkardel {
400abb0f93cSkardel 	char buf[256];
401abb0f93cSkardel 
402abb0f93cSkardel 	snprintf(buf, sizeof(buf), "%s %d %s %s",
403abb0f93cSkardel 		 (rb != NULL)
404abb0f93cSkardel 		     ? ((rb->dstadr != NULL)
405abb0f93cSkardel 			    ? stoa(&rb->recv_srcadr)
406abb0f93cSkardel 			    : "-REFCLOCK-")
407abb0f93cSkardel 		     : "-",
408abb0f93cSkardel 		 count, lfptoa(dts, 9), tag);
409abb0f93cSkardel 	record_timing_stats(buf);
410abb0f93cSkardel }
411abb0f93cSkardel #endif
412abb0f93cSkardel 
413abb0f93cSkardel /*
414abb0f93cSkardel  * About dynamic interfaces, sockets, reception and more...
415abb0f93cSkardel  *
416abb0f93cSkardel  * the code solves following tasks:
417abb0f93cSkardel  *
418abb0f93cSkardel  *   - keep a current list of active interfaces in order
419abb0f93cSkardel  *     to bind to to the interface address on NTP_PORT so that
420abb0f93cSkardel  *     all wild and specific bindings for NTP_PORT are taken by ntpd
421abb0f93cSkardel  *     to avoid other daemons messing with the time or sockets.
422abb0f93cSkardel  *   - all interfaces keep a list of peers that are referencing
423abb0f93cSkardel  *     the interface in order to quickly re-assign the peers to
424abb0f93cSkardel  *     new interface in case an interface is deleted (=> gone from system or
425abb0f93cSkardel  *     down)
426abb0f93cSkardel  *   - have a preconfigured socket ready with the right local address
427abb0f93cSkardel  *     for transmission and reception
428abb0f93cSkardel  *   - have an address list for all destination addresses used within ntpd
429abb0f93cSkardel  *     to find the "right" preconfigured socket.
430abb0f93cSkardel  *   - facilitate updating the internal interface list with respect to
431abb0f93cSkardel  *     the current kernel state
432abb0f93cSkardel  *
433abb0f93cSkardel  * special issues:
434abb0f93cSkardel  *
435abb0f93cSkardel  *   - mapping of multicast addresses to the interface affected is not always
436abb0f93cSkardel  *     one to one - especially on hosts with multiple interfaces
437abb0f93cSkardel  *     the code here currently allocates a separate interface entry for those
438abb0f93cSkardel  *     multicast addresses
439abb0f93cSkardel  *     iff it is able to bind to a *new* socket with the multicast address (flags |= MCASTIF)
440abb0f93cSkardel  *     in case of failure the multicast address is bound to an existing interface.
441abb0f93cSkardel  *   - on some systems it is perfectly legal to assign the same address to
442abb0f93cSkardel  *     multiple interfaces. Therefore this code does not keep a list of interfaces
443abb0f93cSkardel  *     but a list of interfaces that represent a unique address as determined by the kernel
444abb0f93cSkardel  *     by the procedure in findlocalinterface. Thus it is perfectly legal to see only
445abb0f93cSkardel  *     one representative of a group of real interfaces if they share the same address.
446abb0f93cSkardel  *
447abb0f93cSkardel  * Frank Kardel 20050910
448abb0f93cSkardel  */
449abb0f93cSkardel 
450abb0f93cSkardel /*
451b3d6264cSchristos  * init_io - initialize I/O module.
452abb0f93cSkardel  */
453abb0f93cSkardel void
454abb0f93cSkardel init_io(void)
455abb0f93cSkardel {
456b3d6264cSchristos 	/* Init buffer free list and stat counters */
457abb0f93cSkardel 	init_recvbuff(RECV_INIT);
458b3d6264cSchristos 	/* update interface every 5 minutes as default */
459b3d6264cSchristos 	interface_interval = 300;
460b3d6264cSchristos 
461b3d6264cSchristos #ifdef WORK_PIPE
462b3d6264cSchristos 	addremove_io_fd = &ntpd_addremove_io_fd;
463b3d6264cSchristos #endif
464abb0f93cSkardel 
465335f7552Schristos #if defined(SYS_WINNT)
466abb0f93cSkardel 	init_io_completion_port();
467335f7552Schristos #elif defined(HAVE_SIGNALED_IO)
468b3d6264cSchristos 	(void) set_signal(input_handler);
469abb0f93cSkardel #endif
470abb0f93cSkardel }
471abb0f93cSkardel 
472abb0f93cSkardel 
473b3d6264cSchristos static void
474b3d6264cSchristos ntpd_addremove_io_fd(
475b3d6264cSchristos 	int	fd,
476b3d6264cSchristos 	int	is_pipe,
477b3d6264cSchristos 	int	remove_it
478b3d6264cSchristos 	)
479b3d6264cSchristos {
480b3d6264cSchristos 	UNUSED_ARG(is_pipe);
481b3d6264cSchristos 
482b3d6264cSchristos #ifdef HAVE_SIGNALED_IO
483335f7552Schristos 	if (!remove_it)
484b3d6264cSchristos 		init_socket_sig(fd);
485b3d6264cSchristos #endif /* not HAVE_SIGNALED_IO */
486b3d6264cSchristos 
487b3d6264cSchristos 	maintain_activefds(fd, remove_it);
488b3d6264cSchristos }
489b3d6264cSchristos 
490b3d6264cSchristos 
491abb0f93cSkardel /*
492abb0f93cSkardel  * io_open_sockets - call socket creation routine
493abb0f93cSkardel  */
494abb0f93cSkardel void
495abb0f93cSkardel io_open_sockets(void)
496abb0f93cSkardel {
497abb0f93cSkardel 	static int already_opened;
498abb0f93cSkardel 
499abb0f93cSkardel 	if (already_opened || HAVE_OPT( SAVECONFIGQUIT ))
500abb0f93cSkardel 		return;
501abb0f93cSkardel 
502abb0f93cSkardel 	already_opened = 1;
503abb0f93cSkardel 
504abb0f93cSkardel 	/*
505abb0f93cSkardel 	 * Create the sockets
506abb0f93cSkardel 	 */
507abb0f93cSkardel 	BLOCKIO();
508abb0f93cSkardel 	create_sockets(NTP_PORT);
509abb0f93cSkardel 	UNBLOCKIO();
510abb0f93cSkardel 
511abb0f93cSkardel 	init_async_notifications();
512abb0f93cSkardel 
513abb0f93cSkardel 	DPRINTF(3, ("io_open_sockets: maxactivefd %d\n", maxactivefd));
514abb0f93cSkardel }
515abb0f93cSkardel 
516abb0f93cSkardel 
517abb0f93cSkardel #ifdef DEBUG
518abb0f93cSkardel /*
519abb0f93cSkardel  * function to dump the contents of the interface structure
520abb0f93cSkardel  * for debugging use only.
521*1c24ec91Schristos  * We face a dilemma here -- sockets are FDs under POSIX and
522*1c24ec91Schristos  * actually HANDLES under Windows. So we use '%lld' as format
523*1c24ec91Schristos  * and cast the value to 'long long'; this should not hurt
524*1c24ec91Schristos  * with UNIX-like systems and does not truncate values on Win64.
525abb0f93cSkardel  */
526abb0f93cSkardel void
52745530cf1Skardel interface_dump(const endpt *itf)
528abb0f93cSkardel {
529abb0f93cSkardel 	printf("Dumping interface: %p\n", itf);
530*1c24ec91Schristos 	printf("fd = %lld\n", (long long)itf->fd);
531*1c24ec91Schristos 	printf("bfd = %lld\n", (long long)itf->bfd);
532abb0f93cSkardel 	printf("sin = %s,\n", stoa(&itf->sin));
533abb0f93cSkardel 	sockaddr_dump(&itf->sin);
534abb0f93cSkardel 	printf("bcast = %s,\n", stoa(&itf->bcast));
535abb0f93cSkardel 	sockaddr_dump(&itf->bcast);
536abb0f93cSkardel 	printf("mask = %s,\n", stoa(&itf->mask));
537abb0f93cSkardel 	sockaddr_dump(&itf->mask);
538abb0f93cSkardel 	printf("name = %s\n", itf->name);
539abb0f93cSkardel 	printf("flags = 0x%08x\n", itf->flags);
540abb0f93cSkardel 	printf("last_ttl = %d\n", itf->last_ttl);
541abb0f93cSkardel 	printf("addr_refid = %08x\n", itf->addr_refid);
542abb0f93cSkardel 	printf("num_mcast = %d\n", itf->num_mcast);
543abb0f93cSkardel 	printf("received = %ld\n", itf->received);
544abb0f93cSkardel 	printf("sent = %ld\n", itf->sent);
545abb0f93cSkardel 	printf("notsent = %ld\n", itf->notsent);
54645530cf1Skardel 	printf("ifindex = %u\n", itf->ifindex);
547abb0f93cSkardel 	printf("peercnt = %u\n", itf->peercnt);
548abb0f93cSkardel 	printf("phase = %u\n", itf->phase);
549abb0f93cSkardel }
550abb0f93cSkardel 
551abb0f93cSkardel /*
552abb0f93cSkardel  * sockaddr_dump - hex dump the start of a sockaddr_u
553abb0f93cSkardel  */
554abb0f93cSkardel static void
55545530cf1Skardel sockaddr_dump(const sockaddr_u *psau)
556abb0f93cSkardel {
557b3d6264cSchristos 	/* Limit the size of the sockaddr_in6 hex dump */
55845530cf1Skardel 	const int maxsize = min(32, sizeof(psau->sa6));
55945530cf1Skardel 	const u_char *	cp;
560abb0f93cSkardel 	int		i;
561abb0f93cSkardel 
562b3d6264cSchristos 	/* XXX: Should we limit maxsize based on psau->saX.sin_family? */
563b3d6264cSchristos 	cp = (const void *)&psau->sa6;
564abb0f93cSkardel 
56545530cf1Skardel 	for(i = 0; i < maxsize; i++) {
566abb0f93cSkardel 		printf("%02x", *cp++);
567abb0f93cSkardel 		if (!((i + 1) % 4))
568abb0f93cSkardel 			printf(" ");
569abb0f93cSkardel 	}
570abb0f93cSkardel 	printf("\n");
571abb0f93cSkardel }
572abb0f93cSkardel 
573abb0f93cSkardel /*
574abb0f93cSkardel  * print_interface - helper to output debug information
575abb0f93cSkardel  */
576abb0f93cSkardel static void
577f40817b7Skardel print_interface(const endpt *iface, const char *pfx, const char *sfx)
578abb0f93cSkardel {
579*1c24ec91Schristos 	printf("%sinterface #%d: fd=%lld, bfd=%lld, name=%s, flags=0x%x, ifindex=%u, sin=%s",
580abb0f93cSkardel 	       pfx,
581abb0f93cSkardel 	       iface->ifnum,
582*1c24ec91Schristos 	       (long long)iface->fd,
583*1c24ec91Schristos 	       (long long)iface->bfd,
584abb0f93cSkardel 	       iface->name,
585abb0f93cSkardel 	       iface->flags,
58645530cf1Skardel 	       iface->ifindex,
587abb0f93cSkardel 	       stoa(&iface->sin));
588abb0f93cSkardel 	if (AF_INET == iface->family) {
589abb0f93cSkardel 		if (iface->flags & INT_BROADCAST)
590abb0f93cSkardel 			printf(", bcast=%s", stoa(&iface->bcast));
591abb0f93cSkardel 		printf(", mask=%s", stoa(&iface->mask));
592abb0f93cSkardel 	}
593abb0f93cSkardel 	printf(", %s:%s",
594abb0f93cSkardel 	       (iface->ignore_packets)
595abb0f93cSkardel 		   ? "Disabled"
596abb0f93cSkardel 		   : "Enabled",
597abb0f93cSkardel 	       sfx);
598abb0f93cSkardel 	if (debug > 4)	/* in-depth debugging only */
599abb0f93cSkardel 		interface_dump(iface);
600abb0f93cSkardel }
601abb0f93cSkardel #endif
602abb0f93cSkardel 
603abb0f93cSkardel #if !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET)
604abb0f93cSkardel /*
605abb0f93cSkardel  * create an asyncio_reader structure
606abb0f93cSkardel  */
607abb0f93cSkardel static struct asyncio_reader *
608abb0f93cSkardel new_asyncio_reader(void)
609abb0f93cSkardel {
610abb0f93cSkardel 	struct asyncio_reader *reader;
611abb0f93cSkardel 
612b3d6264cSchristos 	reader = emalloc_zero(sizeof(*reader));
613abb0f93cSkardel 	reader->fd = INVALID_SOCKET;
614b3d6264cSchristos 
615abb0f93cSkardel 	return reader;
616abb0f93cSkardel }
617abb0f93cSkardel 
618abb0f93cSkardel /*
619abb0f93cSkardel  * delete a reader
620abb0f93cSkardel  */
621abb0f93cSkardel static void
622abb0f93cSkardel delete_asyncio_reader(
623abb0f93cSkardel 	struct asyncio_reader *reader
624abb0f93cSkardel 	)
625abb0f93cSkardel {
626abb0f93cSkardel 	free(reader);
627abb0f93cSkardel }
628abb0f93cSkardel 
629abb0f93cSkardel /*
630abb0f93cSkardel  * add asynchio_reader
631abb0f93cSkardel  */
632abb0f93cSkardel static void
633abb0f93cSkardel add_asyncio_reader(
634abb0f93cSkardel 	struct asyncio_reader *	reader,
635abb0f93cSkardel 	enum desc_type		type)
636abb0f93cSkardel {
637abb0f93cSkardel 	LINK_SLIST(asyncio_reader_list, reader, link);
638abb0f93cSkardel 	add_fd_to_list(reader->fd, type);
639abb0f93cSkardel }
640abb0f93cSkardel 
641abb0f93cSkardel /*
642abb0f93cSkardel  * remove asynchio_reader
643abb0f93cSkardel  */
644abb0f93cSkardel static void
645abb0f93cSkardel remove_asyncio_reader(
646abb0f93cSkardel 	struct asyncio_reader *reader
647abb0f93cSkardel 	)
648abb0f93cSkardel {
649abb0f93cSkardel 	struct asyncio_reader *unlinked;
650abb0f93cSkardel 
651abb0f93cSkardel 	UNLINK_SLIST(unlinked, asyncio_reader_list, reader, link,
652abb0f93cSkardel 	    struct asyncio_reader);
653abb0f93cSkardel 
654abb0f93cSkardel 	if (reader->fd != INVALID_SOCKET)
655abb0f93cSkardel 		close_and_delete_fd_from_list(reader->fd);
656abb0f93cSkardel 
657abb0f93cSkardel 	reader->fd = INVALID_SOCKET;
658abb0f93cSkardel }
659abb0f93cSkardel #endif /* !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) */
660abb0f93cSkardel 
66145530cf1Skardel 
66245530cf1Skardel /* compare two sockaddr prefixes */
66345530cf1Skardel static int
66445530cf1Skardel addr_eqprefix(
66545530cf1Skardel 	const sockaddr_u *	a,
66645530cf1Skardel 	const sockaddr_u *	b,
66745530cf1Skardel 	int			prefixlen
66845530cf1Skardel 	)
66945530cf1Skardel {
67045530cf1Skardel 	isc_netaddr_t		isc_a;
67145530cf1Skardel 	isc_netaddr_t		isc_b;
67245530cf1Skardel 	isc_sockaddr_t		isc_sa;
67345530cf1Skardel 
674b3d6264cSchristos 	ZERO(isc_sa);
675b3d6264cSchristos 	memcpy(&isc_sa.type, a, min(sizeof(isc_sa.type), sizeof(*a)));
67645530cf1Skardel 	isc_netaddr_fromsockaddr(&isc_a, &isc_sa);
67745530cf1Skardel 
678b3d6264cSchristos 	ZERO(isc_sa);
679b3d6264cSchristos 	memcpy(&isc_sa.type, b, min(sizeof(isc_sa.type), sizeof(*b)));
68045530cf1Skardel 	isc_netaddr_fromsockaddr(&isc_b, &isc_sa);
68145530cf1Skardel 
68245530cf1Skardel 	return (int)isc_netaddr_eqprefix(&isc_a, &isc_b,
68345530cf1Skardel 					 (u_int)prefixlen);
68445530cf1Skardel }
68545530cf1Skardel 
68645530cf1Skardel 
68745530cf1Skardel static int
68845530cf1Skardel addr_samesubnet(
68945530cf1Skardel 	const sockaddr_u *	a,
69045530cf1Skardel 	const sockaddr_u *	a_mask,
69145530cf1Skardel 	const sockaddr_u *	b,
69245530cf1Skardel 	const sockaddr_u *	b_mask
69345530cf1Skardel 	)
69445530cf1Skardel {
69545530cf1Skardel 	const u_int32 *	pa;
69645530cf1Skardel 	const u_int32 *	pa_limit;
69745530cf1Skardel 	const u_int32 *	pb;
69845530cf1Skardel 	const u_int32 *	pm;
69945530cf1Skardel 	size_t		loops;
70045530cf1Skardel 
70109f14f80Schristos 	REQUIRE(AF(a) == AF(a_mask));
70209f14f80Schristos 	REQUIRE(AF(b) == AF(b_mask));
70345530cf1Skardel 	/*
70445530cf1Skardel 	 * With address and mask families verified to match, comparing
70545530cf1Skardel 	 * the masks also validates the address's families match.
70645530cf1Skardel 	 */
70745530cf1Skardel 	if (!SOCK_EQ(a_mask, b_mask))
70845530cf1Skardel 		return FALSE;
70945530cf1Skardel 
71045530cf1Skardel 	if (IS_IPV6(a)) {
71145530cf1Skardel 		loops = sizeof(NSRCADR6(a)) / sizeof(*pa);
71245530cf1Skardel 		pa = (const void *)&NSRCADR6(a);
71345530cf1Skardel 		pb = (const void *)&NSRCADR6(b);
71445530cf1Skardel 		pm = (const void *)&NSRCADR6(a_mask);
71545530cf1Skardel 	} else {
71645530cf1Skardel 		loops = sizeof(NSRCADR(a)) / sizeof(*pa);
71745530cf1Skardel 		pa = (const void *)&NSRCADR(a);
71845530cf1Skardel 		pb = (const void *)&NSRCADR(b);
71945530cf1Skardel 		pm = (const void *)&NSRCADR(a_mask);
72045530cf1Skardel 	}
72145530cf1Skardel 	for (pa_limit = pa + loops; pa < pa_limit; pa++, pb++, pm++)
72245530cf1Skardel 		if ((*pa & *pm) != (*pb & *pm))
72345530cf1Skardel 			return FALSE;
72445530cf1Skardel 
72545530cf1Skardel 	return TRUE;
72645530cf1Skardel }
72745530cf1Skardel 
72845530cf1Skardel 
729abb0f93cSkardel /*
730abb0f93cSkardel  * interface list enumerator - visitor pattern
731abb0f93cSkardel  */
732abb0f93cSkardel void
733abb0f93cSkardel interface_enumerate(
734abb0f93cSkardel 	interface_receiver_t	receiver,
735abb0f93cSkardel 	void *			data
736abb0f93cSkardel 	)
737abb0f93cSkardel {
738abb0f93cSkardel 	interface_info_t ifi;
739abb0f93cSkardel 
740abb0f93cSkardel 	ifi.action = IFS_EXISTS;
74145530cf1Skardel 	for (ifi.ep = ep_list; ifi.ep != NULL; ifi.ep = ifi.ep->elink)
742abb0f93cSkardel 		(*receiver)(data, &ifi);
743abb0f93cSkardel }
744abb0f93cSkardel 
745abb0f93cSkardel /*
746abb0f93cSkardel  * do standard initialization of interface structure
747abb0f93cSkardel  */
748abb0f93cSkardel static void
749abb0f93cSkardel init_interface(
75045530cf1Skardel 	endpt *ep
751abb0f93cSkardel 	)
752abb0f93cSkardel {
753b3d6264cSchristos 	ZERO(*ep);
75445530cf1Skardel 	ep->fd = INVALID_SOCKET;
75545530cf1Skardel 	ep->bfd = INVALID_SOCKET;
75645530cf1Skardel 	ep->phase = sys_interphase;
757abb0f93cSkardel }
758abb0f93cSkardel 
759abb0f93cSkardel 
760abb0f93cSkardel /*
761abb0f93cSkardel  * create new interface structure initialize from
762abb0f93cSkardel  * template structure or via standard initialization
763abb0f93cSkardel  * function
764abb0f93cSkardel  */
765abb0f93cSkardel static struct interface *
766abb0f93cSkardel new_interface(
767abb0f93cSkardel 	struct interface *interface
768abb0f93cSkardel 	)
769abb0f93cSkardel {
770abb0f93cSkardel 	struct interface *	iface;
771abb0f93cSkardel 
772abb0f93cSkardel 	iface = emalloc(sizeof(*iface));
773abb0f93cSkardel 
774abb0f93cSkardel 	if (NULL == interface)
775abb0f93cSkardel 		init_interface(iface);
776abb0f93cSkardel 	else				/* use the template */
777abb0f93cSkardel 		memcpy(iface, interface, sizeof(*iface));
778abb0f93cSkardel 
779abb0f93cSkardel 	/* count every new instance of an interface in the system */
780abb0f93cSkardel 	iface->ifnum = sys_ifnum++;
781abb0f93cSkardel 	iface->starttime = current_time;
782abb0f93cSkardel 
783335f7552Schristos #   ifdef HAVE_IO_COMPLETION_PORT
784335f7552Schristos 	if (!io_completion_port_add_interface(iface)) {
785335f7552Schristos 		msyslog(LOG_EMERG, "cannot register interface with IO engine -- will exit now");
786335f7552Schristos 		exit(1);
787335f7552Schristos 	}
788335f7552Schristos #   endif
789abb0f93cSkardel 	return iface;
790abb0f93cSkardel }
791abb0f93cSkardel 
792abb0f93cSkardel 
793abb0f93cSkardel /*
794abb0f93cSkardel  * return interface storage into free memory pool
795abb0f93cSkardel  */
796335f7552Schristos static void
797abb0f93cSkardel delete_interface(
79845530cf1Skardel 	endpt *ep
799abb0f93cSkardel 	)
800abb0f93cSkardel {
801335f7552Schristos #    ifdef HAVE_IO_COMPLETION_PORT
802335f7552Schristos 	io_completion_port_remove_interface(ep);
803335f7552Schristos #    endif
80445530cf1Skardel 	free(ep);
805abb0f93cSkardel }
806abb0f93cSkardel 
807abb0f93cSkardel 
808abb0f93cSkardel /*
809abb0f93cSkardel  * link interface into list of known interfaces
810abb0f93cSkardel  */
811abb0f93cSkardel static void
812abb0f93cSkardel add_interface(
81345530cf1Skardel 	endpt *	ep
814abb0f93cSkardel 	)
815abb0f93cSkardel {
81645530cf1Skardel 	endpt **	pmclisthead;
81745530cf1Skardel 	endpt *		scan;
81845530cf1Skardel 	endpt *		scan_next;
81945530cf1Skardel 	endpt *		unlinked;
82045530cf1Skardel 	sockaddr_u *	addr;
82145530cf1Skardel 	int		ep_local;
82245530cf1Skardel 	int		scan_local;
82345530cf1Skardel 	int		same_subnet;
82445530cf1Skardel 	int		ep_univ_iid;	/* iface ID from MAC address */
82545530cf1Skardel 	int		scan_univ_iid;	/* see RFC 4291 */
82645530cf1Skardel 	int		ep_privacy;	/* random local iface ID */
82745530cf1Skardel 	int		scan_privacy;	/* see RFC 4941 */
82845530cf1Skardel 	int		rc;
82945530cf1Skardel 
830b3d6264cSchristos 	/* Calculate the refid */
83145530cf1Skardel 	ep->addr_refid = addr2refid(&ep->sin);
832b3d6264cSchristos 	/* link at tail so ntpdc -c ifstats index increases each row */
833b3d6264cSchristos 	LINK_TAIL_SLIST(ep_list, ep, elink, endpt);
834abb0f93cSkardel 	ninterfaces++;
83545530cf1Skardel #ifdef MCAST
83645530cf1Skardel 	/* the rest is for enabled multicast-capable addresses only */
83745530cf1Skardel 	if (ep->ignore_packets || !(INT_MULTICAST & ep->flags) ||
83845530cf1Skardel 	    INT_LOOPBACK & ep->flags)
83945530cf1Skardel 		return;
84045530cf1Skardel # ifndef INCLUDE_IPV6_MULTICAST_SUPPORT
84145530cf1Skardel 	if (AF_INET6 == ep->family)
84245530cf1Skardel 		return;
84345530cf1Skardel # endif
84445530cf1Skardel 	pmclisthead = (AF_INET == ep->family)
84545530cf1Skardel 			 ? &mc4_list
84645530cf1Skardel 			 : &mc6_list;
84745530cf1Skardel 
84845530cf1Skardel 	if (AF_INET6 == ep->family) {
84945530cf1Skardel 		ep_local =
85045530cf1Skardel 		    IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(&ep->sin)) ||
85145530cf1Skardel 		    IN6_IS_ADDR_SITELOCAL(PSOCK_ADDR6(&ep->sin));
85245530cf1Skardel 		ep_univ_iid = IS_IID_UNIV(&ep->sin);
85345530cf1Skardel 		ep_privacy = !!(INT_PRIVACY & ep->flags);
85445530cf1Skardel 	} else {
85545530cf1Skardel 		ep_local = FALSE;
85645530cf1Skardel 		ep_univ_iid = FALSE;
85745530cf1Skardel 		ep_privacy = FALSE;
85845530cf1Skardel 	}
85945530cf1Skardel 	DPRINTF(4, ("add_interface mcast-capable %s%s%s%s\n",
86045530cf1Skardel 		    stoa(&ep->sin),
86145530cf1Skardel 		    (ep_local) ? " link/scope-local" : "",
86245530cf1Skardel 		    (ep_univ_iid) ? " univ-IID" : "",
86345530cf1Skardel 		    (ep_privacy) ? " privacy" : ""));
86445530cf1Skardel 	/*
86545530cf1Skardel 	 * If we have multiple local addresses on the same network
86645530cf1Skardel 	 * interface, and some are link- or site-local, do not multicast
86745530cf1Skardel 	 * out from the link-/site-local addresses by default, to avoid
86845530cf1Skardel 	 * duplicate manycastclient associations between v6 peers using
86945530cf1Skardel 	 * link-local and global addresses.  link-local can still be
87045530cf1Skardel 	 * chosen using "nic ignore myv6globalprefix::/64".
87145530cf1Skardel 	 * Similarly, if we have multiple global addresses from the same
87245530cf1Skardel 	 * prefix on the same network interface, multicast from one,
87345530cf1Skardel 	 * preferring EUI-64, then static, then least RFC 4941 privacy
87445530cf1Skardel 	 * addresses.
87545530cf1Skardel 	 */
87645530cf1Skardel 	for (scan = *pmclisthead; scan != NULL; scan = scan_next) {
87745530cf1Skardel 		scan_next = scan->mclink;
87845530cf1Skardel 		if (ep->family != scan->family)
87945530cf1Skardel 			continue;
88045530cf1Skardel 		if (strcmp(ep->name, scan->name))
88145530cf1Skardel 			continue;
88245530cf1Skardel 		same_subnet = addr_samesubnet(&ep->sin, &ep->mask,
88345530cf1Skardel 					      &scan->sin, &scan->mask);
88445530cf1Skardel 		if (AF_INET6 == ep->family) {
88545530cf1Skardel 			addr = &scan->sin;
88645530cf1Skardel 			scan_local =
88745530cf1Skardel 			    IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(addr)) ||
88845530cf1Skardel 			    IN6_IS_ADDR_SITELOCAL(PSOCK_ADDR6(addr));
88945530cf1Skardel 			scan_univ_iid = IS_IID_UNIV(addr);
89045530cf1Skardel 			scan_privacy = !!(INT_PRIVACY & scan->flags);
89145530cf1Skardel 		} else {
89245530cf1Skardel 			scan_local = FALSE;
89345530cf1Skardel 			scan_univ_iid = FALSE;
89445530cf1Skardel 			scan_privacy = FALSE;
89545530cf1Skardel 		}
89645530cf1Skardel 		DPRINTF(4, ("add_interface mcast-capable scan %s%s%s%s\n",
89745530cf1Skardel 			    stoa(&scan->sin),
89845530cf1Skardel 			    (scan_local) ? " link/scope-local" : "",
89945530cf1Skardel 			    (scan_univ_iid) ? " univ-IID" : "",
90045530cf1Skardel 			    (scan_privacy) ? " privacy" : ""));
90145530cf1Skardel 		if ((ep_local && !scan_local) || (same_subnet &&
90245530cf1Skardel 		    ((ep_privacy && !scan_privacy) ||
90345530cf1Skardel 		     (!ep_univ_iid && scan_univ_iid)))) {
90445530cf1Skardel 			DPRINTF(4, ("did not add %s to %s of IPv6 multicast-capable list which already has %s\n",
90545530cf1Skardel 				stoa(&ep->sin),
90645530cf1Skardel 				(ep_local)
90745530cf1Skardel 				    ? "tail"
90845530cf1Skardel 				    : "head",
90945530cf1Skardel 				stoa(&scan->sin)));
91045530cf1Skardel 			return;
91145530cf1Skardel 		}
91245530cf1Skardel 		if ((scan_local && !ep_local) || (same_subnet &&
91345530cf1Skardel 		    ((scan_privacy && !ep_privacy) ||
91445530cf1Skardel 		     (!scan_univ_iid && ep_univ_iid)))) {
91545530cf1Skardel 			UNLINK_SLIST(unlinked, *pmclisthead,
91645530cf1Skardel 				     scan, mclink, endpt);
91745530cf1Skardel 			DPRINTF(4, ("%s %s from IPv6 multicast-capable list to add %s\n",
91845530cf1Skardel 				(unlinked != scan)
91945530cf1Skardel 				    ? "Failed to remove"
92045530cf1Skardel 				    : "removed",
92145530cf1Skardel 				stoa(&scan->sin), stoa(&ep->sin)));
92245530cf1Skardel 		}
92345530cf1Skardel 	}
92445530cf1Skardel 	/*
92545530cf1Skardel 	 * Add link/site local at the tail of the multicast-
92645530cf1Skardel 	 * capable unicast interfaces list, so that ntpd will
92745530cf1Skardel 	 * send from global addresses before link-/site-local
92845530cf1Skardel 	 * ones.
92945530cf1Skardel 	 */
93045530cf1Skardel 	if (ep_local)
93145530cf1Skardel 		LINK_TAIL_SLIST(*pmclisthead, ep, mclink, endpt);
93245530cf1Skardel 	else
93345530cf1Skardel 		LINK_SLIST(*pmclisthead, ep, mclink);
93445530cf1Skardel 	DPRINTF(4, ("added %s to %s of IPv%s multicast-capable unicast local address list\n",
93545530cf1Skardel 		stoa(&ep->sin),
93645530cf1Skardel 		(ep_local)
93745530cf1Skardel 		    ? "tail"
93845530cf1Skardel 		    : "head",
93945530cf1Skardel 		(AF_INET == ep->family)
94045530cf1Skardel 		    ? "4"
94145530cf1Skardel 		    : "6"));
94245530cf1Skardel 
943b3d6264cSchristos 	if (INVALID_SOCKET == ep->fd)
944b3d6264cSchristos 		return;
945b3d6264cSchristos 
94645530cf1Skardel 	/*
94745530cf1Skardel 	 * select the local address from which to send to multicast.
94845530cf1Skardel 	 */
94945530cf1Skardel 	switch (AF(&ep->sin)) {
950b3d6264cSchristos 
95145530cf1Skardel 	case AF_INET :
95245530cf1Skardel 		rc = setsockopt(ep->fd, IPPROTO_IP,
95345530cf1Skardel 				IP_MULTICAST_IF,
95445530cf1Skardel 				(void *)&NSRCADR(&ep->sin),
95545530cf1Skardel 				sizeof(NSRCADR(&ep->sin)));
95645530cf1Skardel 		if (rc)
95745530cf1Skardel 			msyslog(LOG_ERR,
95845530cf1Skardel 				"setsockopt IP_MULTICAST_IF %s fails: %m",
95945530cf1Skardel 				stoa(&ep->sin));
96045530cf1Skardel 		break;
961b3d6264cSchristos 
96245530cf1Skardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
96345530cf1Skardel 	case AF_INET6 :
96445530cf1Skardel 		rc = setsockopt(ep->fd, IPPROTO_IPV6,
96545530cf1Skardel 				 IPV6_MULTICAST_IF,
96645530cf1Skardel 				 (void *)&ep->ifindex,
96745530cf1Skardel 				 sizeof(ep->ifindex));
968b3d6264cSchristos 		/* do not complain if bound addr scope is ifindex */
969b3d6264cSchristos 		if (rc && ep->ifindex != SCOPE(&ep->sin))
97045530cf1Skardel 			msyslog(LOG_ERR,
97145530cf1Skardel 				"setsockopt IPV6_MULTICAST_IF %u for %s fails: %m",
97245530cf1Skardel 				ep->ifindex, stoa(&ep->sin));
97345530cf1Skardel 		break;
97445530cf1Skardel # endif
97545530cf1Skardel 	}
97645530cf1Skardel #endif	/* MCAST */
977abb0f93cSkardel }
978abb0f93cSkardel 
979abb0f93cSkardel 
980abb0f93cSkardel /*
981abb0f93cSkardel  * remove interface from known interface list and clean up
982abb0f93cSkardel  * associated resources
983abb0f93cSkardel  */
984abb0f93cSkardel static void
985abb0f93cSkardel remove_interface(
98645530cf1Skardel 	endpt *	ep
987abb0f93cSkardel 	)
988abb0f93cSkardel {
98945530cf1Skardel 	endpt *		unlinked;
99045530cf1Skardel 	endpt **	pmclisthead;
991abb0f93cSkardel 	sockaddr_u	resmask;
992abb0f93cSkardel 
99345530cf1Skardel 	UNLINK_SLIST(unlinked, ep_list, ep, elink, endpt);
99445530cf1Skardel 	if (!ep->ignore_packets && INT_MULTICAST & ep->flags) {
99545530cf1Skardel 		pmclisthead = (AF_INET == ep->family)
99645530cf1Skardel 				 ? &mc4_list
99745530cf1Skardel 				 : &mc6_list;
99845530cf1Skardel 		UNLINK_SLIST(unlinked, *pmclisthead, ep, mclink, endpt);
99945530cf1Skardel 		DPRINTF(4, ("%s %s IPv%s multicast-capable unicast local address list\n",
100045530cf1Skardel 			stoa(&ep->sin),
100145530cf1Skardel 			(unlinked != NULL)
100245530cf1Skardel 			    ? "removed from"
100345530cf1Skardel 			    : "not found on",
100445530cf1Skardel 			(AF_INET == ep->family)
100545530cf1Skardel 			    ? "4"
100645530cf1Skardel 			    : "6"));
100745530cf1Skardel 	}
100845530cf1Skardel 	delete_interface_from_list(ep);
1009abb0f93cSkardel 
101045530cf1Skardel 	if (ep->fd != INVALID_SOCKET) {
1011abb0f93cSkardel 		msyslog(LOG_INFO,
1012abb0f93cSkardel 			"Deleting interface #%d %s, %s#%d, interface stats: received=%ld, sent=%ld, dropped=%ld, active_time=%ld secs",
101345530cf1Skardel 			ep->ifnum,
101445530cf1Skardel 			ep->name,
101545530cf1Skardel 			stoa(&ep->sin),
101645530cf1Skardel 			SRCPORT(&ep->sin),
101745530cf1Skardel 			ep->received,
101845530cf1Skardel 			ep->sent,
101945530cf1Skardel 			ep->notsent,
102045530cf1Skardel 			current_time - ep->starttime);
1021335f7552Schristos #	    ifdef HAVE_IO_COMPLETION_PORT
1022335f7552Schristos 		io_completion_port_remove_socket(ep->fd, ep);
1023335f7552Schristos #	    endif
102445530cf1Skardel 		close_and_delete_fd_from_list(ep->fd);
1025b3d6264cSchristos 		ep->fd = INVALID_SOCKET;
1026abb0f93cSkardel 	}
1027abb0f93cSkardel 
102845530cf1Skardel 	if (ep->bfd != INVALID_SOCKET) {
1029abb0f93cSkardel 		msyslog(LOG_INFO,
1030b3d6264cSchristos 			"stop listening for broadcasts to %s on interface #%d %s",
1031b3d6264cSchristos 			stoa(&ep->bcast), ep->ifnum, ep->name);
1032335f7552Schristos #	    ifdef HAVE_IO_COMPLETION_PORT
1033335f7552Schristos 		io_completion_port_remove_socket(ep->bfd, ep);
1034335f7552Schristos #	    endif
103545530cf1Skardel 		close_and_delete_fd_from_list(ep->bfd);
1036b3d6264cSchristos 		ep->bfd = INVALID_SOCKET;
1037abb0f93cSkardel 	}
1038335f7552Schristos #   ifdef HAVE_IO_COMPLETION_PORT
1039335f7552Schristos 	io_completion_port_remove_interface(ep);
1040335f7552Schristos #   endif
1041abb0f93cSkardel 
1042abb0f93cSkardel 	ninterfaces--;
1043b3d6264cSchristos 	mon_clearinterface(ep);
1044abb0f93cSkardel 
1045abb0f93cSkardel 	/* remove restrict interface entry */
104645530cf1Skardel 	SET_HOSTMASK(&resmask, AF(&ep->sin));
104745530cf1Skardel 	hack_restrict(RESTRICT_REMOVEIF, &ep->sin, &resmask,
1048b3d6264cSchristos 		      RESM_NTPONLY | RESM_INTERFACE, RES_IGNORE, 0);
1049abb0f93cSkardel }
1050abb0f93cSkardel 
1051abb0f93cSkardel 
1052abb0f93cSkardel static void
105345530cf1Skardel log_listen_address(
105445530cf1Skardel 	endpt *	ep
1055abb0f93cSkardel 	)
1056abb0f93cSkardel {
1057b3d6264cSchristos 	msyslog(LOG_INFO, "%s on %d %s %s",
105845530cf1Skardel 		(ep->ignore_packets)
1059abb0f93cSkardel 		    ? "Listen and drop"
1060abb0f93cSkardel 		    : "Listen normally",
106145530cf1Skardel 		ep->ifnum,
106245530cf1Skardel 		ep->name,
1063b3d6264cSchristos 		sptoa(&ep->sin));
1064abb0f93cSkardel }
1065abb0f93cSkardel 
1066abb0f93cSkardel 
1067abb0f93cSkardel static void
1068abb0f93cSkardel create_wildcards(
1069abb0f93cSkardel 	u_short	port
1070abb0f93cSkardel 	)
1071abb0f93cSkardel {
107243476b9eSkardel 	int			v4wild;
107343476b9eSkardel #ifdef INCLUDE_IPV6_SUPPORT
107443476b9eSkardel 	int			v6wild;
107543476b9eSkardel #endif
1076abb0f93cSkardel 	sockaddr_u		wildaddr;
1077abb0f93cSkardel 	nic_rule_action		action;
1078abb0f93cSkardel 	struct interface *	wildif;
1079abb0f93cSkardel 
1080abb0f93cSkardel 	/*
1081abb0f93cSkardel 	 * silence "potentially uninitialized" warnings from VC9
1082abb0f93cSkardel 	 * failing to follow the logic.  Ideally action could remain
1083abb0f93cSkardel 	 * uninitialized, and the memset be the first statement under
1084abb0f93cSkardel 	 * the first if (v4wild).
1085abb0f93cSkardel 	 */
1086abb0f93cSkardel 	action = ACTION_LISTEN;
1087b3d6264cSchristos 	ZERO(wildaddr);
1088abb0f93cSkardel 
1089abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT
1090abb0f93cSkardel 	/*
1091abb0f93cSkardel 	 * create pseudo-interface with wildcard IPv6 address
1092abb0f93cSkardel 	 */
1093abb0f93cSkardel 	v6wild = ipv6_works;
1094abb0f93cSkardel 	if (v6wild) {
1095abb0f93cSkardel 		/* set wildaddr to the v6 wildcard address :: */
1096b3d6264cSchristos 		ZERO(wildaddr);
1097abb0f93cSkardel 		AF(&wildaddr) = AF_INET6;
1098abb0f93cSkardel 		SET_ADDR6N(&wildaddr, in6addr_any);
1099abb0f93cSkardel 		SET_PORT(&wildaddr, port);
1100abb0f93cSkardel 		SET_SCOPE(&wildaddr, 0);
1101abb0f93cSkardel 
1102abb0f93cSkardel 		/* check for interface/nic rules affecting the wildcard */
110345530cf1Skardel 		action = interface_action(NULL, &wildaddr, 0);
1104abb0f93cSkardel 		v6wild = (ACTION_IGNORE != action);
1105abb0f93cSkardel 	}
1106abb0f93cSkardel 	if (v6wild) {
1107abb0f93cSkardel 		wildif = new_interface(NULL);
1108abb0f93cSkardel 
1109b3d6264cSchristos 		strlcpy(wildif->name, "v6wildcard", sizeof(wildif->name));
1110abb0f93cSkardel 		memcpy(&wildif->sin, &wildaddr, sizeof(wildif->sin));
1111abb0f93cSkardel 		wildif->family = AF_INET6;
1112abb0f93cSkardel 		AF(&wildif->mask) = AF_INET6;
1113abb0f93cSkardel 		SET_ONESMASK(&wildif->mask);
1114abb0f93cSkardel 
1115abb0f93cSkardel 		wildif->flags = INT_UP | INT_WILDCARD;
1116abb0f93cSkardel 		wildif->ignore_packets = (ACTION_DROP == action);
1117abb0f93cSkardel 
1118abb0f93cSkardel 		wildif->fd = open_socket(&wildif->sin, 0, 1, wildif);
1119abb0f93cSkardel 
1120abb0f93cSkardel 		if (wildif->fd != INVALID_SOCKET) {
1121abb0f93cSkardel 			wildipv6 = wildif;
1122abb0f93cSkardel 			any6_interface = wildif;
1123abb0f93cSkardel 			add_addr_to_list(&wildif->sin, wildif);
1124abb0f93cSkardel 			add_interface(wildif);
112545530cf1Skardel 			log_listen_address(wildif);
1126abb0f93cSkardel 		} else {
1127abb0f93cSkardel 			msyslog(LOG_ERR,
1128abb0f93cSkardel 				"unable to bind to wildcard address %s - another process may be running - EXITING",
1129abb0f93cSkardel 				stoa(&wildif->sin));
1130abb0f93cSkardel 			exit(1);
1131abb0f93cSkardel 		}
1132abb0f93cSkardel 		DPRINT_INTERFACE(2, (wildif, "created ", "\n"));
1133abb0f93cSkardel 	}
1134abb0f93cSkardel #endif
1135b3d6264cSchristos 
1136b3d6264cSchristos 	/*
1137b3d6264cSchristos 	 * create pseudo-interface with wildcard IPv4 address
1138b3d6264cSchristos 	 */
1139b3d6264cSchristos 	v4wild = ipv4_works;
1140b3d6264cSchristos 	if (v4wild) {
1141b3d6264cSchristos 		/* set wildaddr to the v4 wildcard address 0.0.0.0 */
1142b3d6264cSchristos 		AF(&wildaddr) = AF_INET;
1143b3d6264cSchristos 		SET_ADDR4N(&wildaddr, INADDR_ANY);
1144b3d6264cSchristos 		SET_PORT(&wildaddr, port);
1145b3d6264cSchristos 
1146b3d6264cSchristos 		/* check for interface/nic rules affecting the wildcard */
1147b3d6264cSchristos 		action = interface_action(NULL, &wildaddr, 0);
1148b3d6264cSchristos 		v4wild = (ACTION_IGNORE != action);
1149b3d6264cSchristos 	}
1150b3d6264cSchristos 	if (v4wild) {
1151b3d6264cSchristos 		wildif = new_interface(NULL);
1152b3d6264cSchristos 
1153b3d6264cSchristos 		strlcpy(wildif->name, "v4wildcard", sizeof(wildif->name));
1154b3d6264cSchristos 		memcpy(&wildif->sin, &wildaddr, sizeof(wildif->sin));
1155b3d6264cSchristos 		wildif->family = AF_INET;
1156b3d6264cSchristos 		AF(&wildif->mask) = AF_INET;
1157b3d6264cSchristos 		SET_ONESMASK(&wildif->mask);
1158b3d6264cSchristos 
1159b3d6264cSchristos 		wildif->flags = INT_BROADCAST | INT_UP | INT_WILDCARD;
1160b3d6264cSchristos 		wildif->ignore_packets = (ACTION_DROP == action);
1161b3d6264cSchristos #if defined(MCAST)
1162b3d6264cSchristos 		/*
1163b3d6264cSchristos 		 * enable multicast reception on the broadcast socket
1164b3d6264cSchristos 		 */
1165b3d6264cSchristos 		AF(&wildif->bcast) = AF_INET;
1166b3d6264cSchristos 		SET_ADDR4N(&wildif->bcast, INADDR_ANY);
1167b3d6264cSchristos 		SET_PORT(&wildif->bcast, port);
1168b3d6264cSchristos #endif /* MCAST */
1169b3d6264cSchristos 		wildif->fd = open_socket(&wildif->sin, 0, 1, wildif);
1170b3d6264cSchristos 
1171b3d6264cSchristos 		if (wildif->fd != INVALID_SOCKET) {
1172b3d6264cSchristos 			wildipv4 = wildif;
1173b3d6264cSchristos 			any_interface = wildif;
1174b3d6264cSchristos 
1175b3d6264cSchristos 			add_addr_to_list(&wildif->sin, wildif);
1176b3d6264cSchristos 			add_interface(wildif);
1177b3d6264cSchristos 			log_listen_address(wildif);
1178b3d6264cSchristos 		} else {
1179b3d6264cSchristos 			msyslog(LOG_ERR,
1180b3d6264cSchristos 				"unable to bind to wildcard address %s - another process may be running - EXITING",
1181b3d6264cSchristos 				stoa(&wildif->sin));
1182b3d6264cSchristos 			exit(1);
1183b3d6264cSchristos 		}
1184b3d6264cSchristos 		DPRINT_INTERFACE(2, (wildif, "created ", "\n"));
1185b3d6264cSchristos 	}
1186abb0f93cSkardel }
1187abb0f93cSkardel 
1188abb0f93cSkardel 
1189abb0f93cSkardel /*
1190abb0f93cSkardel  * add_nic_rule() -- insert a rule entry at the head of nic_rule_list.
1191abb0f93cSkardel  */
1192abb0f93cSkardel void
1193abb0f93cSkardel add_nic_rule(
1194abb0f93cSkardel 	nic_rule_match	match_type,
1195abb0f93cSkardel 	const char *	if_name,	/* interface name or numeric address */
1196abb0f93cSkardel 	int		prefixlen,
1197abb0f93cSkardel 	nic_rule_action	action
1198abb0f93cSkardel 	)
1199abb0f93cSkardel {
1200abb0f93cSkardel 	nic_rule *	rule;
1201abb0f93cSkardel 	isc_boolean_t	is_ip;
1202abb0f93cSkardel 
1203b3d6264cSchristos 	rule = emalloc_zero(sizeof(*rule));
1204abb0f93cSkardel 	rule->match_type = match_type;
1205abb0f93cSkardel 	rule->prefixlen = prefixlen;
1206abb0f93cSkardel 	rule->action = action;
1207abb0f93cSkardel 
1208abb0f93cSkardel 	if (MATCH_IFNAME == match_type) {
120909f14f80Schristos 		REQUIRE(NULL != if_name);
1210abb0f93cSkardel 		rule->if_name = estrdup(if_name);
1211abb0f93cSkardel 	} else if (MATCH_IFADDR == match_type) {
121209f14f80Schristos 		REQUIRE(NULL != if_name);
121345530cf1Skardel 		/* set rule->addr */
1214b3d6264cSchristos 		is_ip = is_ip_address(if_name, AF_UNSPEC, &rule->addr);
121509f14f80Schristos 		REQUIRE(is_ip);
1216abb0f93cSkardel 	} else
121709f14f80Schristos 		REQUIRE(NULL == if_name);
1218abb0f93cSkardel 
1219abb0f93cSkardel 	LINK_SLIST(nic_rule_list, rule, next);
1220abb0f93cSkardel }
1221abb0f93cSkardel 
1222abb0f93cSkardel 
1223abb0f93cSkardel #ifdef DEBUG
1224abb0f93cSkardel static const char *
1225abb0f93cSkardel action_text(
1226abb0f93cSkardel 	nic_rule_action	action
1227abb0f93cSkardel 	)
1228abb0f93cSkardel {
1229abb0f93cSkardel 	const char *t;
1230abb0f93cSkardel 
1231abb0f93cSkardel 	switch (action) {
1232abb0f93cSkardel 
1233abb0f93cSkardel 	default:
1234abb0f93cSkardel 		t = "ERROR";	/* quiet uninit warning */
1235abb0f93cSkardel 		DPRINTF(1, ("fatal: unknown nic_rule_action %d\n",
1236abb0f93cSkardel 			    action));
123709f14f80Schristos 		ENSURE(0);
1238abb0f93cSkardel 		break;
1239abb0f93cSkardel 
1240abb0f93cSkardel 	case ACTION_LISTEN:
1241abb0f93cSkardel 		t = "listen";
1242abb0f93cSkardel 		break;
1243abb0f93cSkardel 
1244abb0f93cSkardel 	case ACTION_IGNORE:
1245abb0f93cSkardel 		t = "ignore";
1246abb0f93cSkardel 		break;
1247abb0f93cSkardel 
1248abb0f93cSkardel 	case ACTION_DROP:
1249abb0f93cSkardel 		t = "drop";
1250abb0f93cSkardel 		break;
1251abb0f93cSkardel 	}
1252abb0f93cSkardel 
1253abb0f93cSkardel 	return t;
1254abb0f93cSkardel }
1255abb0f93cSkardel #endif	/* DEBUG */
1256abb0f93cSkardel 
1257abb0f93cSkardel 
1258abb0f93cSkardel static nic_rule_action
1259abb0f93cSkardel interface_action(
1260abb0f93cSkardel 	char *		if_name,
126145530cf1Skardel 	sockaddr_u *	if_addr,
126245530cf1Skardel 	u_int32		if_flags
1263abb0f93cSkardel 	)
1264abb0f93cSkardel {
1265abb0f93cSkardel 	nic_rule *	rule;
1266abb0f93cSkardel 	int		isloopback;
1267abb0f93cSkardel 	int		iswildcard;
1268abb0f93cSkardel 
1269b3d6264cSchristos 	DPRINTF(4, ("interface_action: interface %s ",
1270b3d6264cSchristos 		    (if_name != NULL) ? if_name : "wildcard"));
1271abb0f93cSkardel 
127245530cf1Skardel 	iswildcard = is_wildcard_addr(if_addr);
1273b3d6264cSchristos 	isloopback = !!(INT_LOOPBACK & if_flags);
1274abb0f93cSkardel 
1275abb0f93cSkardel 	/*
1276abb0f93cSkardel 	 * Find any matching NIC rule from --interface / -I or ntp.conf
1277abb0f93cSkardel 	 * interface/nic rules.
1278abb0f93cSkardel 	 */
1279abb0f93cSkardel 	for (rule = nic_rule_list; rule != NULL; rule = rule->next) {
1280abb0f93cSkardel 
1281abb0f93cSkardel 		switch (rule->match_type) {
1282abb0f93cSkardel 
1283abb0f93cSkardel 		case MATCH_ALL:
1284abb0f93cSkardel 			/* loopback and wildcard excluded from "all" */
1285abb0f93cSkardel 			if (isloopback || iswildcard)
1286abb0f93cSkardel 				break;
1287abb0f93cSkardel 			DPRINTF(4, ("nic all %s\n",
1288abb0f93cSkardel 			    action_text(rule->action)));
1289abb0f93cSkardel 			return rule->action;
1290abb0f93cSkardel 
1291abb0f93cSkardel 		case MATCH_IPV4:
129245530cf1Skardel 			if (IS_IPV4(if_addr)) {
1293abb0f93cSkardel 				DPRINTF(4, ("nic ipv4 %s\n",
1294abb0f93cSkardel 				    action_text(rule->action)));
1295abb0f93cSkardel 				return rule->action;
1296abb0f93cSkardel 			}
1297abb0f93cSkardel 			break;
1298abb0f93cSkardel 
1299abb0f93cSkardel 		case MATCH_IPV6:
130045530cf1Skardel 			if (IS_IPV6(if_addr)) {
1301abb0f93cSkardel 				DPRINTF(4, ("nic ipv6 %s\n",
1302abb0f93cSkardel 				    action_text(rule->action)));
1303abb0f93cSkardel 				return rule->action;
1304abb0f93cSkardel 			}
1305abb0f93cSkardel 			break;
1306abb0f93cSkardel 
1307abb0f93cSkardel 		case MATCH_WILDCARD:
1308abb0f93cSkardel 			if (iswildcard) {
1309abb0f93cSkardel 				DPRINTF(4, ("nic wildcard %s\n",
1310abb0f93cSkardel 				    action_text(rule->action)));
1311abb0f93cSkardel 				return rule->action;
1312abb0f93cSkardel 			}
1313abb0f93cSkardel 			break;
1314abb0f93cSkardel 
1315abb0f93cSkardel 		case MATCH_IFADDR:
1316abb0f93cSkardel 			if (rule->prefixlen != -1) {
131745530cf1Skardel 				if (addr_eqprefix(if_addr, &rule->addr,
131845530cf1Skardel 						  rule->prefixlen)) {
1319abb0f93cSkardel 
1320abb0f93cSkardel 					DPRINTF(4, ("subnet address match - %s\n",
1321abb0f93cSkardel 					    action_text(rule->action)));
1322abb0f93cSkardel 					return rule->action;
1323abb0f93cSkardel 				}
1324abb0f93cSkardel 			} else
132545530cf1Skardel 				if (SOCK_EQ(if_addr, &rule->addr)) {
1326abb0f93cSkardel 
1327abb0f93cSkardel 					DPRINTF(4, ("address match - %s\n",
1328abb0f93cSkardel 					    action_text(rule->action)));
1329abb0f93cSkardel 					return rule->action;
1330abb0f93cSkardel 				}
1331abb0f93cSkardel 			break;
1332abb0f93cSkardel 
1333abb0f93cSkardel 		case MATCH_IFNAME:
1334abb0f93cSkardel 			if (if_name != NULL
1335ad131110Schristos #if defined(HAVE_FNMATCH) && defined(FNM_CASEFOLD)
1336ad131110Schristos 			    && !fnmatch(rule->if_name, if_name, FNM_CASEFOLD)
1337ad131110Schristos #else
1338ad131110Schristos 			    && !strcasecmp(if_name, rule->if_name)
1339ad131110Schristos #endif
1340ad131110Schristos 			    ) {
1341abb0f93cSkardel 
1342abb0f93cSkardel 				DPRINTF(4, ("interface name match - %s\n",
1343abb0f93cSkardel 				    action_text(rule->action)));
1344abb0f93cSkardel 				return rule->action;
1345abb0f93cSkardel 			}
1346abb0f93cSkardel 			break;
1347abb0f93cSkardel 		}
1348abb0f93cSkardel 	}
1349abb0f93cSkardel 
1350abb0f93cSkardel 	/*
1351abb0f93cSkardel 	 * Unless explicitly disabled such as with "nic ignore ::1"
1352abb0f93cSkardel 	 * listen on loopback addresses.  Since ntpq and ntpdc query
1353abb0f93cSkardel 	 * "localhost" by default, which typically resolves to ::1 and
1354abb0f93cSkardel 	 * 127.0.0.1, it's useful to default to listening on both.
1355abb0f93cSkardel 	 */
1356abb0f93cSkardel 	if (isloopback) {
1357abb0f93cSkardel 		DPRINTF(4, ("default loopback listen\n"));
1358abb0f93cSkardel 		return ACTION_LISTEN;
1359abb0f93cSkardel 	}
1360abb0f93cSkardel 
1361abb0f93cSkardel 	/*
1362abb0f93cSkardel 	 * Treat wildcard addresses specially.  If there is no explicit
1363abb0f93cSkardel 	 * "nic ... wildcard" or "nic ... 0.0.0.0" or "nic ... ::" rule
1364abb0f93cSkardel 	 * default to drop.
1365abb0f93cSkardel 	 */
1366abb0f93cSkardel 	if (iswildcard) {
1367abb0f93cSkardel 		DPRINTF(4, ("default wildcard drop\n"));
1368abb0f93cSkardel 		return ACTION_DROP;
1369abb0f93cSkardel 	}
1370abb0f93cSkardel 
1371abb0f93cSkardel 	/*
1372abb0f93cSkardel 	 * Check for "virtual IP" (colon in the interface name) after
1373abb0f93cSkardel 	 * the rules so that "ntpd --interface eth0:1 -novirtualips"
1374abb0f93cSkardel 	 * does indeed listen on eth0:1's addresses.
1375abb0f93cSkardel 	 */
1376abb0f93cSkardel 	if (!listen_to_virtual_ips && if_name != NULL
1377abb0f93cSkardel 	    && (strchr(if_name, ':') != NULL)) {
1378abb0f93cSkardel 
1379abb0f93cSkardel 		DPRINTF(4, ("virtual ip - ignore\n"));
1380abb0f93cSkardel 		return ACTION_IGNORE;
1381abb0f93cSkardel 	}
1382abb0f93cSkardel 
1383abb0f93cSkardel 	/*
1384abb0f93cSkardel 	 * If there are no --interface/-I command-line options and no
1385abb0f93cSkardel 	 * interface/nic rules in ntp.conf, the default action is to
1386abb0f93cSkardel 	 * listen.  In the presence of rules from either, the default
1387abb0f93cSkardel 	 * is to ignore.  This implements ntpd's traditional listen-
1388abb0f93cSkardel 	 * every default with no interface listen configuration, and
1389abb0f93cSkardel 	 * ensures a single -I eth0 or "nic listen eth0" means do not
1390abb0f93cSkardel 	 * listen on any other addresses.
1391abb0f93cSkardel 	 */
1392abb0f93cSkardel 	if (NULL == nic_rule_list) {
1393abb0f93cSkardel 		DPRINTF(4, ("default listen\n"));
1394abb0f93cSkardel 		return ACTION_LISTEN;
1395abb0f93cSkardel 	}
1396abb0f93cSkardel 
1397abb0f93cSkardel 	DPRINTF(4, ("implicit ignore\n"));
1398abb0f93cSkardel 	return ACTION_IGNORE;
1399abb0f93cSkardel }
1400abb0f93cSkardel 
1401abb0f93cSkardel 
1402abb0f93cSkardel static void
1403abb0f93cSkardel convert_isc_if(
1404abb0f93cSkardel 	isc_interface_t *isc_if,
140545530cf1Skardel 	endpt *itf,
1406abb0f93cSkardel 	u_short port
1407abb0f93cSkardel 	)
1408abb0f93cSkardel {
140945530cf1Skardel 	const u_char v6loop[16] = {0, 0, 0, 0, 0, 0, 0, 0,
141045530cf1Skardel 				   0, 0, 0, 0, 0, 0, 0, 1};
141145530cf1Skardel 
1412b3d6264cSchristos 	strlcpy(itf->name, isc_if->name, sizeof(itf->name));
141345530cf1Skardel 	itf->ifindex = isc_if->ifindex;
1414abb0f93cSkardel 	itf->family = (u_short)isc_if->af;
1415abb0f93cSkardel 	AF(&itf->sin) = itf->family;
1416abb0f93cSkardel 	AF(&itf->mask) = itf->family;
1417abb0f93cSkardel 	AF(&itf->bcast) = itf->family;
1418abb0f93cSkardel 	SET_PORT(&itf->sin, port);
1419abb0f93cSkardel 	SET_PORT(&itf->mask, port);
1420abb0f93cSkardel 	SET_PORT(&itf->bcast, port);
1421abb0f93cSkardel 
1422abb0f93cSkardel 	if (IS_IPV4(&itf->sin)) {
1423abb0f93cSkardel 		NSRCADR(&itf->sin) = isc_if->address.type.in.s_addr;
1424abb0f93cSkardel 		NSRCADR(&itf->mask) = isc_if->netmask.type.in.s_addr;
1425abb0f93cSkardel 
1426abb0f93cSkardel 		if (isc_if->flags & INTERFACE_F_BROADCAST) {
1427abb0f93cSkardel 			itf->flags |= INT_BROADCAST;
1428abb0f93cSkardel 			NSRCADR(&itf->bcast) =
1429abb0f93cSkardel 			    isc_if->broadcast.type.in.s_addr;
1430abb0f93cSkardel 		}
1431abb0f93cSkardel 	}
1432abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT
1433abb0f93cSkardel 	else if (IS_IPV6(&itf->sin)) {
1434abb0f93cSkardel 		SET_ADDR6N(&itf->sin, isc_if->address.type.in6);
1435abb0f93cSkardel 		SET_ADDR6N(&itf->mask, isc_if->netmask.type.in6);
1436abb0f93cSkardel 
143745530cf1Skardel 		SET_SCOPE(&itf->sin, isc_if->address.zone);
1438abb0f93cSkardel 	}
1439abb0f93cSkardel #endif /* INCLUDE_IPV6_SUPPORT */
1440abb0f93cSkardel 
1441abb0f93cSkardel 
1442abb0f93cSkardel 	/* Process the rest of the flags */
1443abb0f93cSkardel 
1444abb0f93cSkardel 	itf->flags |=
1445abb0f93cSkardel 		  ((INTERFACE_F_UP & isc_if->flags)
1446abb0f93cSkardel 			? INT_UP : 0)
1447abb0f93cSkardel 		| ((INTERFACE_F_LOOPBACK & isc_if->flags)
1448abb0f93cSkardel 			? INT_LOOPBACK : 0)
1449abb0f93cSkardel 		| ((INTERFACE_F_POINTTOPOINT & isc_if->flags)
1450abb0f93cSkardel 			? INT_PPP : 0)
1451abb0f93cSkardel 		| ((INTERFACE_F_MULTICAST & isc_if->flags)
1452abb0f93cSkardel 			? INT_MULTICAST : 0)
145345530cf1Skardel 		| ((INTERFACE_F_PRIVACY & isc_if->flags)
145445530cf1Skardel 			? INT_PRIVACY : 0)
1455abb0f93cSkardel 		;
145645530cf1Skardel 
145745530cf1Skardel 	/*
145845530cf1Skardel 	 * Clear the loopback flag if the address is not localhost.
145945530cf1Skardel 	 * http://bugs.ntp.org/1683
146045530cf1Skardel 	 */
146145530cf1Skardel 	if (INT_LOOPBACK & itf->flags) {
146245530cf1Skardel 		if (AF_INET == itf->family) {
146345530cf1Skardel 			if (127 != (SRCADR(&itf->sin) >> 24))
146445530cf1Skardel 				itf->flags &= ~INT_LOOPBACK;
146545530cf1Skardel 		} else {
146645530cf1Skardel 			if (memcmp(v6loop, NSRCADR6(&itf->sin),
146745530cf1Skardel 				   sizeof(NSRCADR6(&itf->sin))))
146845530cf1Skardel 				itf->flags &= ~INT_LOOPBACK;
146945530cf1Skardel 		}
147045530cf1Skardel 	}
1471abb0f93cSkardel }
1472abb0f93cSkardel 
1473abb0f93cSkardel 
1474abb0f93cSkardel /*
1475abb0f93cSkardel  * refresh_interface
1476abb0f93cSkardel  *
1477abb0f93cSkardel  * some OSes have been observed to keep
1478abb0f93cSkardel  * cached routes even when more specific routes
1479abb0f93cSkardel  * become available.
1480abb0f93cSkardel  * this can be mitigated by re-binding
1481abb0f93cSkardel  * the socket.
1482abb0f93cSkardel  */
1483abb0f93cSkardel static int
1484abb0f93cSkardel refresh_interface(
1485abb0f93cSkardel 	struct interface * interface
1486abb0f93cSkardel 	)
1487abb0f93cSkardel {
1488abb0f93cSkardel #ifdef  OS_MISSES_SPECIFIC_ROUTE_UPDATES
1489abb0f93cSkardel 	if (interface->fd != INVALID_SOCKET) {
1490b3d6264cSchristos 		int bcast = (interface->flags & INT_BCASTXMIT) != 0;
1491b3d6264cSchristos 		/* as we forcibly close() the socket remove the
1492b3d6264cSchristos 		   broadcast permission indication */
1493b3d6264cSchristos 		if (bcast)
1494b3d6264cSchristos 			socket_broadcast_disable(interface, &interface->sin);
1495b3d6264cSchristos 
1496abb0f93cSkardel 		close_and_delete_fd_from_list(interface->fd);
1497b3d6264cSchristos 
1498b3d6264cSchristos 		/* create new socket picking up a new first hop binding
1499b3d6264cSchristos 		   at connect() time */
1500abb0f93cSkardel 		interface->fd = open_socket(&interface->sin,
1501766d83b9Skardel 					    bcast, 0, interface);
1502abb0f93cSkardel 		 /*
1503abb0f93cSkardel 		  * reset TTL indication so TTL is is set again
1504abb0f93cSkardel 		  * next time around
1505abb0f93cSkardel 		  */
1506abb0f93cSkardel 		interface->last_ttl = 0;
1507abb0f93cSkardel 		return (interface->fd != INVALID_SOCKET);
1508abb0f93cSkardel 	} else
1509abb0f93cSkardel 		return 0;	/* invalid sockets are not refreshable */
1510abb0f93cSkardel #else /* !OS_MISSES_SPECIFIC_ROUTE_UPDATES */
1511abb0f93cSkardel 	return (interface->fd != INVALID_SOCKET);
1512abb0f93cSkardel #endif /* !OS_MISSES_SPECIFIC_ROUTE_UPDATES */
1513abb0f93cSkardel }
1514abb0f93cSkardel 
1515abb0f93cSkardel /*
1516abb0f93cSkardel  * interface_update - externally callable update function
1517abb0f93cSkardel  */
1518abb0f93cSkardel void
1519abb0f93cSkardel interface_update(
1520abb0f93cSkardel 	interface_receiver_t	receiver,
1521abb0f93cSkardel 	void *			data)
1522abb0f93cSkardel {
1523abb0f93cSkardel 	int new_interface_found;
1524abb0f93cSkardel 
1525abb0f93cSkardel 	if (disable_dynamic_updates)
1526abb0f93cSkardel 		return;
1527abb0f93cSkardel 
1528abb0f93cSkardel 	BLOCKIO();
1529abb0f93cSkardel 	new_interface_found = update_interfaces(NTP_PORT, receiver, data);
1530abb0f93cSkardel 	UNBLOCKIO();
1531abb0f93cSkardel 
1532abb0f93cSkardel 	if (!new_interface_found)
1533abb0f93cSkardel 		return;
1534abb0f93cSkardel 
1535abb0f93cSkardel #ifdef DEBUG
1536abb0f93cSkardel 	msyslog(LOG_DEBUG, "new interface(s) found: waking up resolver");
1537abb0f93cSkardel #endif
1538b3d6264cSchristos 	interrupt_worker_sleep();
1539abb0f93cSkardel }
1540abb0f93cSkardel 
1541abb0f93cSkardel 
1542abb0f93cSkardel /*
1543abb0f93cSkardel  * sau_from_netaddr() - convert network address on-wire formats.
1544abb0f93cSkardel  * Convert from libisc's isc_netaddr_t to NTP's sockaddr_u
1545abb0f93cSkardel  */
1546abb0f93cSkardel void
1547abb0f93cSkardel sau_from_netaddr(
1548abb0f93cSkardel 	sockaddr_u *psau,
1549abb0f93cSkardel 	const isc_netaddr_t *pna
1550abb0f93cSkardel 	)
1551abb0f93cSkardel {
1552b3d6264cSchristos 	ZERO_SOCK(psau);
1553abb0f93cSkardel 	AF(psau) = (u_short)pna->family;
1554abb0f93cSkardel 	switch (pna->family) {
1555abb0f93cSkardel 
1556abb0f93cSkardel 	case AF_INET:
1557abb0f93cSkardel 		memcpy(&psau->sa4.sin_addr, &pna->type.in,
1558abb0f93cSkardel 		       sizeof(psau->sa4.sin_addr));
1559abb0f93cSkardel 		break;
1560abb0f93cSkardel 
1561abb0f93cSkardel 	case AF_INET6:
1562abb0f93cSkardel 		memcpy(&psau->sa6.sin6_addr, &pna->type.in6,
1563abb0f93cSkardel 		       sizeof(psau->sa6.sin6_addr));
1564abb0f93cSkardel 		break;
1565abb0f93cSkardel 	}
1566abb0f93cSkardel }
1567abb0f93cSkardel 
1568abb0f93cSkardel 
1569abb0f93cSkardel static int
1570abb0f93cSkardel is_wildcard_addr(
157145530cf1Skardel 	const sockaddr_u *psau
1572abb0f93cSkardel 	)
1573abb0f93cSkardel {
1574abb0f93cSkardel 	if (IS_IPV4(psau) && !NSRCADR(psau))
1575abb0f93cSkardel 		return 1;
1576abb0f93cSkardel 
1577abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT
1578abb0f93cSkardel 	if (IS_IPV6(psau) && S_ADDR6_EQ(psau, &in6addr_any))
1579abb0f93cSkardel 		return 1;
1580abb0f93cSkardel #endif
1581abb0f93cSkardel 
1582abb0f93cSkardel 	return 0;
1583abb0f93cSkardel }
1584abb0f93cSkardel 
1585abb0f93cSkardel 
1586abb0f93cSkardel #ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND
1587abb0f93cSkardel /*
1588abb0f93cSkardel  * enable/disable re-use of wildcard address socket
1589abb0f93cSkardel  */
1590abb0f93cSkardel static void
1591abb0f93cSkardel set_wildcard_reuse(
1592abb0f93cSkardel 	u_short	family,
1593abb0f93cSkardel 	int	on
1594abb0f93cSkardel 	)
1595abb0f93cSkardel {
1596abb0f93cSkardel 	struct interface *any;
1597abb0f93cSkardel 	SOCKET fd = INVALID_SOCKET;
1598abb0f93cSkardel 
1599abb0f93cSkardel 	any = ANY_INTERFACE_BYFAM(family);
1600abb0f93cSkardel 	if (any != NULL)
1601abb0f93cSkardel 		fd = any->fd;
1602abb0f93cSkardel 
1603abb0f93cSkardel 	if (fd != INVALID_SOCKET) {
1604abb0f93cSkardel 		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
1605abb0f93cSkardel 			       (char *)&on, sizeof(on)))
1606abb0f93cSkardel 			msyslog(LOG_ERR,
1607abb0f93cSkardel 				"set_wildcard_reuse: setsockopt(SO_REUSEADDR, %s) failed: %m",
1608abb0f93cSkardel 				on ? "on" : "off");
1609abb0f93cSkardel 
1610abb0f93cSkardel 		DPRINTF(4, ("set SO_REUSEADDR to %s on %s\n",
1611abb0f93cSkardel 			    on ? "on" : "off",
1612abb0f93cSkardel 			    stoa(&any->sin)));
1613abb0f93cSkardel 	}
1614abb0f93cSkardel }
1615abb0f93cSkardel #endif /* OS_NEEDS_REUSEADDR_FOR_IFADDRBIND */
1616abb0f93cSkardel 
16177469785fSroy static isc_boolean_t
16187469785fSroy check_flags(
16197469785fSroy 	sockaddr_u *psau,
16207469785fSroy 	const char *name,
16217469785fSroy 	u_int32 flags
16227469785fSroy 	)
16237469785fSroy {
16247469785fSroy #if defined(SIOCGIFAFLAG_IN)
16257469785fSroy 	struct ifreq ifr;
16267469785fSroy 	int fd;
16277469785fSroy 
16287469785fSroy 	if (psau->sa.sa_family != AF_INET)
16297469785fSroy 		return ISC_FALSE;
16307469785fSroy 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
16317469785fSroy 		return ISC_FALSE;
16327469785fSroy 	ZERO(ifr);
16337469785fSroy 	memcpy(&ifr.ifr_addr, &psau->sa, sizeof(ifr.ifr_addr));
16347469785fSroy 	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
16357469785fSroy 	if (ioctl(fd, SIOCGIFAFLAG_IN, &ifr) < 0) {
16367469785fSroy 		close(fd);
16377469785fSroy 		return ISC_FALSE;
16387469785fSroy 	}
16397469785fSroy 	close(fd);
16407469785fSroy 	if ((ifr.ifr_addrflags & flags) != 0)
16417469785fSroy 		return ISC_TRUE;
16427469785fSroy #endif	/* SIOCGIFAFLAG_IN */
16437469785fSroy 	return ISC_FALSE;
16447469785fSroy }
164545530cf1Skardel 
164645530cf1Skardel static isc_boolean_t
1647df44c210Sroy check_flags6(
164845530cf1Skardel 	sockaddr_u *psau,
1649df44c210Sroy 	const char *name,
1650df44c210Sroy 	u_int32 flags6
165145530cf1Skardel 	)
165245530cf1Skardel {
1653df44c210Sroy #if defined(INCLUDE_IPV6_SUPPORT) && defined(SIOCGIFAFLAG_IN6)
165445530cf1Skardel 	struct in6_ifreq ifr6;
165545530cf1Skardel 	int fd;
165645530cf1Skardel 
165745530cf1Skardel 	if (psau->sa.sa_family != AF_INET6)
165845530cf1Skardel 		return ISC_FALSE;
165945530cf1Skardel 	if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
166045530cf1Skardel 		return ISC_FALSE;
1661b3d6264cSchristos 	ZERO(ifr6);
166245530cf1Skardel 	memcpy(&ifr6.ifr_addr, &psau->sa6, sizeof(ifr6.ifr_addr));
1663b3d6264cSchristos 	strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
166445530cf1Skardel 	if (ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
166545530cf1Skardel 		close(fd);
166645530cf1Skardel 		return ISC_FALSE;
166745530cf1Skardel 	}
166845530cf1Skardel 	close(fd);
1669df44c210Sroy 	if ((ifr6.ifr_ifru.ifru_flags6 & flags6) != 0)
167045530cf1Skardel 		return ISC_TRUE;
1671df44c210Sroy #endif	/* INCLUDE_IPV6_SUPPORT && SIOCGIFAFLAG_IN6 */
167245530cf1Skardel 	return ISC_FALSE;
167345530cf1Skardel }
167445530cf1Skardel 
1675df44c210Sroy static isc_boolean_t
1676df44c210Sroy is_anycast(
1677df44c210Sroy 	sockaddr_u *psau,
1678df44c210Sroy 	const char *name
1679df44c210Sroy 	)
1680df44c210Sroy {
1681df44c210Sroy #ifdef IN6_IFF_ANYCAST
1682df44c210Sroy 	return check_flags6(psau, name, IN6_IFF_ANYCAST);
1683df44c210Sroy #else
1684df44c210Sroy 	return ISC_FALSE;
1685df44c210Sroy #endif
1686df44c210Sroy }
1687df44c210Sroy 
1688df44c210Sroy static isc_boolean_t
1689df44c210Sroy is_valid(
1690df44c210Sroy 	sockaddr_u *psau,
1691df44c210Sroy 	const char *name
1692df44c210Sroy 	)
1693df44c210Sroy {
16947469785fSroy 	u_int32 flags;
1695df44c210Sroy 
16967469785fSroy 	flags = 0;
16977469785fSroy 	switch (psau->sa.sa_family) {
16987469785fSroy 	case AF_INET:
16997469785fSroy #ifdef IN_IFF_DETACHED
17007469785fSroy 		flags |= IN_IFF_DETACHED;
17017469785fSroy #endif
17027469785fSroy #ifdef IN_IFF_TENTATIVE
17037469785fSroy 		flags |= IN_IFF_TENTATIVE;
17047469785fSroy #endif
17057469785fSroy 		return check_flags(psau, name, flags) ? ISC_FALSE : ISC_TRUE;
17067469785fSroy 	case AF_INET6:
1707df44c210Sroy #ifdef IN6_IFF_DEPARTED
17087469785fSroy 		flags |= IN6_IFF_DEPARTED;
1709df44c210Sroy #endif
1710df44c210Sroy #ifdef IN6_IFF_DETACHED
17117469785fSroy 		flags |= IN6_IFF_DETACHED;
1712df44c210Sroy #endif
1713df44c210Sroy #ifdef IN6_IFF_TENTATIVE
17147469785fSroy 		flags |= IN6_IFF_TENTATIVE;
1715df44c210Sroy #endif
17167469785fSroy 		return check_flags6(psau, name, flags) ? ISC_FALSE : ISC_TRUE;
17177469785fSroy 	default:
17187469785fSroy 		return ISC_FALSE;
17197469785fSroy 	}
1720df44c210Sroy }
172145530cf1Skardel 
1722abb0f93cSkardel /*
1723abb0f93cSkardel  * update_interface strategy
1724abb0f93cSkardel  *
1725abb0f93cSkardel  * toggle configuration phase
1726abb0f93cSkardel  *
1727abb0f93cSkardel  * Phase 1:
1728abb0f93cSkardel  * forall currently existing interfaces
1729abb0f93cSkardel  *   if address is known:
1730abb0f93cSkardel  *	drop socket - rebind again
1731abb0f93cSkardel  *
1732abb0f93cSkardel  *   if address is NOT known:
1733abb0f93cSkardel  *	attempt to create a new interface entry
1734abb0f93cSkardel  *
1735abb0f93cSkardel  * Phase 2:
1736abb0f93cSkardel  * forall currently known non MCAST and WILDCARD interfaces
1737abb0f93cSkardel  *   if interface does not match configuration phase (not seen in phase 1):
1738abb0f93cSkardel  *	remove interface from known interface list
1739abb0f93cSkardel  *	forall peers associated with this interface
1740abb0f93cSkardel  *         disconnect peer from this interface
1741abb0f93cSkardel  *
1742abb0f93cSkardel  * Phase 3:
1743abb0f93cSkardel  *   attempt to re-assign interfaces to peers
1744abb0f93cSkardel  *
1745abb0f93cSkardel  */
1746abb0f93cSkardel 
1747abb0f93cSkardel static int
1748abb0f93cSkardel update_interfaces(
1749abb0f93cSkardel 	u_short			port,
1750abb0f93cSkardel 	interface_receiver_t	receiver,
1751abb0f93cSkardel 	void *			data
1752abb0f93cSkardel 	)
1753abb0f93cSkardel {
1754abb0f93cSkardel 	isc_mem_t *		mctx = (void *)-1;
1755abb0f93cSkardel 	interface_info_t	ifi;
1756abb0f93cSkardel 	isc_interfaceiter_t *	iter;
1757abb0f93cSkardel 	isc_result_t		result;
1758abb0f93cSkardel 	isc_interface_t		isc_if;
1759abb0f93cSkardel 	int			new_interface_found;
1760abb0f93cSkardel 	unsigned int		family;
176145530cf1Skardel 	endpt			enumep;
176245530cf1Skardel 	endpt *			ep;
176345530cf1Skardel 	endpt *			next_ep;
1764abb0f93cSkardel 
1765abb0f93cSkardel 	DPRINTF(3, ("update_interfaces(%d)\n", port));
1766abb0f93cSkardel 
1767abb0f93cSkardel 	/*
1768abb0f93cSkardel 	 * phase one - scan interfaces
1769abb0f93cSkardel 	 * - create those that are not found
1770abb0f93cSkardel 	 * - update those that are found
1771abb0f93cSkardel 	 */
1772abb0f93cSkardel 
177345530cf1Skardel 	new_interface_found = FALSE;
1774abb0f93cSkardel 	iter = NULL;
1775abb0f93cSkardel 	result = isc_interfaceiter_create(mctx, &iter);
1776abb0f93cSkardel 
1777abb0f93cSkardel 	if (result != ISC_R_SUCCESS)
1778abb0f93cSkardel 		return 0;
1779abb0f93cSkardel 
1780abb0f93cSkardel 	/*
1781abb0f93cSkardel 	 * Toggle system interface scan phase to find untouched
1782abb0f93cSkardel 	 * interfaces to be deleted.
1783abb0f93cSkardel 	 */
1784abb0f93cSkardel 	sys_interphase ^= 0x1;
1785abb0f93cSkardel 
1786abb0f93cSkardel 	for (result = isc_interfaceiter_first(iter);
1787abb0f93cSkardel 	     ISC_R_SUCCESS == result;
1788abb0f93cSkardel 	     result = isc_interfaceiter_next(iter)) {
1789abb0f93cSkardel 
1790abb0f93cSkardel 		result = isc_interfaceiter_current(iter, &isc_if);
1791abb0f93cSkardel 
1792abb0f93cSkardel 		if (result != ISC_R_SUCCESS)
1793abb0f93cSkardel 			break;
1794abb0f93cSkardel 
1795abb0f93cSkardel 		/* See if we have a valid family to use */
1796abb0f93cSkardel 		family = isc_if.address.family;
1797abb0f93cSkardel 		if (AF_INET != family && AF_INET6 != family)
1798abb0f93cSkardel 			continue;
1799abb0f93cSkardel 		if (AF_INET == family && !ipv4_works)
1800abb0f93cSkardel 			continue;
1801abb0f93cSkardel 		if (AF_INET6 == family && !ipv6_works)
1802abb0f93cSkardel 			continue;
1803abb0f93cSkardel 
1804abb0f93cSkardel 		/* create prototype */
180545530cf1Skardel 		init_interface(&enumep);
1806abb0f93cSkardel 
180745530cf1Skardel 		convert_isc_if(&isc_if, &enumep, port);
1808abb0f93cSkardel 
1809b3d6264cSchristos 		DPRINT_INTERFACE(4, (&enumep, "examining ", "\n"));
1810b3d6264cSchristos 
1811abb0f93cSkardel 		/*
1812abb0f93cSkardel 		 * Check if and how we are going to use the interface.
1813abb0f93cSkardel 		 */
181445530cf1Skardel 		switch (interface_action(enumep.name, &enumep.sin,
181545530cf1Skardel 					 enumep.flags)) {
1816abb0f93cSkardel 
1817abb0f93cSkardel 		case ACTION_IGNORE:
1818b3d6264cSchristos 			DPRINTF(4, ("ignoring interface %s (%s) - by nic rules\n",
1819b3d6264cSchristos 				    enumep.name, stoa(&enumep.sin)));
1820abb0f93cSkardel 			continue;
1821abb0f93cSkardel 
1822abb0f93cSkardel 		case ACTION_LISTEN:
1823b3d6264cSchristos 			DPRINTF(4, ("listen interface %s (%s) - by nic rules\n",
1824b3d6264cSchristos 				    enumep.name, stoa(&enumep.sin)));
182545530cf1Skardel 			enumep.ignore_packets = ISC_FALSE;
1826abb0f93cSkardel 			break;
1827abb0f93cSkardel 
1828abb0f93cSkardel 		case ACTION_DROP:
1829b3d6264cSchristos 			DPRINTF(4, ("drop on interface %s (%s) - by nic rules\n",
1830b3d6264cSchristos 				    enumep.name, stoa(&enumep.sin)));
183145530cf1Skardel 			enumep.ignore_packets = ISC_TRUE;
1832abb0f93cSkardel 			break;
1833abb0f93cSkardel 		}
1834abb0f93cSkardel 
1835abb0f93cSkardel 		 /* interfaces must be UP to be usable */
183645530cf1Skardel 		if (!(enumep.flags & INT_UP)) {
1837abb0f93cSkardel 			DPRINTF(4, ("skipping interface %s (%s) - DOWN\n",
183845530cf1Skardel 				    enumep.name, stoa(&enumep.sin)));
1839abb0f93cSkardel 			continue;
1840abb0f93cSkardel 		}
1841abb0f93cSkardel 
1842abb0f93cSkardel 		/*
1843abb0f93cSkardel 		 * skip any interfaces UP and bound to a wildcard
1844abb0f93cSkardel 		 * address - some dhcp clients produce that in the
1845abb0f93cSkardel 		 * wild
1846abb0f93cSkardel 		 */
184745530cf1Skardel 		if (is_wildcard_addr(&enumep.sin))
184845530cf1Skardel 			continue;
184945530cf1Skardel 
185045530cf1Skardel 		if (is_anycast(&enumep.sin, isc_if.name))
1851abb0f93cSkardel 			continue;
1852abb0f93cSkardel 
1853abb0f93cSkardel 		/*
1854df44c210Sroy 		 * skip any address that is an invalid state to be used
1855df44c210Sroy 		 */
1856df44c210Sroy 		if (!is_valid(&enumep.sin, isc_if.name))
1857df44c210Sroy 			continue;
1858df44c210Sroy 
1859df44c210Sroy 		/*
1860abb0f93cSkardel 		 * map to local *address* in order to map all duplicate
186145530cf1Skardel 		 * interfaces to an endpt structure with the appropriate
186245530cf1Skardel 		 * socket.  Our name space is (ip-address), NOT
186345530cf1Skardel 		 * (interface name, ip-address).
1864abb0f93cSkardel 		 */
186545530cf1Skardel 		ep = getinterface(&enumep.sin, INT_WILDCARD);
1866abb0f93cSkardel 
186745530cf1Skardel 		if (ep != NULL && refresh_interface(ep)) {
1868abb0f93cSkardel 			/*
1869abb0f93cSkardel 			 * found existing and up to date interface -
1870abb0f93cSkardel 			 * mark present.
1871abb0f93cSkardel 			 */
187245530cf1Skardel 			if (ep->phase != sys_interphase) {
1873abb0f93cSkardel 				/*
1874abb0f93cSkardel 				 * On a new round we reset the name so
1875abb0f93cSkardel 				 * the interface name shows up again if
1876abb0f93cSkardel 				 * this address is no longer shared.
187745530cf1Skardel 				 * We reset ignore_packets from the
187845530cf1Skardel 				 * new prototype to respect any runtime
187945530cf1Skardel 				 * changes to the nic rules.
1880abb0f93cSkardel 				 */
1881b3d6264cSchristos 				strlcpy(ep->name, enumep.name,
188245530cf1Skardel 					sizeof(ep->name));
188345530cf1Skardel 				ep->ignore_packets =
188445530cf1Skardel 					    enumep.ignore_packets;
188545530cf1Skardel 			} else {
1886abb0f93cSkardel 				/* name collision - rename interface */
1887b3d6264cSchristos 				strlcpy(ep->name, "*multiple*",
188845530cf1Skardel 					sizeof(ep->name));
188945530cf1Skardel 			}
1890abb0f93cSkardel 
189145530cf1Skardel 			DPRINT_INTERFACE(4, (ep, "updating ",
1892abb0f93cSkardel 					     " present\n"));
1893abb0f93cSkardel 
189445530cf1Skardel 			if (ep->ignore_packets !=
189545530cf1Skardel 			    enumep.ignore_packets) {
1896abb0f93cSkardel 				/*
1897abb0f93cSkardel 				 * We have conflicting configurations
1898abb0f93cSkardel 				 * for the interface address. This is
1899abb0f93cSkardel 				 * caused by using -I <interfacename>
1900abb0f93cSkardel 				 * for an interface that shares its
1901abb0f93cSkardel 				 * address with other interfaces. We
1902abb0f93cSkardel 				 * can not disambiguate incoming
1903abb0f93cSkardel 				 * packets delivered to this socket
1904abb0f93cSkardel 				 * without extra syscalls/features.
1905abb0f93cSkardel 				 * These are not (commonly) available.
1906abb0f93cSkardel 				 * Note this is a more unusual
1907abb0f93cSkardel 				 * configuration where several
1908abb0f93cSkardel 				 * interfaces share an address but
1909abb0f93cSkardel 				 * filtering via interface name is
1910abb0f93cSkardel 				 * attempted.  We resolve the
1911abb0f93cSkardel 				 * configuration conflict by disabling
1912abb0f93cSkardel 				 * the processing of received packets.
1913abb0f93cSkardel 				 * This leads to no service on the
1914abb0f93cSkardel 				 * interface address where the conflict
1915abb0f93cSkardel 				 * occurs.
1916abb0f93cSkardel 				 */
1917abb0f93cSkardel 				msyslog(LOG_ERR,
1918abb0f93cSkardel 					"WARNING: conflicting enable configuration for interfaces %s and %s for address %s - unsupported configuration - address DISABLED",
191945530cf1Skardel 					enumep.name, ep->name,
192045530cf1Skardel 					stoa(&enumep.sin));
1921abb0f93cSkardel 
192245530cf1Skardel 				ep->ignore_packets = ISC_TRUE;
1923abb0f93cSkardel 			}
1924abb0f93cSkardel 
192545530cf1Skardel 			ep->phase = sys_interphase;
1926abb0f93cSkardel 
1927abb0f93cSkardel 			ifi.action = IFS_EXISTS;
192845530cf1Skardel 			ifi.ep = ep;
1929abb0f93cSkardel 			if (receiver != NULL)
1930abb0f93cSkardel 				(*receiver)(data, &ifi);
1931abb0f93cSkardel 		} else {
1932abb0f93cSkardel 			/*
1933abb0f93cSkardel 			 * This is new or refreshing failed - add to
1934abb0f93cSkardel 			 * our interface list.  If refreshing failed we
1935abb0f93cSkardel 			 * will delete the interface structure in phase
1936abb0f93cSkardel 			 * 2 as the interface was not marked current.
1937abb0f93cSkardel 			 * We can bind to the address as the refresh
1938abb0f93cSkardel 			 * code already closed the offending socket
1939abb0f93cSkardel 			 */
194045530cf1Skardel 			ep = create_interface(port, &enumep);
1941abb0f93cSkardel 
194245530cf1Skardel 			if (ep != NULL) {
1943abb0f93cSkardel 				ifi.action = IFS_CREATED;
194445530cf1Skardel 				ifi.ep = ep;
1945abb0f93cSkardel 				if (receiver != NULL)
1946abb0f93cSkardel 					(*receiver)(data, &ifi);
1947abb0f93cSkardel 
194845530cf1Skardel 				new_interface_found = TRUE;
1949abb0f93cSkardel 				DPRINT_INTERFACE(3,
195045530cf1Skardel 					(ep, "updating ",
1951abb0f93cSkardel 					 " new - created\n"));
1952abb0f93cSkardel 			} else {
1953abb0f93cSkardel 				DPRINT_INTERFACE(3,
195445530cf1Skardel 					(&enumep, "updating ",
1955abb0f93cSkardel 					 " new - creation FAILED"));
1956abb0f93cSkardel 
1957abb0f93cSkardel 				msyslog(LOG_INFO,
1958abb0f93cSkardel 					"failed to init interface for address %s",
195945530cf1Skardel 					stoa(&enumep.sin));
1960abb0f93cSkardel 				continue;
1961abb0f93cSkardel 			}
1962abb0f93cSkardel 		}
1963abb0f93cSkardel 	}
1964abb0f93cSkardel 
1965abb0f93cSkardel 	isc_interfaceiter_destroy(&iter);
1966abb0f93cSkardel 
1967abb0f93cSkardel 	/*
1968abb0f93cSkardel 	 * phase 2 - delete gone interfaces - reassigning peers to
1969abb0f93cSkardel 	 * other interfaces
1970abb0f93cSkardel 	 */
197145530cf1Skardel 	for (ep = ep_list; ep != NULL; ep = next_ep) {
197245530cf1Skardel 		next_ep = ep->elink;
1973abb0f93cSkardel 
1974abb0f93cSkardel 		/*
197545530cf1Skardel 		 * if phase does not match sys_phase this interface was
197645530cf1Skardel 		 * not enumerated during the last interface scan - so it
197745530cf1Skardel 		 * is gone and will be deleted here unless it did not
197845530cf1Skardel 		 * originate from interface enumeration (INT_WILDCARD,
197945530cf1Skardel 		 * INT_MCASTIF).
1980abb0f93cSkardel 		 */
198145530cf1Skardel 		if (((INT_WILDCARD | INT_MCASTIF) & ep->flags) ||
198245530cf1Skardel 		    ep->phase == sys_interphase)
198345530cf1Skardel 			continue;
198445530cf1Skardel 
198545530cf1Skardel 		DPRINT_INTERFACE(3, (ep, "updating ",
1986abb0f93cSkardel 				     "GONE - deleting\n"));
198745530cf1Skardel 		remove_interface(ep);
1988abb0f93cSkardel 
1989abb0f93cSkardel 		ifi.action = IFS_DELETED;
199045530cf1Skardel 		ifi.ep = ep;
1991abb0f93cSkardel 		if (receiver != NULL)
1992abb0f93cSkardel 			(*receiver)(data, &ifi);
1993abb0f93cSkardel 
199445530cf1Skardel 		/* disconnect peers from deleted endpt. */
199545530cf1Skardel 		while (ep->peers != NULL)
199645530cf1Skardel 			set_peerdstadr(ep->peers, NULL);
1997abb0f93cSkardel 
1998abb0f93cSkardel 		/*
1999abb0f93cSkardel 		 * update globals in case we lose
2000abb0f93cSkardel 		 * a loopback interface
2001abb0f93cSkardel 		 */
200245530cf1Skardel 		if (ep == loopback_interface)
2003abb0f93cSkardel 			loopback_interface = NULL;
2004abb0f93cSkardel 
200545530cf1Skardel 		delete_interface(ep);
2006abb0f93cSkardel 	}
2007abb0f93cSkardel 
2008abb0f93cSkardel 	/*
2009b3d6264cSchristos 	 * phase 3 - re-configure as the world has possibly changed
2010b3d6264cSchristos 	 *
2011b3d6264cSchristos 	 * never ever make this conditional again - it is needed to track
2012b3d6264cSchristos 	 * routing updates. see bug #2506
2013abb0f93cSkardel 	 */
2014abb0f93cSkardel 	refresh_all_peerinterfaces();
2015b3d6264cSchristos 
2016b3d6264cSchristos 	if (broadcast_client_enabled)
2017b3d6264cSchristos 		io_setbclient();
201845530cf1Skardel 
2019766d83b9Skardel 	if (sys_bclient)
2020766d83b9Skardel 		io_setbclient();
2021766d83b9Skardel 
202209f14f80Schristos #ifdef MCAST
20234e3b3909Schristos 	/*
20244e3b3909Schristos 	 * Check multicast interfaces and try to join multicast groups if
20254e3b3909Schristos          * not joined yet.
20264e3b3909Schristos          */
20274e3b3909Schristos 	for (ep = ep_list; ep != NULL; ep = ep->elink) {
20284e3b3909Schristos 		remaddr_t *entry;
20294e3b3909Schristos 
20304e3b3909Schristos 		if (!(INT_MCASTIF & ep->flags) || (INT_MCASTOPEN & ep->flags))
20314e3b3909Schristos 			continue;
20324e3b3909Schristos 
20334e3b3909Schristos 		/* Find remote address that was linked to this interface */
20344e3b3909Schristos 		for (entry = remoteaddr_list;
20354e3b3909Schristos 		     entry != NULL;
20364e3b3909Schristos 		     entry = entry->link) {
20374e3b3909Schristos 			if (entry->ep == ep) {
20384e3b3909Schristos 				if (socket_multicast_enable(ep, &entry->addr)) {
20394e3b3909Schristos 					msyslog(LOG_INFO,
20404e3b3909Schristos 						"Joined %s socket to multicast group %s",
20414e3b3909Schristos 						stoa(&ep->sin),
20424e3b3909Schristos 						stoa(&entry->addr));
20434e3b3909Schristos 				}
20444e3b3909Schristos 				break;
20454e3b3909Schristos 			}
20464e3b3909Schristos 		}
20474e3b3909Schristos 	}
204809f14f80Schristos #endif /* MCAST */
20494e3b3909Schristos 
2050abb0f93cSkardel 	return new_interface_found;
2051abb0f93cSkardel }
2052abb0f93cSkardel 
2053abb0f93cSkardel 
2054abb0f93cSkardel /*
2055abb0f93cSkardel  * create_sockets - create a socket for each interface plus a default
2056abb0f93cSkardel  *			socket for when we don't know where to send
2057abb0f93cSkardel  */
2058abb0f93cSkardel static int
2059abb0f93cSkardel create_sockets(
2060abb0f93cSkardel 	u_short port
2061abb0f93cSkardel 	)
2062abb0f93cSkardel {
2063abb0f93cSkardel #ifndef HAVE_IO_COMPLETION_PORT
2064abb0f93cSkardel 	/*
2065abb0f93cSkardel 	 * I/O Completion Ports don't care about the select and FD_SET
2066abb0f93cSkardel 	 */
2067abb0f93cSkardel 	maxactivefd = 0;
2068abb0f93cSkardel 	FD_ZERO(&activefds);
2069abb0f93cSkardel #endif
2070abb0f93cSkardel 
2071abb0f93cSkardel 	DPRINTF(2, ("create_sockets(%d)\n", port));
2072abb0f93cSkardel 
2073abb0f93cSkardel 	create_wildcards(port);
2074abb0f93cSkardel 
2075abb0f93cSkardel 	update_interfaces(port, NULL, NULL);
2076abb0f93cSkardel 
2077abb0f93cSkardel 	/*
2078abb0f93cSkardel 	 * Now that we have opened all the sockets, turn off the reuse
2079abb0f93cSkardel 	 * flag for security.
2080abb0f93cSkardel 	 */
2081abb0f93cSkardel 	set_reuseaddr(0);
2082abb0f93cSkardel 
2083abb0f93cSkardel 	DPRINTF(2, ("create_sockets: Total interfaces = %d\n", ninterfaces));
2084abb0f93cSkardel 
2085abb0f93cSkardel 	return ninterfaces;
2086abb0f93cSkardel }
2087abb0f93cSkardel 
2088abb0f93cSkardel /*
2089abb0f93cSkardel  * create_interface - create a new interface for a given prototype
2090abb0f93cSkardel  *		      binding the socket.
2091abb0f93cSkardel  */
2092abb0f93cSkardel static struct interface *
2093abb0f93cSkardel create_interface(
2094abb0f93cSkardel 	u_short			port,
2095abb0f93cSkardel 	struct interface *	protot
2096abb0f93cSkardel 	)
2097abb0f93cSkardel {
2098abb0f93cSkardel 	sockaddr_u	resmask;
209945530cf1Skardel 	endpt *		iface;
210045530cf1Skardel #if defined(MCAST) && defined(MULTICAST_NONEWSOCKET)
210145530cf1Skardel 	remaddr_t *	entry;
210245530cf1Skardel 	remaddr_t *	next_entry;
210345530cf1Skardel #endif
2104abb0f93cSkardel 	DPRINTF(2, ("create_interface(%s#%d)\n", stoa(&protot->sin),
2105abb0f93cSkardel 		    port));
2106abb0f93cSkardel 
2107abb0f93cSkardel 	/* build an interface */
2108abb0f93cSkardel 	iface = new_interface(protot);
2109abb0f93cSkardel 
2110abb0f93cSkardel 	/*
2111abb0f93cSkardel 	 * create socket
2112abb0f93cSkardel 	 */
2113abb0f93cSkardel 	iface->fd = open_socket(&iface->sin, 0, 0, iface);
2114abb0f93cSkardel 
2115abb0f93cSkardel 	if (iface->fd != INVALID_SOCKET)
211645530cf1Skardel 		log_listen_address(iface);
2117abb0f93cSkardel 
2118abb0f93cSkardel 	if ((INT_BROADCAST & iface->flags)
2119abb0f93cSkardel 	    && iface->bfd != INVALID_SOCKET)
2120abb0f93cSkardel 		msyslog(LOG_INFO, "Listening on broadcast address %s#%d",
2121abb0f93cSkardel 			stoa((&iface->bcast)), port);
2122abb0f93cSkardel 
2123abb0f93cSkardel 	if (INVALID_SOCKET == iface->fd
2124abb0f93cSkardel 	    && INVALID_SOCKET == iface->bfd) {
2125abb0f93cSkardel 		msyslog(LOG_ERR, "unable to create socket on %s (%d) for %s#%d",
2126abb0f93cSkardel 			iface->name,
2127abb0f93cSkardel 			iface->ifnum,
2128abb0f93cSkardel 			stoa((&iface->sin)),
2129abb0f93cSkardel 			port);
2130abb0f93cSkardel 		delete_interface(iface);
2131abb0f93cSkardel 		return NULL;
2132abb0f93cSkardel 	}
2133abb0f93cSkardel 
2134abb0f93cSkardel 	/*
2135abb0f93cSkardel 	 * Blacklist our own addresses, no use talking to ourself
2136abb0f93cSkardel 	 */
2137abb0f93cSkardel 	SET_HOSTMASK(&resmask, AF(&iface->sin));
2138abb0f93cSkardel 	hack_restrict(RESTRICT_FLAGS, &iface->sin, &resmask,
2139b3d6264cSchristos 		      RESM_NTPONLY | RESM_INTERFACE, RES_IGNORE, 0);
2140abb0f93cSkardel 
2141abb0f93cSkardel 	/*
2142abb0f93cSkardel 	 * set globals with the first found
2143abb0f93cSkardel 	 * loopback interface of the appropriate class
2144abb0f93cSkardel 	 */
2145abb0f93cSkardel 	if (NULL == loopback_interface && AF_INET == iface->family
2146abb0f93cSkardel 	    && (INT_LOOPBACK & iface->flags))
2147abb0f93cSkardel 		loopback_interface = iface;
2148abb0f93cSkardel 
2149abb0f93cSkardel 	/*
2150abb0f93cSkardel 	 * put into our interface list
2151abb0f93cSkardel 	 */
2152abb0f93cSkardel 	add_addr_to_list(&iface->sin, iface);
2153abb0f93cSkardel 	add_interface(iface);
2154abb0f93cSkardel 
215545530cf1Skardel #if defined(MCAST) && defined(MULTICAST_NONEWSOCKET)
215645530cf1Skardel 	/*
215745530cf1Skardel 	 * Join any previously-configured compatible multicast groups.
215845530cf1Skardel 	 */
215945530cf1Skardel 	if (INT_MULTICAST & iface->flags &&
216045530cf1Skardel 	    !((INT_LOOPBACK | INT_WILDCARD) & iface->flags) &&
216145530cf1Skardel 	    !iface->ignore_packets) {
216245530cf1Skardel 		for (entry = remoteaddr_list;
216345530cf1Skardel 		     entry != NULL;
216445530cf1Skardel 		     entry = next_entry) {
216545530cf1Skardel 			next_entry = entry->link;
216645530cf1Skardel 			if (AF(&iface->sin) != AF(&entry->addr) ||
216745530cf1Skardel 			    !IS_MCAST(&entry->addr))
216845530cf1Skardel 				continue;
216945530cf1Skardel 			if (socket_multicast_enable(iface,
217045530cf1Skardel 						    &entry->addr))
217145530cf1Skardel 				msyslog(LOG_INFO,
217245530cf1Skardel 					"Joined %s socket to multicast group %s",
217345530cf1Skardel 					stoa(&iface->sin),
217445530cf1Skardel 					stoa(&entry->addr));
217545530cf1Skardel 			else
217645530cf1Skardel 				msyslog(LOG_ERR,
217745530cf1Skardel 					"Failed to join %s socket to multicast group %s",
217845530cf1Skardel 					stoa(&iface->sin),
217945530cf1Skardel 					stoa(&entry->addr));
218045530cf1Skardel 		}
218145530cf1Skardel 	}
218245530cf1Skardel #endif	/* MCAST && MCAST_NONEWSOCKET */
218345530cf1Skardel 
2184abb0f93cSkardel 	DPRINT_INTERFACE(2, (iface, "created ", "\n"));
2185abb0f93cSkardel 	return iface;
2186abb0f93cSkardel }
2187abb0f93cSkardel 
2188abb0f93cSkardel 
2189abb0f93cSkardel #ifdef SO_EXCLUSIVEADDRUSE
2190abb0f93cSkardel static void
2191abb0f93cSkardel set_excladdruse(
2192abb0f93cSkardel 	SOCKET fd
2193abb0f93cSkardel 	)
2194abb0f93cSkardel {
2195abb0f93cSkardel 	int one = 1;
2196abb0f93cSkardel 	int failed;
2197abb0f93cSkardel #ifdef SYS_WINNT
2198abb0f93cSkardel 	DWORD err;
2199abb0f93cSkardel #endif
2200abb0f93cSkardel 
2201abb0f93cSkardel 	failed = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
2202abb0f93cSkardel 			    (char *)&one, sizeof(one));
2203abb0f93cSkardel 
2204abb0f93cSkardel 	if (!failed)
2205abb0f93cSkardel 		return;
2206abb0f93cSkardel 
2207abb0f93cSkardel #ifdef SYS_WINNT
2208abb0f93cSkardel 	/*
2209abb0f93cSkardel 	 * Prior to Windows XP setting SO_EXCLUSIVEADDRUSE can fail with
2210abb0f93cSkardel 	 * error WSAINVAL depending on service pack level and whether
2211abb0f93cSkardel 	 * the user account is in the Administrators group.  Do not
2212abb0f93cSkardel 	 * complain if it fails that way on versions prior to XP (5.1).
2213abb0f93cSkardel 	 */
2214abb0f93cSkardel 	err = GetLastError();
2215abb0f93cSkardel 
2216abb0f93cSkardel 	if (isc_win32os_versioncheck(5, 1, 0, 0) < 0	/* < 5.1/XP */
2217abb0f93cSkardel 	    && WSAEINVAL == err)
2218abb0f93cSkardel 		return;
2219abb0f93cSkardel 
2220abb0f93cSkardel 	SetLastError(err);
2221abb0f93cSkardel #endif
2222abb0f93cSkardel 	msyslog(LOG_ERR,
2223abb0f93cSkardel 		"setsockopt(%d, SO_EXCLUSIVEADDRUSE, on): %m",
2224abb0f93cSkardel 		(int)fd);
2225abb0f93cSkardel }
2226abb0f93cSkardel #endif  /* SO_EXCLUSIVEADDRUSE */
2227abb0f93cSkardel 
2228abb0f93cSkardel 
2229abb0f93cSkardel /*
2230abb0f93cSkardel  * set_reuseaddr() - set/clear REUSEADDR on all sockets
2231abb0f93cSkardel  *			NB possible hole - should we be doing this on broadcast
2232abb0f93cSkardel  *			fd's also?
2233abb0f93cSkardel  */
2234abb0f93cSkardel static void
2235abb0f93cSkardel set_reuseaddr(
2236abb0f93cSkardel 	int flag
2237abb0f93cSkardel 	)
2238abb0f93cSkardel {
2239abb0f93cSkardel #ifndef SO_EXCLUSIVEADDRUSE
224045530cf1Skardel 	endpt *ep;
2241abb0f93cSkardel 
224245530cf1Skardel 	for (ep = ep_list; ep != NULL; ep = ep->elink) {
224345530cf1Skardel 		if (ep->flags & INT_WILDCARD)
2244abb0f93cSkardel 			continue;
2245abb0f93cSkardel 
2246abb0f93cSkardel 		/*
224745530cf1Skardel 		 * if ep->fd  is INVALID_SOCKET, we might have a adapter
2248abb0f93cSkardel 		 * configured but not present
2249abb0f93cSkardel 		 */
2250abb0f93cSkardel 		DPRINTF(4, ("setting SO_REUSEADDR on %.16s@%s to %s\n",
225145530cf1Skardel 			    ep->name, stoa(&ep->sin),
2252abb0f93cSkardel 			    flag ? "on" : "off"));
2253abb0f93cSkardel 
225445530cf1Skardel 		if (ep->fd != INVALID_SOCKET) {
225545530cf1Skardel 			if (setsockopt(ep->fd, SOL_SOCKET, SO_REUSEADDR,
225645530cf1Skardel 				       (char *)&flag, sizeof(flag))) {
225745530cf1Skardel 				msyslog(LOG_ERR, "set_reuseaddr: setsockopt(%s, SO_REUSEADDR, %s) failed: %m",
225845530cf1Skardel 					stoa(&ep->sin), flag ? "on" : "off");
2259abb0f93cSkardel 			}
2260abb0f93cSkardel 		}
2261abb0f93cSkardel 	}
2262abb0f93cSkardel #endif /* ! SO_EXCLUSIVEADDRUSE */
2263abb0f93cSkardel }
2264abb0f93cSkardel 
2265abb0f93cSkardel /*
2266abb0f93cSkardel  * This is just a wrapper around an internal function so we can
2267abb0f93cSkardel  * make other changes as necessary later on
2268abb0f93cSkardel  */
2269abb0f93cSkardel void
2270abb0f93cSkardel enable_broadcast(
2271abb0f93cSkardel 	struct interface *	iface,
2272abb0f93cSkardel 	sockaddr_u *		baddr
2273abb0f93cSkardel 	)
2274abb0f93cSkardel {
2275abb0f93cSkardel #ifdef OPEN_BCAST_SOCKET
2276abb0f93cSkardel 	socket_broadcast_enable(iface, iface->fd, baddr);
2277abb0f93cSkardel #endif
2278abb0f93cSkardel }
2279abb0f93cSkardel 
2280abb0f93cSkardel #ifdef OPEN_BCAST_SOCKET
2281abb0f93cSkardel /*
2282abb0f93cSkardel  * Enable a broadcast address to a given socket
2283b3d6264cSchristos  * The socket is in the ep_list all we need to do is enable
2284abb0f93cSkardel  * broadcasting. It is not this function's job to select the socket
2285abb0f93cSkardel  */
2286abb0f93cSkardel static isc_boolean_t
2287abb0f93cSkardel socket_broadcast_enable(
2288abb0f93cSkardel 	struct interface *	iface,
2289abb0f93cSkardel 	SOCKET			fd,
2290abb0f93cSkardel 	sockaddr_u *		baddr
2291abb0f93cSkardel 	)
2292abb0f93cSkardel {
2293abb0f93cSkardel #ifdef SO_BROADCAST
2294abb0f93cSkardel 	int on = 1;
2295abb0f93cSkardel 
2296abb0f93cSkardel 	if (IS_IPV4(baddr)) {
2297abb0f93cSkardel 		/* if this interface can support broadcast, set SO_BROADCAST */
2298abb0f93cSkardel 		if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
2299abb0f93cSkardel 			       (char *)&on, sizeof(on)))
2300abb0f93cSkardel 			msyslog(LOG_ERR,
2301abb0f93cSkardel 				"setsockopt(SO_BROADCAST) enable failure on address %s: %m",
2302abb0f93cSkardel 				stoa(baddr));
2303abb0f93cSkardel 		else
2304abb0f93cSkardel 			DPRINTF(2, ("Broadcast enabled on socket %d for address %s\n",
2305abb0f93cSkardel 				    fd, stoa(baddr)));
2306abb0f93cSkardel 	}
2307b3d6264cSchristos 	iface->flags |= INT_BCASTXMIT;
2308abb0f93cSkardel 	return ISC_TRUE;
2309abb0f93cSkardel #else
2310abb0f93cSkardel 	return ISC_FALSE;
2311abb0f93cSkardel #endif /* SO_BROADCAST */
2312abb0f93cSkardel }
2313abb0f93cSkardel 
2314ad131110Schristos #ifdef  OS_MISSES_SPECIFIC_ROUTE_UPDATES
2315abb0f93cSkardel /*
2316abb0f93cSkardel  * Remove a broadcast address from a given socket
2317b3d6264cSchristos  * The socket is in the ep_list all we need to do is disable
2318abb0f93cSkardel  * broadcasting. It is not this function's job to select the socket
2319abb0f93cSkardel  */
2320abb0f93cSkardel static isc_boolean_t
2321abb0f93cSkardel socket_broadcast_disable(
2322abb0f93cSkardel 	struct interface *	iface,
2323abb0f93cSkardel 	sockaddr_u *		baddr
2324abb0f93cSkardel 	)
2325abb0f93cSkardel {
2326abb0f93cSkardel #ifdef SO_BROADCAST
2327abb0f93cSkardel 	int off = 0;	/* This seems to be OK as an int */
2328abb0f93cSkardel 
2329abb0f93cSkardel 	if (IS_IPV4(baddr) && setsockopt(iface->fd, SOL_SOCKET,
2330abb0f93cSkardel 	    SO_BROADCAST, (char *)&off, sizeof(off)))
2331abb0f93cSkardel 		msyslog(LOG_ERR,
2332abb0f93cSkardel 			"setsockopt(SO_BROADCAST) disable failure on address %s: %m",
2333abb0f93cSkardel 			stoa(baddr));
2334abb0f93cSkardel 
2335b3d6264cSchristos 	iface->flags &= ~INT_BCASTXMIT;
2336abb0f93cSkardel 	return ISC_TRUE;
2337abb0f93cSkardel #else
2338abb0f93cSkardel 	return ISC_FALSE;
2339abb0f93cSkardel #endif /* SO_BROADCAST */
2340abb0f93cSkardel }
2341ad131110Schristos #endif /* OS_MISSES_SPECIFIC_ROUTE_UPDATES */
2342abb0f93cSkardel 
2343abb0f93cSkardel #endif /* OPEN_BCAST_SOCKET */
2344abb0f93cSkardel 
2345abb0f93cSkardel /*
2346abb0f93cSkardel  * return the broadcast client flag value
2347abb0f93cSkardel  */
2348abb0f93cSkardel isc_boolean_t
2349abb0f93cSkardel get_broadcastclient_flag(void)
2350abb0f93cSkardel {
2351abb0f93cSkardel 	return (broadcast_client_enabled);
2352abb0f93cSkardel }
2353335f7552Schristos 
2354abb0f93cSkardel /*
2355abb0f93cSkardel  * Check to see if the address is a multicast address
2356abb0f93cSkardel  */
2357abb0f93cSkardel static isc_boolean_t
2358abb0f93cSkardel addr_ismulticast(
2359abb0f93cSkardel 	sockaddr_u *maddr
2360abb0f93cSkardel 	)
2361abb0f93cSkardel {
2362abb0f93cSkardel 	isc_boolean_t result;
2363abb0f93cSkardel 
2364abb0f93cSkardel #ifndef INCLUDE_IPV6_MULTICAST_SUPPORT
2365abb0f93cSkardel 	/*
2366abb0f93cSkardel 	 * If we don't have IPV6 support any IPV6 addr is not multicast
2367abb0f93cSkardel 	 */
2368abb0f93cSkardel 	if (IS_IPV6(maddr))
2369abb0f93cSkardel 		result = ISC_FALSE;
2370abb0f93cSkardel 	else
2371abb0f93cSkardel #endif
2372abb0f93cSkardel 		result = IS_MCAST(maddr);
2373abb0f93cSkardel 
2374abb0f93cSkardel 	if (!result)
2375abb0f93cSkardel 		DPRINTF(4, ("address %s is not multicast\n",
2376abb0f93cSkardel 			    stoa(maddr)));
2377abb0f93cSkardel 
2378abb0f93cSkardel 	return result;
2379abb0f93cSkardel }
2380abb0f93cSkardel 
2381abb0f93cSkardel /*
2382abb0f93cSkardel  * Multicast servers need to set the appropriate Multicast interface
2383abb0f93cSkardel  * socket option in order for it to know which interface to use for
2384abb0f93cSkardel  * send the multicast packet.
2385abb0f93cSkardel  */
2386abb0f93cSkardel void
2387abb0f93cSkardel enable_multicast_if(
2388abb0f93cSkardel 	struct interface *	iface,
2389abb0f93cSkardel 	sockaddr_u *		maddr
2390abb0f93cSkardel 	)
2391abb0f93cSkardel {
2392abb0f93cSkardel #ifdef MCAST
2393b3d6264cSchristos #ifdef IP_MULTICAST_LOOP
2394abb0f93cSkardel 	TYPEOF_IP_MULTICAST_LOOP off = 0;
2395b3d6264cSchristos #endif
239670953dd2Sprlw1 #if defined(INCLUDE_IPV6_MULTICAST_SUPPORT) && defined(IPV6_MULTICAST_LOOP)
2397b3d6264cSchristos 	u_int off6 = 0;
2398b3d6264cSchristos #endif
2399abb0f93cSkardel 
240009f14f80Schristos 	REQUIRE(AF(maddr) == AF(&iface->sin));
2401abb0f93cSkardel 
2402abb0f93cSkardel 	switch (AF(&iface->sin)) {
2403abb0f93cSkardel 
2404abb0f93cSkardel 	case AF_INET:
2405abb0f93cSkardel #ifdef IP_MULTICAST_LOOP
2406abb0f93cSkardel 		/*
2407abb0f93cSkardel 		 * Don't send back to itself, but allow failure to set
2408abb0f93cSkardel 		 */
2409abb0f93cSkardel 		if (setsockopt(iface->fd, IPPROTO_IP,
2410abb0f93cSkardel 			       IP_MULTICAST_LOOP,
2411abb0f93cSkardel 			       SETSOCKOPT_ARG_CAST &off,
2412abb0f93cSkardel 			       sizeof(off))) {
2413abb0f93cSkardel 
2414abb0f93cSkardel 			msyslog(LOG_ERR,
2415abb0f93cSkardel 				"setsockopt IP_MULTICAST_LOOP failed: %m on socket %d, addr %s for multicast address %s",
2416abb0f93cSkardel 				iface->fd, stoa(&iface->sin),
2417abb0f93cSkardel 				stoa(maddr));
2418abb0f93cSkardel 		}
2419abb0f93cSkardel #endif
2420abb0f93cSkardel 		break;
2421abb0f93cSkardel 
2422abb0f93cSkardel 	case AF_INET6:
2423abb0f93cSkardel #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
2424abb0f93cSkardel #ifdef IPV6_MULTICAST_LOOP
2425abb0f93cSkardel 		/*
2426abb0f93cSkardel 		 * Don't send back to itself, but allow failure to set
2427abb0f93cSkardel 		 */
2428abb0f93cSkardel 		if (setsockopt(iface->fd, IPPROTO_IPV6,
2429abb0f93cSkardel 			       IPV6_MULTICAST_LOOP,
2430b3d6264cSchristos 			       (char *) &off6, sizeof(off6))) {
2431abb0f93cSkardel 
2432abb0f93cSkardel 			msyslog(LOG_ERR,
2433b3d6264cSchristos 				"setsockopt IPV6_MULTICAST_LOOP failed: %m on socket %d, addr %s for multicast address %s",
2434abb0f93cSkardel 				iface->fd, stoa(&iface->sin),
2435abb0f93cSkardel 				stoa(maddr));
2436abb0f93cSkardel 		}
2437abb0f93cSkardel #endif
2438abb0f93cSkardel 		break;
2439abb0f93cSkardel #else
2440abb0f93cSkardel 		return;
2441abb0f93cSkardel #endif	/* INCLUDE_IPV6_MULTICAST_SUPPORT */
2442abb0f93cSkardel 	}
2443abb0f93cSkardel 	return;
2444abb0f93cSkardel #endif
2445abb0f93cSkardel }
2446abb0f93cSkardel 
2447abb0f93cSkardel /*
2448abb0f93cSkardel  * Add a multicast address to a given socket
2449b3d6264cSchristos  * The socket is in the ep_list all we need to do is enable
2450abb0f93cSkardel  * multicasting. It is not this function's job to select the socket
2451abb0f93cSkardel  */
245245530cf1Skardel #if defined(MCAST)
2453abb0f93cSkardel static isc_boolean_t
2454abb0f93cSkardel socket_multicast_enable(
245545530cf1Skardel 	endpt *		iface,
2456abb0f93cSkardel 	sockaddr_u *	maddr
2457abb0f93cSkardel 	)
2458abb0f93cSkardel {
2459abb0f93cSkardel 	struct ip_mreq		mreq;
2460abb0f93cSkardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
2461abb0f93cSkardel 	struct ipv6_mreq	mreq6;
2462abb0f93cSkardel # endif
2463abb0f93cSkardel 	switch (AF(maddr)) {
2464abb0f93cSkardel 
2465abb0f93cSkardel 	case AF_INET:
2466b3d6264cSchristos 		ZERO(mreq);
2467abb0f93cSkardel 		mreq.imr_multiaddr = SOCK_ADDR4(maddr);
2468abb0f93cSkardel 		mreq.imr_interface.s_addr = htonl(INADDR_ANY);
2469abb0f93cSkardel 		if (setsockopt(iface->fd,
2470abb0f93cSkardel 			       IPPROTO_IP,
2471abb0f93cSkardel 			       IP_ADD_MEMBERSHIP,
2472abb0f93cSkardel 			       (char *)&mreq,
2473abb0f93cSkardel 			       sizeof(mreq))) {
24744e3b3909Schristos 			DPRINTF(2, (
2475abb0f93cSkardel 				"setsockopt IP_ADD_MEMBERSHIP failed: %m on socket %d, addr %s for %x / %x (%s)",
2476abb0f93cSkardel 				iface->fd, stoa(&iface->sin),
2477abb0f93cSkardel 				mreq.imr_multiaddr.s_addr,
2478abb0f93cSkardel 				mreq.imr_interface.s_addr,
24794e3b3909Schristos 				stoa(maddr)));
2480abb0f93cSkardel 			return ISC_FALSE;
2481abb0f93cSkardel 		}
2482abb0f93cSkardel 		DPRINTF(4, ("Added IPv4 multicast membership on socket %d, addr %s for %x / %x (%s)\n",
2483abb0f93cSkardel 			    iface->fd, stoa(&iface->sin),
2484abb0f93cSkardel 			    mreq.imr_multiaddr.s_addr,
2485abb0f93cSkardel 			    mreq.imr_interface.s_addr, stoa(maddr)));
2486abb0f93cSkardel 		break;
2487abb0f93cSkardel 
2488abb0f93cSkardel 	case AF_INET6:
2489abb0f93cSkardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
2490abb0f93cSkardel 		/*
2491abb0f93cSkardel 		 * Enable reception of multicast packets.
2492abb0f93cSkardel 		 * If the address is link-local we can get the
2493abb0f93cSkardel 		 * interface index from the scope id. Don't do this
2494abb0f93cSkardel 		 * for other types of multicast addresses. For now let
2495abb0f93cSkardel 		 * the kernel figure it out.
2496abb0f93cSkardel 		 */
2497b3d6264cSchristos 		ZERO(mreq6);
2498abb0f93cSkardel 		mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr);
249945530cf1Skardel 		mreq6.ipv6mr_interface = iface->ifindex;
2500abb0f93cSkardel 
2501abb0f93cSkardel 		if (setsockopt(iface->fd, IPPROTO_IPV6,
2502abb0f93cSkardel 			       IPV6_JOIN_GROUP, (char *)&mreq6,
2503abb0f93cSkardel 			       sizeof(mreq6))) {
25044e3b3909Schristos 			DPRINTF(2, (
250545530cf1Skardel 				"setsockopt IPV6_JOIN_GROUP failed: %m on socket %d, addr %s for interface %u (%s)",
2506abb0f93cSkardel 				iface->fd, stoa(&iface->sin),
25074e3b3909Schristos 				mreq6.ipv6mr_interface, stoa(maddr)));
2508abb0f93cSkardel 			return ISC_FALSE;
2509abb0f93cSkardel 		}
251045530cf1Skardel 		DPRINTF(4, ("Added IPv6 multicast group on socket %d, addr %s for interface %u (%s)\n",
2511abb0f93cSkardel 			    iface->fd, stoa(&iface->sin),
2512abb0f93cSkardel 			    mreq6.ipv6mr_interface, stoa(maddr)));
2513abb0f93cSkardel # else
2514abb0f93cSkardel 		return ISC_FALSE;
2515abb0f93cSkardel # endif	/* INCLUDE_IPV6_MULTICAST_SUPPORT */
2516abb0f93cSkardel 	}
2517abb0f93cSkardel 	iface->flags |= INT_MCASTOPEN;
2518abb0f93cSkardel 	iface->num_mcast++;
251945530cf1Skardel 
2520abb0f93cSkardel 	return ISC_TRUE;
2521abb0f93cSkardel }
252245530cf1Skardel #endif	/* MCAST */
252345530cf1Skardel 
2524abb0f93cSkardel 
2525abb0f93cSkardel /*
2526abb0f93cSkardel  * Remove a multicast address from a given socket
2527b3d6264cSchristos  * The socket is in the ep_list all we need to do is disable
2528abb0f93cSkardel  * multicasting. It is not this function's job to select the socket
2529abb0f93cSkardel  */
253045530cf1Skardel #ifdef MCAST
2531abb0f93cSkardel static isc_boolean_t
2532abb0f93cSkardel socket_multicast_disable(
2533abb0f93cSkardel 	struct interface *	iface,
2534abb0f93cSkardel 	sockaddr_u *		maddr
2535abb0f93cSkardel 	)
2536abb0f93cSkardel {
2537abb0f93cSkardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
2538abb0f93cSkardel 	struct ipv6_mreq mreq6;
2539abb0f93cSkardel # endif
2540abb0f93cSkardel 	struct ip_mreq mreq;
2541abb0f93cSkardel 
2542b3d6264cSchristos 	ZERO(mreq);
2543abb0f93cSkardel 
2544abb0f93cSkardel 	if (find_addr_in_list(maddr) == NULL) {
2545abb0f93cSkardel 		DPRINTF(4, ("socket_multicast_disable(%s): not found\n",
2546abb0f93cSkardel 			    stoa(maddr)));
2547abb0f93cSkardel 		return ISC_TRUE;
2548abb0f93cSkardel 	}
2549abb0f93cSkardel 
2550abb0f93cSkardel 	switch (AF(maddr)) {
2551abb0f93cSkardel 
2552abb0f93cSkardel 	case AF_INET:
2553abb0f93cSkardel 		mreq.imr_multiaddr = SOCK_ADDR4(maddr);
2554abb0f93cSkardel 		mreq.imr_interface = SOCK_ADDR4(&iface->sin);
2555abb0f93cSkardel 		if (setsockopt(iface->fd, IPPROTO_IP,
2556abb0f93cSkardel 			       IP_DROP_MEMBERSHIP, (char *)&mreq,
2557abb0f93cSkardel 			       sizeof(mreq))) {
2558abb0f93cSkardel 
2559abb0f93cSkardel 			msyslog(LOG_ERR,
2560abb0f93cSkardel 				"setsockopt IP_DROP_MEMBERSHIP failed: %m on socket %d, addr %s for %x / %x (%s)",
2561abb0f93cSkardel 				iface->fd, stoa(&iface->sin),
2562abb0f93cSkardel 				SRCADR(maddr), SRCADR(&iface->sin),
2563abb0f93cSkardel 				stoa(maddr));
2564abb0f93cSkardel 			return ISC_FALSE;
2565abb0f93cSkardel 		}
2566abb0f93cSkardel 		break;
2567abb0f93cSkardel 	case AF_INET6:
2568abb0f93cSkardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
2569abb0f93cSkardel 		/*
2570abb0f93cSkardel 		 * Disable reception of multicast packets
2571abb0f93cSkardel 		 * If the address is link-local we can get the
2572abb0f93cSkardel 		 * interface index from the scope id.  Don't do this
2573abb0f93cSkardel 		 * for other types of multicast addresses. For now let
2574abb0f93cSkardel 		 * the kernel figure it out.
2575abb0f93cSkardel 		 */
2576abb0f93cSkardel 		mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr);
257745530cf1Skardel 		mreq6.ipv6mr_interface = iface->ifindex;
2578abb0f93cSkardel 
2579abb0f93cSkardel 		if (setsockopt(iface->fd, IPPROTO_IPV6,
2580abb0f93cSkardel 			       IPV6_LEAVE_GROUP, (char *)&mreq6,
2581abb0f93cSkardel 			       sizeof(mreq6))) {
2582abb0f93cSkardel 
2583abb0f93cSkardel 			msyslog(LOG_ERR,
2584abb0f93cSkardel 				"setsockopt IPV6_LEAVE_GROUP failure: %m on socket %d, addr %s for %d (%s)",
2585abb0f93cSkardel 				iface->fd, stoa(&iface->sin),
258645530cf1Skardel 				iface->ifindex, stoa(maddr));
2587abb0f93cSkardel 			return ISC_FALSE;
2588abb0f93cSkardel 		}
2589abb0f93cSkardel 		break;
2590abb0f93cSkardel # else
2591abb0f93cSkardel 		return ISC_FALSE;
2592abb0f93cSkardel # endif	/* INCLUDE_IPV6_MULTICAST_SUPPORT */
2593abb0f93cSkardel 	}
2594abb0f93cSkardel 
2595abb0f93cSkardel 	iface->num_mcast--;
2596abb0f93cSkardel 	if (!iface->num_mcast)
2597abb0f93cSkardel 		iface->flags &= ~INT_MCASTOPEN;
2598abb0f93cSkardel 
2599abb0f93cSkardel 	return ISC_TRUE;
2600abb0f93cSkardel }
2601abb0f93cSkardel #endif	/* MCAST */
2602abb0f93cSkardel 
2603abb0f93cSkardel /*
2604abb0f93cSkardel  * io_setbclient - open the broadcast client sockets
2605abb0f93cSkardel  */
2606abb0f93cSkardel void
2607abb0f93cSkardel io_setbclient(void)
2608abb0f93cSkardel {
2609abb0f93cSkardel #ifdef OPEN_BCAST_SOCKET
2610abb0f93cSkardel 	struct interface *	interf;
2611*1c24ec91Schristos 	unsigned int		nif;
2612abb0f93cSkardel 
2613abb0f93cSkardel 	nif = 0;
2614abb0f93cSkardel 	set_reuseaddr(1);
2615abb0f93cSkardel 
261645530cf1Skardel 	for (interf = ep_list;
2617abb0f93cSkardel 	     interf != NULL;
261845530cf1Skardel 	     interf = interf->elink) {
2619abb0f93cSkardel 
2620abb0f93cSkardel 		if (interf->flags & (INT_WILDCARD | INT_LOOPBACK))
2621abb0f93cSkardel 			continue;
2622abb0f93cSkardel 
2623abb0f93cSkardel 		/* use only allowed addresses */
2624abb0f93cSkardel 		if (interf->ignore_packets)
2625abb0f93cSkardel 			continue;
2626abb0f93cSkardel 
2627abb0f93cSkardel 		/* Need a broadcast-capable interface */
2628abb0f93cSkardel 		if (!(interf->flags & INT_BROADCAST))
2629abb0f93cSkardel 			continue;
2630abb0f93cSkardel 
2631abb0f93cSkardel 		/* Only IPv4 addresses are valid for broadcast */
2632335f7552Schristos 		REQUIRE(IS_IPV4(&interf->bcast));
2633abb0f93cSkardel 
2634abb0f93cSkardel 		/* Do we already have the broadcast address open? */
2635abb0f93cSkardel 		if (interf->flags & INT_BCASTOPEN) {
2636abb0f93cSkardel 			/*
2637abb0f93cSkardel 			 * account for already open interfaces to avoid
2638abb0f93cSkardel 			 * misleading warning below
2639abb0f93cSkardel 			 */
2640abb0f93cSkardel 			nif++;
2641abb0f93cSkardel 			continue;
2642abb0f93cSkardel 		}
2643abb0f93cSkardel 
2644abb0f93cSkardel 		/*
2645abb0f93cSkardel 		 * Try to open the broadcast address
2646abb0f93cSkardel 		 */
2647abb0f93cSkardel 		interf->family = AF_INET;
2648abb0f93cSkardel 		interf->bfd = open_socket(&interf->bcast, 1, 0, interf);
2649abb0f93cSkardel 
2650abb0f93cSkardel 		/*
2651abb0f93cSkardel 		 * If we succeeded then we use it otherwise enable
2652abb0f93cSkardel 		 * broadcast on the interface address
2653abb0f93cSkardel 		 */
2654abb0f93cSkardel 		if (interf->bfd != INVALID_SOCKET) {
2655abb0f93cSkardel 			nif++;
2656b3d6264cSchristos 			interf->flags |= INT_BCASTOPEN;
2657abb0f93cSkardel 			msyslog(LOG_INFO,
2658b3d6264cSchristos 				"Listen for broadcasts to %s on interface #%d %s",
2659b3d6264cSchristos 				stoa(&interf->bcast), interf->ifnum, interf->name);
2660335f7552Schristos 		} else switch (errno) {
2661335f7552Schristos 			/* Silently ignore EADDRINUSE as we probably
2662335f7552Schristos 			 * opened the socket already for an address in
2663335f7552Schristos 			 * the same network */
2664335f7552Schristos 		case EADDRINUSE:
2665335f7552Schristos 			/* Some systems cannot bind a socket to a broadcast
2666335f7552Schristos 			 * address, as that is not a valid host address. */
2667335f7552Schristos 		case EADDRNOTAVAIL:
2668335f7552Schristos #		    ifdef SYS_WINNT	/*TODO: use for other systems, too? */
2669335f7552Schristos 			/* avoid recurrence here -- if we already have a
2670335f7552Schristos 			 * regular socket, it's quite useless to try this
2671335f7552Schristos 			 * again.
2672335f7552Schristos 			 */
2673335f7552Schristos 			if (interf->fd != INVALID_SOCKET) {
2674335f7552Schristos 				interf->flags |= INT_BCASTOPEN;
2675335f7552Schristos 				nif++;
2676335f7552Schristos 			}
2677335f7552Schristos #		    endif
2678335f7552Schristos 			break;
2679335f7552Schristos 
2680335f7552Schristos 		default:
2681b3d6264cSchristos 			msyslog(LOG_INFO,
2682b3d6264cSchristos 				"failed to listen for broadcasts to %s on interface #%d %s",
2683b3d6264cSchristos 				stoa(&interf->bcast), interf->ifnum, interf->name);
2684335f7552Schristos 			break;
2685abb0f93cSkardel 		}
2686abb0f93cSkardel 	}
2687abb0f93cSkardel 	set_reuseaddr(0);
2688*1c24ec91Schristos 	if (nif != 0) {
2689b3d6264cSchristos 		broadcast_client_enabled = ISC_TRUE;
2690b3d6264cSchristos 		DPRINTF(1, ("io_setbclient: listening to %d broadcast addresses\n", nif));
2691*1c24ec91Schristos 	} else {
2692b3d6264cSchristos 		broadcast_client_enabled = ISC_FALSE;
2693abb0f93cSkardel 		msyslog(LOG_ERR,
2694abb0f93cSkardel 			"Unable to listen for broadcasts, no broadcast interfaces available");
2695b3d6264cSchristos 	}
2696abb0f93cSkardel #else
2697abb0f93cSkardel 	msyslog(LOG_ERR,
2698abb0f93cSkardel 		"io_setbclient: Broadcast Client disabled by build");
2699abb0f93cSkardel #endif	/* OPEN_BCAST_SOCKET */
2700abb0f93cSkardel }
2701abb0f93cSkardel 
2702abb0f93cSkardel /*
2703abb0f93cSkardel  * io_unsetbclient - close the broadcast client sockets
2704abb0f93cSkardel  */
2705abb0f93cSkardel void
2706abb0f93cSkardel io_unsetbclient(void)
2707abb0f93cSkardel {
270845530cf1Skardel 	endpt *ep;
2709abb0f93cSkardel 
271045530cf1Skardel 	for (ep = ep_list; ep != NULL; ep = ep->elink) {
271145530cf1Skardel 		if (INT_WILDCARD & ep->flags)
2712abb0f93cSkardel 			continue;
271345530cf1Skardel 		if (!(INT_BCASTOPEN & ep->flags))
2714abb0f93cSkardel 			continue;
2715b3d6264cSchristos 
2716b3d6264cSchristos 		if (ep->bfd != INVALID_SOCKET) {
2717b3d6264cSchristos 			/* destroy broadcast listening socket */
2718b3d6264cSchristos 			msyslog(LOG_INFO,
2719b3d6264cSchristos 				"stop listening for broadcasts to %s on interface #%d %s",
2720b3d6264cSchristos 				stoa(&ep->bcast), ep->ifnum, ep->name);
2721335f7552Schristos #		    ifdef HAVE_IO_COMPLETION_PORT
2722335f7552Schristos 			io_completion_port_remove_socket(ep->bfd, ep);
2723335f7552Schristos #		    endif
2724b3d6264cSchristos 			close_and_delete_fd_from_list(ep->bfd);
2725b3d6264cSchristos 			ep->bfd = INVALID_SOCKET;
2726abb0f93cSkardel 		}
2727335f7552Schristos 		ep->flags &= ~INT_BCASTOPEN;
2728abb0f93cSkardel 	}
2729b3d6264cSchristos 	broadcast_client_enabled = ISC_FALSE;
2730b3d6264cSchristos }
2731abb0f93cSkardel 
2732abb0f93cSkardel /*
2733abb0f93cSkardel  * io_multicast_add() - add multicast group address
2734abb0f93cSkardel  */
2735abb0f93cSkardel void
2736abb0f93cSkardel io_multicast_add(
2737abb0f93cSkardel 	sockaddr_u *addr
2738abb0f93cSkardel 	)
2739abb0f93cSkardel {
2740abb0f93cSkardel #ifdef MCAST
274145530cf1Skardel 	endpt *	ep;
274245530cf1Skardel 	endpt *	one_ep;
2743abb0f93cSkardel 
2744abb0f93cSkardel 	/*
2745abb0f93cSkardel 	 * Check to see if this is a multicast address
2746abb0f93cSkardel 	 */
2747abb0f93cSkardel 	if (!addr_ismulticast(addr))
2748abb0f93cSkardel 		return;
2749abb0f93cSkardel 
2750abb0f93cSkardel 	/* If we already have it we can just return */
2751abb0f93cSkardel 	if (NULL != find_flagged_addr_in_list(addr, INT_MCASTOPEN)) {
2752abb0f93cSkardel 		msyslog(LOG_INFO,
2753abb0f93cSkardel 			"Duplicate request found for multicast address %s",
2754abb0f93cSkardel 			stoa(addr));
2755abb0f93cSkardel 		return;
2756abb0f93cSkardel 	}
2757abb0f93cSkardel 
2758abb0f93cSkardel # ifndef MULTICAST_NONEWSOCKET
275945530cf1Skardel 	ep = new_interface(NULL);
2760abb0f93cSkardel 
2761abb0f93cSkardel 	/*
2762abb0f93cSkardel 	 * Open a new socket for the multicast address
2763abb0f93cSkardel 	 */
276445530cf1Skardel 	ep->sin = *addr;
276545530cf1Skardel 	SET_PORT(&ep->sin, NTP_PORT);
276645530cf1Skardel 	ep->family = AF(&ep->sin);
276745530cf1Skardel 	AF(&ep->mask) = ep->family;
276845530cf1Skardel 	SET_ONESMASK(&ep->mask);
2769abb0f93cSkardel 
2770abb0f93cSkardel 	set_reuseaddr(1);
277145530cf1Skardel 	ep->bfd = INVALID_SOCKET;
277245530cf1Skardel 	ep->fd = open_socket(&ep->sin, 0, 0, ep);
277345530cf1Skardel 	if (ep->fd != INVALID_SOCKET) {
277445530cf1Skardel 		ep->ignore_packets = ISC_FALSE;
277545530cf1Skardel 		ep->flags |= INT_MCASTIF;
2776abb0f93cSkardel 
2777b3d6264cSchristos 		strlcpy(ep->name, "multicast", sizeof(ep->name));
277845530cf1Skardel 		DPRINT_INTERFACE(2, (ep, "multicast add ", "\n"));
277945530cf1Skardel 		add_interface(ep);
278045530cf1Skardel 		log_listen_address(ep);
2781abb0f93cSkardel 	} else {
2782abb0f93cSkardel 		/* bind failed, re-use wildcard interface */
278345530cf1Skardel 		delete_interface(ep);
2784abb0f93cSkardel 
2785abb0f93cSkardel 		if (IS_IPV4(addr))
278645530cf1Skardel 			ep = wildipv4;
2787abb0f93cSkardel 		else if (IS_IPV6(addr))
278845530cf1Skardel 			ep = wildipv6;
2789abb0f93cSkardel 		else
279045530cf1Skardel 			ep = NULL;
2791abb0f93cSkardel 
279245530cf1Skardel 		if (ep != NULL) {
2793abb0f93cSkardel 			/* HACK ! -- stuff in an address */
2794abb0f93cSkardel 			/* because we don't bind addr? DH */
279545530cf1Skardel 			ep->bcast = *addr;
2796abb0f93cSkardel 			msyslog(LOG_ERR,
2797abb0f93cSkardel 				"multicast address %s using wildcard interface #%d %s",
279845530cf1Skardel 				stoa(addr), ep->ifnum, ep->name);
2799abb0f93cSkardel 		} else {
2800abb0f93cSkardel 			msyslog(LOG_ERR,
2801abb0f93cSkardel 				"No multicast socket available to use for address %s",
2802abb0f93cSkardel 				stoa(addr));
2803abb0f93cSkardel 			return;
2804abb0f93cSkardel 		}
2805abb0f93cSkardel 	}
280645530cf1Skardel 	{	/* in place of the { following for in #else clause */
280745530cf1Skardel 		one_ep = ep;
280845530cf1Skardel # else	/* MULTICAST_NONEWSOCKET follows */
2809abb0f93cSkardel 	/*
281045530cf1Skardel 	 * For the case where we can't use a separate socket (Windows)
281145530cf1Skardel 	 * join each applicable endpoint socket to the group address.
2812abb0f93cSkardel 	 */
281345530cf1Skardel 	if (IS_IPV4(addr))
281445530cf1Skardel 		one_ep = wildipv4;
281545530cf1Skardel 	else
281645530cf1Skardel 		one_ep = wildipv6;
281745530cf1Skardel 	for (ep = ep_list; ep != NULL; ep = ep->elink) {
281845530cf1Skardel 		if (ep->ignore_packets || AF(&ep->sin) != AF(addr) ||
281945530cf1Skardel 		    !(INT_MULTICAST & ep->flags) ||
282045530cf1Skardel 		    (INT_LOOPBACK | INT_WILDCARD) & ep->flags)
282145530cf1Skardel 			continue;
282245530cf1Skardel 		one_ep = ep;
282345530cf1Skardel # endif	/* MULTICAST_NONEWSOCKET */
282445530cf1Skardel 		if (socket_multicast_enable(ep, addr))
282545530cf1Skardel 			msyslog(LOG_INFO,
282645530cf1Skardel 				"Joined %s socket to multicast group %s",
282745530cf1Skardel 				stoa(&ep->sin),
2828abb0f93cSkardel 				stoa(addr));
2829abb0f93cSkardel 	}
2830abb0f93cSkardel 
283145530cf1Skardel 	add_addr_to_list(addr, one_ep);
283245530cf1Skardel #else	/* !MCAST  follows*/
2833abb0f93cSkardel 	msyslog(LOG_ERR,
2834abb0f93cSkardel 		"Can not add multicast address %s: no multicast support",
2835abb0f93cSkardel 		stoa(addr));
283645530cf1Skardel #endif
2837abb0f93cSkardel 	return;
2838abb0f93cSkardel }
2839abb0f93cSkardel 
2840abb0f93cSkardel 
2841abb0f93cSkardel /*
2842abb0f93cSkardel  * io_multicast_del() - delete multicast group address
2843abb0f93cSkardel  */
2844abb0f93cSkardel void
2845abb0f93cSkardel io_multicast_del(
2846abb0f93cSkardel 	sockaddr_u *	addr
2847abb0f93cSkardel 	)
2848abb0f93cSkardel {
2849abb0f93cSkardel #ifdef MCAST
285045530cf1Skardel 	endpt *iface;
2851abb0f93cSkardel 
2852abb0f93cSkardel 	/*
2853abb0f93cSkardel 	 * Check to see if this is a multicast address
2854abb0f93cSkardel 	 */
2855abb0f93cSkardel 	if (!addr_ismulticast(addr)) {
2856abb0f93cSkardel 		msyslog(LOG_ERR, "invalid multicast address %s",
2857abb0f93cSkardel 			stoa(addr));
2858abb0f93cSkardel 		return;
2859abb0f93cSkardel 	}
2860abb0f93cSkardel 
2861abb0f93cSkardel 	/*
2862abb0f93cSkardel 	 * Disable reception of multicast packets
2863abb0f93cSkardel 	 */
2864abb0f93cSkardel 	while ((iface = find_flagged_addr_in_list(addr, INT_MCASTOPEN))
2865abb0f93cSkardel 	       != NULL)
2866abb0f93cSkardel 		socket_multicast_disable(iface, addr);
2867abb0f93cSkardel 
2868abb0f93cSkardel 	delete_addr_from_list(addr);
2869abb0f93cSkardel 
2870abb0f93cSkardel #else /* not MCAST */
2871abb0f93cSkardel 	msyslog(LOG_ERR,
2872abb0f93cSkardel 		"Can not delete multicast address %s: no multicast support",
2873abb0f93cSkardel 		stoa(addr));
2874abb0f93cSkardel #endif /* not MCAST */
2875abb0f93cSkardel }
2876abb0f93cSkardel 
2877abb0f93cSkardel 
2878abb0f93cSkardel /*
2879abb0f93cSkardel  * open_socket - open a socket, returning the file descriptor
2880abb0f93cSkardel  */
2881abb0f93cSkardel 
2882abb0f93cSkardel static SOCKET
2883abb0f93cSkardel open_socket(
2884abb0f93cSkardel 	sockaddr_u *	addr,
2885abb0f93cSkardel 	int		bcast,
2886abb0f93cSkardel 	int		turn_off_reuse,
288745530cf1Skardel 	endpt *		interf
2888abb0f93cSkardel 	)
2889abb0f93cSkardel {
2890abb0f93cSkardel 	SOCKET	fd;
2891abb0f93cSkardel 	int	errval;
2892abb0f93cSkardel 	/*
2893abb0f93cSkardel 	 * int is OK for REUSEADR per
2894abb0f93cSkardel 	 * http://www.kohala.com/start/mcast.api.txt
2895abb0f93cSkardel 	 */
2896abb0f93cSkardel 	int	on = 1;
2897abb0f93cSkardel 	int	off = 0;
2898abb0f93cSkardel 
2899abb0f93cSkardel 	if (IS_IPV6(addr) && !ipv6_works)
2900abb0f93cSkardel 		return INVALID_SOCKET;
2901abb0f93cSkardel 
2902abb0f93cSkardel 	/* create a datagram (UDP) socket */
2903abb0f93cSkardel 	fd = socket(AF(addr), SOCK_DGRAM, 0);
2904abb0f93cSkardel 	if (INVALID_SOCKET == fd) {
290545530cf1Skardel 		errval = socket_errno();
2906abb0f93cSkardel 		msyslog(LOG_ERR,
2907abb0f93cSkardel 			"socket(AF_INET%s, SOCK_DGRAM, 0) failed on address %s: %m",
2908abb0f93cSkardel 			IS_IPV6(addr) ? "6" : "", stoa(addr));
2909abb0f93cSkardel 
2910abb0f93cSkardel 		if (errval == EPROTONOSUPPORT ||
2911abb0f93cSkardel 		    errval == EAFNOSUPPORT ||
2912abb0f93cSkardel 		    errval == EPFNOSUPPORT)
2913abb0f93cSkardel 			return (INVALID_SOCKET);
2914abb0f93cSkardel 
2915abb0f93cSkardel 		errno = errval;
2916abb0f93cSkardel 		msyslog(LOG_ERR,
2917abb0f93cSkardel 			"unexpected socket() error %m code %d (not EPROTONOSUPPORT nor EAFNOSUPPORT nor EPFNOSUPPORT) - exiting",
2918abb0f93cSkardel 			errno);
2919abb0f93cSkardel 		exit(1);
2920abb0f93cSkardel 	}
2921abb0f93cSkardel 
2922abb0f93cSkardel #ifdef SYS_WINNT
2923abb0f93cSkardel 	connection_reset_fix(fd, addr);
2924abb0f93cSkardel #endif
2925abb0f93cSkardel 	/*
2926abb0f93cSkardel 	 * Fixup the file descriptor for some systems
2927abb0f93cSkardel 	 * See bug #530 for details of the issue.
2928abb0f93cSkardel 	 */
2929abb0f93cSkardel 	fd = move_fd(fd);
2930abb0f93cSkardel 
2931abb0f93cSkardel 	/*
2932abb0f93cSkardel 	 * set SO_REUSEADDR since we will be binding the same port
2933abb0f93cSkardel 	 * number on each interface according to turn_off_reuse.
2934abb0f93cSkardel 	 * This is undesirable on Windows versions starting with
2935abb0f93cSkardel 	 * Windows XP (numeric version 5.1).
2936abb0f93cSkardel 	 */
2937abb0f93cSkardel #ifdef SYS_WINNT
2938abb0f93cSkardel 	if (isc_win32os_versioncheck(5, 1, 0, 0) < 0)  /* before 5.1 */
2939abb0f93cSkardel #endif
2940abb0f93cSkardel 		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
2941abb0f93cSkardel 			       (char *)((turn_off_reuse)
2942abb0f93cSkardel 					    ? &off
2943abb0f93cSkardel 					    : &on),
2944abb0f93cSkardel 			       sizeof(on))) {
2945abb0f93cSkardel 
2946abb0f93cSkardel 			msyslog(LOG_ERR,
2947abb0f93cSkardel 				"setsockopt SO_REUSEADDR %s fails for address %s: %m",
2948abb0f93cSkardel 				(turn_off_reuse)
2949abb0f93cSkardel 				    ? "off"
2950abb0f93cSkardel 				    : "on",
2951abb0f93cSkardel 				stoa(addr));
2952abb0f93cSkardel 			closesocket(fd);
2953abb0f93cSkardel 			return INVALID_SOCKET;
2954abb0f93cSkardel 		}
2955abb0f93cSkardel #ifdef SO_EXCLUSIVEADDRUSE
2956abb0f93cSkardel 	/*
2957abb0f93cSkardel 	 * setting SO_EXCLUSIVEADDRUSE on the wildcard we open
2958abb0f93cSkardel 	 * first will cause more specific binds to fail.
2959abb0f93cSkardel 	 */
2960abb0f93cSkardel 	if (!(interf->flags & INT_WILDCARD))
2961abb0f93cSkardel 		set_excladdruse(fd);
2962abb0f93cSkardel #endif
2963abb0f93cSkardel 
2964abb0f93cSkardel 	/*
2965abb0f93cSkardel 	 * IPv4 specific options go here
2966abb0f93cSkardel 	 */
2967abb0f93cSkardel 	if (IS_IPV4(addr)) {
2968b3d6264cSchristos #if defined(IPPROTO_IP) && defined(IP_TOS)
2969abb0f93cSkardel 		if (setsockopt(fd, IPPROTO_IP, IP_TOS, (char*)&qos,
2970abb0f93cSkardel 			       sizeof(qos)))
2971abb0f93cSkardel 			msyslog(LOG_ERR,
2972abb0f93cSkardel 				"setsockopt IP_TOS (%02x) fails on address %s: %m",
2973abb0f93cSkardel 				qos, stoa(addr));
2974b3d6264cSchristos #endif /* IPPROTO_IP && IP_TOS */
2975abb0f93cSkardel 		if (bcast)
2976abb0f93cSkardel 			socket_broadcast_enable(interf, fd, addr);
2977abb0f93cSkardel 	}
2978abb0f93cSkardel 
2979abb0f93cSkardel 	/*
2980abb0f93cSkardel 	 * IPv6 specific options go here
2981abb0f93cSkardel 	 */
2982abb0f93cSkardel 	if (IS_IPV6(addr)) {
2983b3d6264cSchristos #if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
2984b3d6264cSchristos 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, (char*)&qos,
2985b3d6264cSchristos 			       sizeof(qos)))
2986b3d6264cSchristos 			msyslog(LOG_ERR,
2987b3d6264cSchristos 				"setsockopt IPV6_TCLASS (%02x) fails on address %s: %m",
2988b3d6264cSchristos 				qos, stoa(addr));
2989b3d6264cSchristos #endif /* IPPROTO_IPV6 && IPV6_TCLASS */
299045530cf1Skardel #ifdef IPV6_V6ONLY
2991abb0f93cSkardel 		if (isc_net_probe_ipv6only() == ISC_R_SUCCESS
2992abb0f93cSkardel 		    && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
2993abb0f93cSkardel 		    (char*)&on, sizeof(on)))
2994abb0f93cSkardel 			msyslog(LOG_ERR,
2995abb0f93cSkardel 				"setsockopt IPV6_V6ONLY on fails on address %s: %m",
2996abb0f93cSkardel 				stoa(addr));
299745530cf1Skardel #endif
299845530cf1Skardel #ifdef IPV6_BINDV6ONLY
2999abb0f93cSkardel 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDV6ONLY,
3000abb0f93cSkardel 		    (char*)&on, sizeof(on)))
3001abb0f93cSkardel 			msyslog(LOG_ERR,
3002abb0f93cSkardel 				"setsockopt IPV6_BINDV6ONLY on fails on address %s: %m",
3003abb0f93cSkardel 				stoa(addr));
300445530cf1Skardel #endif
3005abb0f93cSkardel 	}
3006abb0f93cSkardel 
3007abb0f93cSkardel #ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND
3008abb0f93cSkardel 	/*
3009abb0f93cSkardel 	 * some OSes don't allow binding to more specific
3010abb0f93cSkardel 	 * addresses if a wildcard address already bound
3011abb0f93cSkardel 	 * to the port and SO_REUSEADDR is not set
3012abb0f93cSkardel 	 */
3013abb0f93cSkardel 	if (!is_wildcard_addr(addr))
3014abb0f93cSkardel 		set_wildcard_reuse(AF(addr), 1);
3015abb0f93cSkardel #endif
3016abb0f93cSkardel 
3017abb0f93cSkardel 	/*
3018abb0f93cSkardel 	 * bind the local address.
3019abb0f93cSkardel 	 */
3020abb0f93cSkardel 	errval = bind(fd, &addr->sa, SOCKLEN(addr));
3021abb0f93cSkardel 
3022abb0f93cSkardel #ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND
3023abb0f93cSkardel 	if (!is_wildcard_addr(addr))
3024abb0f93cSkardel 		set_wildcard_reuse(AF(addr), 0);
3025abb0f93cSkardel #endif
3026abb0f93cSkardel 
3027abb0f93cSkardel 	if (errval < 0) {
3028abb0f93cSkardel 		/*
3029abb0f93cSkardel 		 * Don't log this under all conditions
3030abb0f93cSkardel 		 */
3031abb0f93cSkardel 		if (turn_off_reuse == 0
3032abb0f93cSkardel #ifdef DEBUG
3033abb0f93cSkardel 		    || debug > 1
3034abb0f93cSkardel #endif
3035abb0f93cSkardel 		    ) {
3036abb0f93cSkardel 			msyslog(LOG_ERR,
303724d029faSmlelstv 				"bind(%d) AF_INET%s %s#%d%s flags 0x%x failed: %m",
3038abb0f93cSkardel 				fd, IS_IPV6(addr) ? "6" : "",
303924d029faSmlelstv 				stoa(addr), SRCPORT(addr),
3040abb0f93cSkardel 				IS_MCAST(addr) ? " (multicast)" : "",
3041abb0f93cSkardel 				interf->flags);
3042abb0f93cSkardel 		}
3043abb0f93cSkardel 
3044abb0f93cSkardel 		closesocket(fd);
3045abb0f93cSkardel 
3046abb0f93cSkardel 		return INVALID_SOCKET;
3047abb0f93cSkardel 	}
3048abb0f93cSkardel 
3049abb0f93cSkardel #ifdef HAVE_TIMESTAMP
3050abb0f93cSkardel 	{
3051abb0f93cSkardel 		if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP,
3052abb0f93cSkardel 			       (char*)&on, sizeof(on)))
3053abb0f93cSkardel 			msyslog(LOG_DEBUG,
3054abb0f93cSkardel 				"setsockopt SO_TIMESTAMP on fails on address %s: %m",
3055abb0f93cSkardel 				stoa(addr));
3056abb0f93cSkardel 		else
3057abb0f93cSkardel 			DPRINTF(4, ("setsockopt SO_TIMESTAMP enabled on fd %d address %s\n",
3058abb0f93cSkardel 				    fd, stoa(addr)));
3059abb0f93cSkardel 	}
3060abb0f93cSkardel #endif
3061b3d6264cSchristos #ifdef HAVE_TIMESTAMPNS
3062b3d6264cSchristos 	{
3063b3d6264cSchristos 		if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS,
3064b3d6264cSchristos 			       (char*)&on, sizeof(on)))
3065b3d6264cSchristos 			msyslog(LOG_DEBUG,
3066b3d6264cSchristos 				"setsockopt SO_TIMESTAMPNS on fails on address %s: %m",
3067b3d6264cSchristos 				stoa(addr));
3068b3d6264cSchristos 		else
3069b3d6264cSchristos 			DPRINTF(4, ("setsockopt SO_TIMESTAMPNS enabled on fd %d address %s\n",
3070b3d6264cSchristos 				    fd, stoa(addr)));
3071b3d6264cSchristos 	}
3072b3d6264cSchristos #endif
3073b3d6264cSchristos #ifdef HAVE_BINTIME
3074b3d6264cSchristos 	{
3075b3d6264cSchristos 		if (setsockopt(fd, SOL_SOCKET, SO_BINTIME,
3076b3d6264cSchristos 			       (char*)&on, sizeof(on)))
3077b3d6264cSchristos 			msyslog(LOG_DEBUG,
3078b3d6264cSchristos 				"setsockopt SO_BINTIME on fails on address %s: %m",
3079b3d6264cSchristos 				stoa(addr));
3080b3d6264cSchristos 		else
3081b3d6264cSchristos 			DPRINTF(4, ("setsockopt SO_BINTIME enabled on fd %d address %s\n",
3082b3d6264cSchristos 				    fd, stoa(addr)));
3083b3d6264cSchristos 	}
3084b3d6264cSchristos #endif
3085b3d6264cSchristos 
3086abb0f93cSkardel 	DPRINTF(4, ("bind(%d) AF_INET%s, addr %s%%%d#%d, flags 0x%x\n",
3087abb0f93cSkardel 		   fd, IS_IPV6(addr) ? "6" : "", stoa(addr),
3088abb0f93cSkardel 		   SCOPE(addr), SRCPORT(addr), interf->flags));
3089abb0f93cSkardel 
3090b3d6264cSchristos 	make_socket_nonblocking(fd);
3091abb0f93cSkardel 
3092abb0f93cSkardel #ifdef HAVE_SIGNALED_IO
3093abb0f93cSkardel 	init_socket_sig(fd);
3094abb0f93cSkardel #endif /* not HAVE_SIGNALED_IO */
3095abb0f93cSkardel 
3096abb0f93cSkardel 	add_fd_to_list(fd, FD_TYPE_SOCKET);
3097abb0f93cSkardel 
3098abb0f93cSkardel #if !defined(SYS_WINNT) && !defined(VMS)
3099abb0f93cSkardel 	DPRINTF(4, ("flags for fd %d: 0x%x\n", fd,
3100abb0f93cSkardel 		    fcntl(fd, F_GETFL, 0)));
3101abb0f93cSkardel #endif /* SYS_WINNT || VMS */
3102abb0f93cSkardel 
3103abb0f93cSkardel #if defined(HAVE_IO_COMPLETION_PORT)
3104abb0f93cSkardel /*
3105abb0f93cSkardel  * Add the socket to the completion port
3106abb0f93cSkardel  */
3107335f7552Schristos 	if (!io_completion_port_add_socket(fd, interf, bcast)) {
3108abb0f93cSkardel 		msyslog(LOG_ERR, "unable to set up io completion port - EXITING");
3109abb0f93cSkardel 		exit(1);
3110abb0f93cSkardel 	}
3111abb0f93cSkardel #endif
3112abb0f93cSkardel 	return fd;
3113abb0f93cSkardel }
3114abb0f93cSkardel 
311545530cf1Skardel 
311645530cf1Skardel 
3117abb0f93cSkardel /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
3118abb0f93cSkardel /*
3119abb0f93cSkardel  * sendpkt - send a packet to the specified destination. Maintain a
3120abb0f93cSkardel  * send error cache so that only the first consecutive error for a
3121abb0f93cSkardel  * destination is logged.
3122abb0f93cSkardel  */
3123abb0f93cSkardel void
3124abb0f93cSkardel sendpkt(
3125abb0f93cSkardel 	sockaddr_u *		dest,
312645530cf1Skardel 	struct interface *	ep,
3127abb0f93cSkardel 	int			ttl,
3128abb0f93cSkardel 	struct pkt *		pkt,
3129abb0f93cSkardel 	int			len
3130abb0f93cSkardel 	)
3131abb0f93cSkardel {
313245530cf1Skardel 	endpt *	src;
313345530cf1Skardel 	int	ismcast;
3134abb0f93cSkardel 	int	cc;
313545530cf1Skardel 	int	rc;
313645530cf1Skardel 	u_char	cttl;
3137abb0f93cSkardel 
313845530cf1Skardel 	ismcast = IS_MCAST(dest);
313945530cf1Skardel 	if (!ismcast)
314045530cf1Skardel 		src = ep;
314145530cf1Skardel 	else
314245530cf1Skardel 		src = (IS_IPV4(dest))
314345530cf1Skardel 			  ? mc4_list
314445530cf1Skardel 			  : mc6_list;
314545530cf1Skardel 
314645530cf1Skardel 	if (NULL == src) {
3147abb0f93cSkardel 		/*
3148abb0f93cSkardel 		 * unbound peer - drop request and wait for better
3149abb0f93cSkardel 		 * network conditions
3150abb0f93cSkardel 		 */
3151abb0f93cSkardel 		DPRINTF(2, ("%ssendpkt(dst=%s, ttl=%d, len=%d): no interface - IGNORED\n",
315245530cf1Skardel 			    ismcast ? "\tMCAST\t***** " : "",
3153abb0f93cSkardel 			    stoa(dest), ttl, len));
3154abb0f93cSkardel 		return;
3155abb0f93cSkardel 	}
3156abb0f93cSkardel 
315745530cf1Skardel 	do {
3158abb0f93cSkardel 		DPRINTF(2, ("%ssendpkt(%d, dst=%s, src=%s, ttl=%d, len=%d)\n",
315945530cf1Skardel 			    ismcast ? "\tMCAST\t***** " : "", src->fd,
316045530cf1Skardel 			    stoa(dest), stoa(&src->sin), ttl, len));
3161abb0f93cSkardel #ifdef MCAST
3162abb0f93cSkardel 		/*
3163abb0f93cSkardel 		 * for the moment we use the bcast option to set multicast ttl
3164abb0f93cSkardel 		 */
316545530cf1Skardel 		if (ismcast && ttl > 0 && ttl != src->last_ttl) {
3166abb0f93cSkardel 			/*
3167abb0f93cSkardel 			 * set the multicast ttl for outgoing packets
3168abb0f93cSkardel 			 */
316945530cf1Skardel 			switch (AF(&src->sin)) {
3170abb0f93cSkardel 
3171abb0f93cSkardel 			case AF_INET :
3172abb0f93cSkardel 				cttl = (u_char)ttl;
317345530cf1Skardel 				rc = setsockopt(src->fd, IPPROTO_IP,
3174abb0f93cSkardel 						IP_MULTICAST_TTL,
317545530cf1Skardel 						(void *)&cttl,
317645530cf1Skardel 						sizeof(cttl));
3177abb0f93cSkardel 				break;
3178abb0f93cSkardel 
3179abb0f93cSkardel # ifdef INCLUDE_IPV6_SUPPORT
3180abb0f93cSkardel 			case AF_INET6 :
318145530cf1Skardel 				rc = setsockopt(src->fd, IPPROTO_IPV6,
3182abb0f93cSkardel 						 IPV6_MULTICAST_HOPS,
318345530cf1Skardel 						 (void *)&ttl,
318445530cf1Skardel 						 sizeof(ttl));
3185abb0f93cSkardel 				break;
3186abb0f93cSkardel # endif	/* INCLUDE_IPV6_SUPPORT */
3187abb0f93cSkardel 
318845530cf1Skardel 			default:
318945530cf1Skardel 				rc = 0;
3190abb0f93cSkardel 			}
3191abb0f93cSkardel 
319245530cf1Skardel 			if (!rc)
319345530cf1Skardel 				src->last_ttl = ttl;
3194abb0f93cSkardel 			else
3195abb0f93cSkardel 				msyslog(LOG_ERR,
3196abb0f93cSkardel 					"setsockopt IP_MULTICAST_TTL/IPV6_MULTICAST_HOPS fails on address %s: %m",
319745530cf1Skardel 					stoa(&src->sin));
3198abb0f93cSkardel 		}
3199abb0f93cSkardel #endif	/* MCAST */
3200abb0f93cSkardel 
3201abb0f93cSkardel #ifdef SIM
320245530cf1Skardel 		cc = simulate_server(dest, src, pkt);
3203335f7552Schristos #elif defined(HAVE_IO_COMPLETION_PORT)
3204335f7552Schristos 		cc = io_completion_port_sendto(src, src->fd, pkt,
3205335f7552Schristos 			(size_t)len, (sockaddr_u *)&dest->sa);
320645530cf1Skardel #else
320745530cf1Skardel 		cc = sendto(src->fd, (char *)pkt, (u_int)len, 0,
320845530cf1Skardel 			    &dest->sa, SOCKLEN(dest));
3209abb0f93cSkardel #endif
321045530cf1Skardel 		if (cc == -1) {
321145530cf1Skardel 			src->notsent++;
3212abb0f93cSkardel 			packets_notsent++;
3213abb0f93cSkardel 		} else	{
321445530cf1Skardel 			src->sent++;
3215abb0f93cSkardel 			packets_sent++;
3216abb0f93cSkardel 		}
321745530cf1Skardel 		if (ismcast)
321845530cf1Skardel 			src = src->mclink;
321945530cf1Skardel 	} while (ismcast && src != NULL);
3220abb0f93cSkardel }
3221abb0f93cSkardel 
3222abb0f93cSkardel 
3223abb0f93cSkardel #if !defined(HAVE_IO_COMPLETION_PORT)
3224335f7552Schristos #if !defined(HAVE_SIGNALED_IO)
3225abb0f93cSkardel /*
3226abb0f93cSkardel  * fdbits - generate ascii representation of fd_set (FAU debug support)
3227abb0f93cSkardel  * HFDF format - highest fd first.
3228abb0f93cSkardel  */
3229abb0f93cSkardel static char *
3230abb0f93cSkardel fdbits(
3231abb0f93cSkardel 	int		count,
3232335f7552Schristos 	const fd_set*	set
3233abb0f93cSkardel 	)
3234abb0f93cSkardel {
3235abb0f93cSkardel 	static char buffer[256];
3236abb0f93cSkardel 	char * buf = buffer;
3237abb0f93cSkardel 
3238abb0f93cSkardel 	count = min(count,  255);
3239abb0f93cSkardel 
3240abb0f93cSkardel 	while (count >= 0) {
3241abb0f93cSkardel 		*buf++ = FD_ISSET(count, set) ? '#' : '-';
3242abb0f93cSkardel 		count--;
3243abb0f93cSkardel 	}
3244abb0f93cSkardel 	*buf = '\0';
3245abb0f93cSkardel 
3246abb0f93cSkardel 	return buffer;
3247abb0f93cSkardel }
3248335f7552Schristos #endif
3249b3d6264cSchristos 
3250b3d6264cSchristos #ifdef REFCLOCK
3251abb0f93cSkardel /*
3252abb0f93cSkardel  * Routine to read the refclock packets for a specific interface
3253abb0f93cSkardel  * Return the number of bytes read. That way we know if we should
3254abb0f93cSkardel  * read it again or go on to the next one if no bytes returned
3255abb0f93cSkardel  */
3256abb0f93cSkardel static inline int
3257b3d6264cSchristos read_refclock_packet(
3258b3d6264cSchristos 	SOCKET			fd,
3259b3d6264cSchristos 	struct refclockio *	rp,
3260b3d6264cSchristos 	l_fp			ts
3261b3d6264cSchristos 	)
3262abb0f93cSkardel {
326309f14f80Schristos 	u_int			read_count;
3264abb0f93cSkardel 	int			buflen;
3265b3d6264cSchristos 	int			saved_errno;
3266b3d6264cSchristos 	int			consumed;
3267b3d6264cSchristos 	struct recvbuf *	rb;
3268abb0f93cSkardel 
3269abb0f93cSkardel 	rb = get_free_recv_buffer();
3270abb0f93cSkardel 
3271abb0f93cSkardel 	if (NULL == rb) {
3272abb0f93cSkardel 		/*
3273abb0f93cSkardel 		 * No buffer space available - just drop the packet
3274abb0f93cSkardel 		 */
3275abb0f93cSkardel 		char buf[RX_BUFF_SIZE];
3276abb0f93cSkardel 
3277abb0f93cSkardel 		buflen = read(fd, buf, sizeof buf);
3278abb0f93cSkardel 		packets_dropped++;
3279abb0f93cSkardel 		return (buflen);
3280abb0f93cSkardel 	}
3281abb0f93cSkardel 
328209f14f80Schristos 	/* TALOS-CAN-0064: avoid signed/unsigned clashes that can lead
328309f14f80Schristos 	 * to buffer overrun and memory corruption
328409f14f80Schristos 	 */
328509f14f80Schristos 	if (rp->datalen <= 0 || (size_t)rp->datalen > sizeof(rb->recv_space))
328609f14f80Schristos 		read_count = sizeof(rb->recv_space);
328709f14f80Schristos 	else
328809f14f80Schristos 		read_count = (u_int)rp->datalen;
3289b3d6264cSchristos 	do {
329009f14f80Schristos 		buflen = read(fd, (char *)&rb->recv_space, read_count);
3291b3d6264cSchristos 	} while (buflen < 0 && EINTR == errno);
3292abb0f93cSkardel 
3293b3d6264cSchristos 	if (buflen <= 0) {
3294b3d6264cSchristos 		saved_errno = errno;
3295abb0f93cSkardel 		freerecvbuf(rb);
3296b3d6264cSchristos 		errno = saved_errno;
3297b3d6264cSchristos 		return buflen;
3298abb0f93cSkardel 	}
3299abb0f93cSkardel 
3300abb0f93cSkardel 	/*
3301abb0f93cSkardel 	 * Got one. Mark how and when it got here,
3302abb0f93cSkardel 	 * put it on the full list and do bookkeeping.
3303abb0f93cSkardel 	 */
3304abb0f93cSkardel 	rb->recv_length = buflen;
3305b3d6264cSchristos 	rb->recv_peer = rp->srcclock;
3306abb0f93cSkardel 	rb->dstadr = 0;
3307abb0f93cSkardel 	rb->fd = fd;
3308abb0f93cSkardel 	rb->recv_time = ts;
3309abb0f93cSkardel 	rb->receiver = rp->clock_recv;
3310abb0f93cSkardel 
3311b3d6264cSchristos 	consumed = indicate_refclock_packet(rp, rb);
3312b3d6264cSchristos 	if (!consumed) {
3313abb0f93cSkardel 		rp->recvcount++;
3314abb0f93cSkardel 		packets_received++;
3315abb0f93cSkardel 	}
3316abb0f93cSkardel 
3317b3d6264cSchristos 	return buflen;
3318b3d6264cSchristos }
3319b3d6264cSchristos #endif	/* REFCLOCK */
3320abb0f93cSkardel 
3321b3d6264cSchristos 
3322b3d6264cSchristos #ifdef HAVE_PACKET_TIMESTAMP
3323abb0f93cSkardel /*
3324abb0f93cSkardel  * extract timestamps from control message buffer
3325abb0f93cSkardel  */
3326abb0f93cSkardel static l_fp
3327abb0f93cSkardel fetch_timestamp(
3328abb0f93cSkardel 	struct recvbuf *	rb,
3329abb0f93cSkardel 	struct msghdr *		msghdr,
3330abb0f93cSkardel 	l_fp			ts
3331abb0f93cSkardel 	)
3332abb0f93cSkardel {
3333abb0f93cSkardel 	struct cmsghdr *	cmsghdr;
3334b3d6264cSchristos 	unsigned long		ticks;
3335b3d6264cSchristos 	double			fuzz;
3336b3d6264cSchristos 	l_fp			lfpfuzz;
3337b3d6264cSchristos 	l_fp			nts;
3338b3d6264cSchristos #ifdef DEBUG_TIMING
3339b3d6264cSchristos 	l_fp			dts;
3340b3d6264cSchristos #endif
3341abb0f93cSkardel 
3342abb0f93cSkardel 	cmsghdr = CMSG_FIRSTHDR(msghdr);
3343abb0f93cSkardel 	while (cmsghdr != NULL) {
3344abb0f93cSkardel 		switch (cmsghdr->cmsg_type)
3345abb0f93cSkardel 		{
3346b3d6264cSchristos #ifdef HAVE_BINTIME
3347b3d6264cSchristos 		case SCM_BINTIME:
3348b3d6264cSchristos #endif  /* HAVE_BINTIME */
3349b3d6264cSchristos #ifdef HAVE_TIMESTAMPNS
3350b3d6264cSchristos 		case SCM_TIMESTAMPNS:
3351b3d6264cSchristos #endif	/* HAVE_TIMESTAMPNS */
3352b3d6264cSchristos #ifdef HAVE_TIMESTAMP
3353abb0f93cSkardel 		case SCM_TIMESTAMP:
3354b3d6264cSchristos #endif	/* HAVE_TIMESTAMP */
3355b3d6264cSchristos #if defined(HAVE_BINTIME) || defined (HAVE_TIMESTAMPNS) || defined(HAVE_TIMESTAMP)
3356b3d6264cSchristos 			switch (cmsghdr->cmsg_type)
3357abb0f93cSkardel 			{
3358b3d6264cSchristos #ifdef HAVE_BINTIME
3359b3d6264cSchristos 			case SCM_BINTIME:
336066fcc386Schristos 				{
336166fcc386Schristos 					struct bintime	pbt;
336266fcc386Schristos 					memcpy(&pbt, CMSG_DATA(cmsghdr), sizeof(pbt));
3363b3d6264cSchristos 					/*
3364b3d6264cSchristos 					 * bintime documentation is at http://phk.freebsd.dk/pubs/timecounter.pdf
3365b3d6264cSchristos 					 */
336666fcc386Schristos 					nts.l_i = pbt.sec + JAN_1970;
336766fcc386Schristos 					nts.l_uf = (u_int32)(pbt.frac >> 32);
3368b3d6264cSchristos 					if (sys_tick > measured_tick &&
3369b3d6264cSchristos 					    sys_tick > 1e-9) {
3370b3d6264cSchristos 						ticks = (unsigned long)(nts.l_uf / (unsigned long)(sys_tick * FRAC));
3371b3d6264cSchristos 						nts.l_uf = (unsigned long)(ticks * (unsigned long)(sys_tick * FRAC));
3372b3d6264cSchristos 					}
3373b3d6264cSchristos 					DPRINTF(4, ("fetch_timestamp: system bintime network time stamp: %ld.%09lu\n",
337466fcc386Schristos 						    pbt.sec, (unsigned long)((nts.l_uf / FRAC) * 1e9)));
337566fcc386Schristos 				}
3376b3d6264cSchristos 				break;
3377b3d6264cSchristos #endif  /* HAVE_BINTIME */
3378b3d6264cSchristos #ifdef HAVE_TIMESTAMPNS
3379b3d6264cSchristos 			case SCM_TIMESTAMPNS:
338066fcc386Schristos 				{
338166fcc386Schristos 					struct timespec	pts;
338266fcc386Schristos 					memcpy(&pts, CMSG_DATA(cmsghdr), sizeof(pts));
3383b3d6264cSchristos 					if (sys_tick > measured_tick &&
3384b3d6264cSchristos 					    sys_tick > 1e-9) {
338566fcc386Schristos 						ticks = (unsigned long)((pts.tv_nsec * 1e-9) /
3386b3d6264cSchristos 									sys_tick);
338766fcc386Schristos 						pts.tv_nsec = (long)(ticks * 1e9 *
3388b3d6264cSchristos 								     sys_tick);
3389b3d6264cSchristos 					}
3390b3d6264cSchristos 					DPRINTF(4, ("fetch_timestamp: system nsec network time stamp: %ld.%09ld\n",
339166fcc386Schristos 						    pts.tv_sec, pts.tv_nsec));
339266fcc386Schristos 					nts = tspec_stamp_to_lfp(pts);
339366fcc386Schristos 				}
3394b3d6264cSchristos 				break;
3395b3d6264cSchristos #endif	/* HAVE_TIMESTAMPNS */
3396b3d6264cSchristos #ifdef HAVE_TIMESTAMP
3397b3d6264cSchristos 			case SCM_TIMESTAMP:
339866fcc386Schristos 				{
339966fcc386Schristos 					struct timeval	ptv;
340066fcc386Schristos 					memcpy(&ptv, CMSG_DATA(cmsghdr), sizeof(ptv));
3401b3d6264cSchristos 					if (sys_tick > measured_tick &&
3402b3d6264cSchristos 					    sys_tick > 1e-6) {
340366fcc386Schristos 						ticks = (unsigned long)((ptv.tv_usec * 1e-6) /
3404b3d6264cSchristos 									sys_tick);
340566fcc386Schristos 						ptv.tv_usec = (long)(ticks * 1e6 *
3406b3d6264cSchristos 								    sys_tick);
3407b3d6264cSchristos 					}
340874fd00ffSchristos 					DPRINTF(4, ("fetch_timestamp: system usec network time stamp: %jd.%06ld\n",
340966fcc386Schristos 						    (intmax_t)ptv.tv_sec, (long)ptv.tv_usec));
341066fcc386Schristos 					nts = tval_stamp_to_lfp(ptv);
341166fcc386Schristos 				}
3412b3d6264cSchristos 				break;
3413b3d6264cSchristos #endif  /* HAVE_TIMESTAMP */
3414b3d6264cSchristos 			}
3415b3d6264cSchristos 			fuzz = ntp_random() * 2. / FRAC * sys_fuzz;
3416b3d6264cSchristos 			DTOLFP(fuzz, &lfpfuzz);
3417b3d6264cSchristos 			L_ADD(&nts, &lfpfuzz);
3418abb0f93cSkardel #ifdef DEBUG_TIMING
3419abb0f93cSkardel 			dts = ts;
3420abb0f93cSkardel 			L_SUB(&dts, &nts);
3421b3d6264cSchristos 			collect_timing(rb, "input processing delay", 1,
3422b3d6264cSchristos 				       &dts);
3423b3d6264cSchristos 			DPRINTF(4, ("fetch_timestamp: timestamp delta: %s (incl. fuzz)\n",
3424abb0f93cSkardel 				    lfptoa(&dts, 9)));
3425b3d6264cSchristos #endif	/* DEBUG_TIMING */
3426abb0f93cSkardel 			ts = nts;  /* network time stamp */
3427abb0f93cSkardel 			break;
3428b3d6264cSchristos #endif	/* HAVE_BINTIME || HAVE_TIMESTAMPNS || HAVE_TIMESTAMP */
3429b3d6264cSchristos 
3430abb0f93cSkardel 		default:
3431abb0f93cSkardel 			DPRINTF(4, ("fetch_timestamp: skipping control message 0x%x\n",
3432abb0f93cSkardel 				    cmsghdr->cmsg_type));
3433abb0f93cSkardel 		}
3434abb0f93cSkardel 		cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr);
3435abb0f93cSkardel 	}
3436abb0f93cSkardel 	return ts;
3437abb0f93cSkardel }
3438b3d6264cSchristos #endif	/* HAVE_PACKET_TIMESTAMP */
3439abb0f93cSkardel 
3440abb0f93cSkardel 
3441abb0f93cSkardel /*
3442abb0f93cSkardel  * Routine to read the network NTP packets for a specific interface
3443abb0f93cSkardel  * Return the number of bytes read. That way we know if we should
3444abb0f93cSkardel  * read it again or go on to the next one if no bytes returned
3445abb0f93cSkardel  */
3446abb0f93cSkardel static inline int
3447abb0f93cSkardel read_network_packet(
3448abb0f93cSkardel 	SOCKET			fd,
3449abb0f93cSkardel 	struct interface *	itf,
3450abb0f93cSkardel 	l_fp			ts
3451abb0f93cSkardel 	)
3452abb0f93cSkardel {
3453abb0f93cSkardel 	GETSOCKNAME_SOCKLEN_TYPE fromlen;
3454abb0f93cSkardel 	int buflen;
3455abb0f93cSkardel 	register struct recvbuf *rb;
3456b3d6264cSchristos #ifdef HAVE_PACKET_TIMESTAMP
3457abb0f93cSkardel 	struct msghdr msghdr;
3458abb0f93cSkardel 	struct iovec iovec;
3459b3d6264cSchristos 	char control[CMSG_BUFSIZE];
3460abb0f93cSkardel #endif
3461abb0f93cSkardel 
3462abb0f93cSkardel 	/*
3463abb0f93cSkardel 	 * Get a buffer and read the frame.  If we
3464abb0f93cSkardel 	 * haven't got a buffer, or this is received
3465abb0f93cSkardel 	 * on a disallowed socket, just dump the
3466abb0f93cSkardel 	 * packet.
3467abb0f93cSkardel 	 */
3468abb0f93cSkardel 
3469abb0f93cSkardel 	rb = get_free_recv_buffer();
3470abb0f93cSkardel 	if (NULL == rb || itf->ignore_packets) {
3471abb0f93cSkardel 		char buf[RX_BUFF_SIZE];
3472abb0f93cSkardel 		sockaddr_u from;
3473abb0f93cSkardel 
3474abb0f93cSkardel 		if (rb != NULL)
3475abb0f93cSkardel 			freerecvbuf(rb);
3476abb0f93cSkardel 
3477abb0f93cSkardel 		fromlen = sizeof(from);
3478abb0f93cSkardel 		buflen = recvfrom(fd, buf, sizeof(buf), 0,
3479abb0f93cSkardel 				  &from.sa, &fromlen);
3480abb0f93cSkardel 		DPRINTF(4, ("%s on (%lu) fd=%d from %s\n",
3481abb0f93cSkardel 			(itf->ignore_packets)
3482abb0f93cSkardel 			    ? "ignore"
3483abb0f93cSkardel 			    : "drop",
3484abb0f93cSkardel 			free_recvbuffs(), fd, stoa(&from)));
3485abb0f93cSkardel 		if (itf->ignore_packets)
3486abb0f93cSkardel 			packets_ignored++;
3487abb0f93cSkardel 		else
3488abb0f93cSkardel 			packets_dropped++;
3489abb0f93cSkardel 		return (buflen);
3490abb0f93cSkardel 	}
3491abb0f93cSkardel 
3492abb0f93cSkardel 	fromlen = sizeof(rb->recv_srcadr);
3493abb0f93cSkardel 
3494b3d6264cSchristos #ifndef HAVE_PACKET_TIMESTAMP
3495abb0f93cSkardel 	rb->recv_length = recvfrom(fd, (char *)&rb->recv_space,
3496abb0f93cSkardel 				   sizeof(rb->recv_space), 0,
3497abb0f93cSkardel 				   &rb->recv_srcadr.sa, &fromlen);
3498abb0f93cSkardel #else
3499abb0f93cSkardel 	iovec.iov_base        = &rb->recv_space;
3500abb0f93cSkardel 	iovec.iov_len         = sizeof(rb->recv_space);
3501abb0f93cSkardel 	msghdr.msg_name       = &rb->recv_srcadr;
3502abb0f93cSkardel 	msghdr.msg_namelen    = fromlen;
3503abb0f93cSkardel 	msghdr.msg_iov        = &iovec;
3504abb0f93cSkardel 	msghdr.msg_iovlen     = 1;
3505abb0f93cSkardel 	msghdr.msg_control    = (void *)&control;
3506abb0f93cSkardel 	msghdr.msg_controllen = sizeof(control);
3507abb0f93cSkardel 	msghdr.msg_flags      = 0;
3508abb0f93cSkardel 	rb->recv_length       = recvmsg(fd, &msghdr, 0);
3509abb0f93cSkardel #endif
3510abb0f93cSkardel 
3511abb0f93cSkardel 	buflen = rb->recv_length;
3512abb0f93cSkardel 
3513abb0f93cSkardel 	if (buflen == 0 || (buflen == -1 &&
3514abb0f93cSkardel 	    (EWOULDBLOCK == errno
3515abb0f93cSkardel #ifdef EAGAIN
3516abb0f93cSkardel 	     || EAGAIN == errno
3517abb0f93cSkardel #endif
3518abb0f93cSkardel 	     ))) {
3519abb0f93cSkardel 		freerecvbuf(rb);
3520abb0f93cSkardel 		return (buflen);
3521abb0f93cSkardel 	} else if (buflen < 0) {
3522abb0f93cSkardel 		msyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m",
3523abb0f93cSkardel 			stoa(&rb->recv_srcadr), fd);
3524abb0f93cSkardel 		DPRINTF(5, ("read_network_packet: fd=%d dropped (bad recvfrom)\n",
3525abb0f93cSkardel 			    fd));
3526abb0f93cSkardel 		freerecvbuf(rb);
3527abb0f93cSkardel 		return (buflen);
3528abb0f93cSkardel 	}
3529abb0f93cSkardel 
3530abb0f93cSkardel 	DPRINTF(3, ("read_network_packet: fd=%d length %d from %s\n",
3531abb0f93cSkardel 		    fd, buflen, stoa(&rb->recv_srcadr)));
3532abb0f93cSkardel 
3533335f7552Schristos #ifdef ENABLE_BUG3020_FIX
3534335f7552Schristos 	if (ISREFCLOCKADR(&rb->recv_srcadr)) {
3535335f7552Schristos 		msyslog(LOG_ERR, "recvfrom(%s) fd=%d: refclock srcadr on a network interface!",
3536335f7552Schristos 			stoa(&rb->recv_srcadr), fd);
3537335f7552Schristos 		DPRINTF(1, ("read_network_packet: fd=%d dropped (refclock srcadr))\n",
3538335f7552Schristos 			    fd));
3539335f7552Schristos 		packets_dropped++;
3540335f7552Schristos 		freerecvbuf(rb);
3541335f7552Schristos 		return (buflen);
3542335f7552Schristos 	}
3543335f7552Schristos #endif
3544335f7552Schristos 
3545abb0f93cSkardel 	/*
3546ad131110Schristos 	** Bug 2672: Some OSes (MacOSX and Linux) don't block spoofed ::1
3547ad131110Schristos 	*/
3548ad131110Schristos 
3549ad131110Schristos 	if (AF_INET6 == itf->family) {
355050cc4415Schristos 		DPRINTF(2, ("Got an IPv6 packet, from <%s> (%d) to <%s> (%d)\n",
3551ad131110Schristos 			stoa(&rb->recv_srcadr),
355250cc4415Schristos 			IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&rb->recv_srcadr)),
3553ad131110Schristos 			stoa(&itf->sin),
355450cc4415Schristos 			!IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&itf->sin))
3555ad131110Schristos 			));
3556ad131110Schristos 
355750cc4415Schristos 		if (   IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&rb->recv_srcadr))
355850cc4415Schristos 		    && !IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&itf->sin))
3559ad131110Schristos 		   ) {
3560ad131110Schristos 			packets_dropped++;
356150cc4415Schristos 			DPRINTF(2, ("DROPPING that packet\n"));
3562ad131110Schristos 			freerecvbuf(rb);
3563ad131110Schristos 			return buflen;
3564ad131110Schristos 		}
356550cc4415Schristos 		DPRINTF(2, ("processing that packet\n"));
356650cc4415Schristos 	}
3567ad131110Schristos 
3568ad131110Schristos 	/*
3569abb0f93cSkardel 	 * Got one.  Mark how and when it got here,
3570abb0f93cSkardel 	 * put it on the full list and do bookkeeping.
3571abb0f93cSkardel 	 */
3572abb0f93cSkardel 	rb->dstadr = itf;
3573abb0f93cSkardel 	rb->fd = fd;
3574b3d6264cSchristos #ifdef HAVE_PACKET_TIMESTAMP
3575abb0f93cSkardel 	/* pick up a network time stamp if possible */
3576abb0f93cSkardel 	ts = fetch_timestamp(rb, &msghdr, ts);
3577abb0f93cSkardel #endif
3578abb0f93cSkardel 	rb->recv_time = ts;
3579abb0f93cSkardel 	rb->receiver = receive;
3580abb0f93cSkardel 
3581abb0f93cSkardel 	add_full_recv_buffer(rb);
3582abb0f93cSkardel 
3583abb0f93cSkardel 	itf->received++;
3584abb0f93cSkardel 	packets_received++;
3585abb0f93cSkardel 	return (buflen);
3586abb0f93cSkardel }
3587abb0f93cSkardel 
3588b3d6264cSchristos /*
3589b3d6264cSchristos  * attempt to handle io (select()/signaled IO)
3590b3d6264cSchristos  */
3591b3d6264cSchristos void
3592b3d6264cSchristos io_handler(void)
3593b3d6264cSchristos {
3594b3d6264cSchristos #  ifndef HAVE_SIGNALED_IO
3595b3d6264cSchristos 	fd_set rdfdes;
3596b3d6264cSchristos 	int nfound;
3597b3d6264cSchristos 
3598b3d6264cSchristos 	/*
3599b3d6264cSchristos 	 * Use select() on all on all input fd's for unlimited
3600b3d6264cSchristos 	 * time.  select() will terminate on SIGALARM or on the
3601b3d6264cSchristos 	 * reception of input.	Using select() means we can't do
3602b3d6264cSchristos 	 * robust signal handling and we get a potential race
3603b3d6264cSchristos 	 * between checking for alarms and doing the select().
3604b3d6264cSchristos 	 * Mostly harmless, I think.
3605b3d6264cSchristos 	 */
3606b3d6264cSchristos 	/*
3607b3d6264cSchristos 	 * On VMS, I suspect that select() can't be interrupted
3608b3d6264cSchristos 	 * by a "signal" either, so I take the easy way out and
3609b3d6264cSchristos 	 * have select() time out after one second.
3610b3d6264cSchristos 	 * System clock updates really aren't time-critical,
3611b3d6264cSchristos 	 * and - lacking a hardware reference clock - I have
3612b3d6264cSchristos 	 * yet to learn about anything else that is.
3613b3d6264cSchristos 	 */
3614335f7552Schristos 	++handler_calls;
3615b3d6264cSchristos 	rdfdes = activefds;
3616b3d6264cSchristos #   if !defined(VMS) && !defined(SYS_VXWORKS)
3617b3d6264cSchristos 	nfound = select(maxactivefd + 1, &rdfdes, NULL,
3618b3d6264cSchristos 			NULL, NULL);
3619b3d6264cSchristos #   else	/* VMS, VxWorks */
3620b3d6264cSchristos 	/* make select() wake up after one second */
3621b3d6264cSchristos 	{
3622b3d6264cSchristos 		struct timeval t1;
3623b3d6264cSchristos 		t1.tv_sec  = 1;
3624b3d6264cSchristos 		t1.tv_usec = 0;
3625b3d6264cSchristos 		nfound = select(maxactivefd + 1,
3626b3d6264cSchristos 				&rdfdes, NULL, NULL,
3627b3d6264cSchristos 				&t1);
3628b3d6264cSchristos 	}
3629b3d6264cSchristos #   endif	/* VMS, VxWorks */
3630335f7552Schristos 	if (nfound < 0 && sanitize_fdset(errno)) {
3631335f7552Schristos 		struct timeval t1;
3632335f7552Schristos 		t1.tv_sec  = 0;
3633335f7552Schristos 		t1.tv_usec = 0;
3634335f7552Schristos 		rdfdes = activefds;
3635335f7552Schristos 		nfound = select(maxactivefd + 1,
3636335f7552Schristos 				&rdfdes, NULL, NULL,
3637335f7552Schristos 				&t1);
3638335f7552Schristos 	}
3639335f7552Schristos 
3640b3d6264cSchristos 	if (nfound > 0) {
3641b3d6264cSchristos 		l_fp ts;
3642b3d6264cSchristos 
3643b3d6264cSchristos 		get_systime(&ts);
3644b3d6264cSchristos 
3645335f7552Schristos 		input_handler_scan(&ts, &rdfdes);
3646b3d6264cSchristos 	} else if (nfound == -1 && errno != EINTR) {
3647b3d6264cSchristos 		msyslog(LOG_ERR, "select() error: %m");
3648b3d6264cSchristos 	}
3649b3d6264cSchristos #   ifdef DEBUG
3650b3d6264cSchristos 	else if (debug > 4) {
3651b3d6264cSchristos 		msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
3652b3d6264cSchristos 	} else {
36534e3b3909Schristos 		DPRINTF(3, ("select() returned %d: %m\n", nfound));
3654b3d6264cSchristos 	}
3655b3d6264cSchristos #   endif /* DEBUG */
3656b3d6264cSchristos #  else /* HAVE_SIGNALED_IO */
3657b3d6264cSchristos 	wait_for_signal();
3658b3d6264cSchristos #  endif /* HAVE_SIGNALED_IO */
3659b3d6264cSchristos }
3660abb0f93cSkardel 
3661335f7552Schristos #ifdef HAVE_SIGNALED_IO
3662abb0f93cSkardel /*
3663abb0f93cSkardel  * input_handler - receive packets asynchronously
3664335f7552Schristos  *
3665335f7552Schristos  * ALWAYS IN SIGNAL HANDLER CONTEXT -- only async-safe functions allowed!
3666abb0f93cSkardel  */
3667335f7552Schristos static RETSIGTYPE
3668abb0f93cSkardel input_handler(
3669abb0f93cSkardel 	l_fp *	cts
3670abb0f93cSkardel 	)
3671abb0f93cSkardel {
3672abb0f93cSkardel 	int		n;
3673335f7552Schristos 	struct timeval	tvzero;
3674335f7552Schristos 	fd_set		fds;
3675335f7552Schristos 
3676335f7552Schristos 	++handler_calls;
3677335f7552Schristos 
3678335f7552Schristos 	/*
3679335f7552Schristos 	 * Do a poll to see who has data
3680335f7552Schristos 	 */
3681335f7552Schristos 
3682335f7552Schristos 	fds = activefds;
3683335f7552Schristos 	tvzero.tv_sec = tvzero.tv_usec = 0;
3684335f7552Schristos 
3685335f7552Schristos 	n = select(maxactivefd + 1, &fds, NULL, NULL, &tvzero);
3686335f7552Schristos 	if (n < 0 && sanitize_fdset(errno)) {
3687335f7552Schristos 		fds = activefds;
3688335f7552Schristos 		tvzero.tv_sec = tvzero.tv_usec = 0;
3689335f7552Schristos 		n = select(maxactivefd + 1, &fds, NULL, NULL, &tvzero);
3690335f7552Schristos 	}
3691335f7552Schristos 	if (n > 0)
3692335f7552Schristos 		input_handler_scan(cts, &fds);
3693335f7552Schristos }
3694335f7552Schristos #endif /* HAVE_SIGNALED_IO */
3695335f7552Schristos 
3696335f7552Schristos 
3697335f7552Schristos /*
3698335f7552Schristos  * Try to sanitize the global FD set
3699335f7552Schristos  *
3700335f7552Schristos  * SIGNAL HANDLER CONTEXT if HAVE_SIGNALED_IO, ordinary userspace otherwise
3701335f7552Schristos  */
3702335f7552Schristos static int/*BOOL*/
3703335f7552Schristos sanitize_fdset(
3704335f7552Schristos 	int	errc
3705335f7552Schristos 	)
3706335f7552Schristos {
3707335f7552Schristos 	int j, b, maxscan;
3708335f7552Schristos 
3709335f7552Schristos #  ifndef HAVE_SIGNALED_IO
3710335f7552Schristos 	/*
3711335f7552Schristos 	 * extended FAU debugging output
3712335f7552Schristos 	 */
3713335f7552Schristos 	if (errc != EINTR) {
3714335f7552Schristos 		msyslog(LOG_ERR,
3715335f7552Schristos 			"select(%d, %s, 0L, 0L, &0.0) error: %m",
3716335f7552Schristos 			maxactivefd + 1,
3717335f7552Schristos 			fdbits(maxactivefd, &activefds));
3718335f7552Schristos 	}
3719335f7552Schristos #   endif
3720335f7552Schristos 
3721335f7552Schristos 	if (errc != EBADF)
3722335f7552Schristos 		return FALSE;
3723335f7552Schristos 
3724335f7552Schristos 	/* if we have oviously bad FDs, try to sanitize the FD set. */
3725335f7552Schristos 	for (j = 0, maxscan = 0; j <= maxactivefd; j++) {
3726335f7552Schristos 		if (FD_ISSET(j, &activefds)) {
3727335f7552Schristos 			if (-1 != read(j, &b, 0)) {
3728335f7552Schristos 				maxscan = j;
3729335f7552Schristos 				continue;
3730335f7552Schristos 			}
3731335f7552Schristos #		    ifndef HAVE_SIGNALED_IO
3732335f7552Schristos 			msyslog(LOG_ERR,
3733335f7552Schristos 				"Removing bad file descriptor %d from select set",
3734335f7552Schristos 				j);
3735335f7552Schristos #		    endif
3736335f7552Schristos 			FD_CLR(j, &activefds);
3737335f7552Schristos 		}
3738335f7552Schristos 	}
3739335f7552Schristos 	if (maxactivefd != maxscan)
3740335f7552Schristos 		maxactivefd = maxscan;
3741335f7552Schristos 	return TRUE;
3742335f7552Schristos }
3743335f7552Schristos 
3744335f7552Schristos /*
3745335f7552Schristos  * scan the known FDs (clocks, servers, ...) for presence in a 'fd_set'.
3746335f7552Schristos  *
3747335f7552Schristos  * SIGNAL HANDLER CONTEXT if HAVE_SIGNALED_IO, ordinary userspace otherwise
3748335f7552Schristos  */
3749335f7552Schristos static void
3750335f7552Schristos input_handler_scan(
3751335f7552Schristos 	const l_fp *	cts,
3752335f7552Schristos 	const fd_set *	pfds
3753335f7552Schristos 	)
3754335f7552Schristos {
3755335f7552Schristos 	int		buflen;
3756b3d6264cSchristos 	u_int		idx;
3757abb0f93cSkardel 	int		doing;
3758abb0f93cSkardel 	SOCKET		fd;
3759b3d6264cSchristos 	blocking_child *c;
3760abb0f93cSkardel 	l_fp		ts;	/* Timestamp at BOselect() gob */
3761335f7552Schristos 
3762335f7552Schristos #if defined(DEBUG_TIMING)
3763abb0f93cSkardel 	l_fp		ts_e;	/* Timestamp at EOselect() gob */
3764abb0f93cSkardel #endif
376545530cf1Skardel 	endpt *		ep;
3766b3d6264cSchristos #ifdef REFCLOCK
3767b3d6264cSchristos 	struct refclockio *rp;
3768b3d6264cSchristos 	int		saved_errno;
3769b3d6264cSchristos 	const char *	clk;
3770b3d6264cSchristos #endif
3771b3d6264cSchristos #ifdef HAS_ROUTING_SOCKET
3772abb0f93cSkardel 	struct asyncio_reader *	asyncio_reader;
3773b3d6264cSchristos 	struct asyncio_reader *	next_asyncio_reader;
3774abb0f93cSkardel #endif
3775abb0f93cSkardel 
3776abb0f93cSkardel 	++handler_pkts;
3777335f7552Schristos 	ts = *cts;
3778abb0f93cSkardel 
3779abb0f93cSkardel #ifdef REFCLOCK
3780abb0f93cSkardel 	/*
3781abb0f93cSkardel 	 * Check out the reference clocks first, if any
3782abb0f93cSkardel 	 */
3783abb0f93cSkardel 
3784abb0f93cSkardel 	for (rp = refio; rp != NULL; rp = rp->next) {
3785abb0f93cSkardel 		fd = rp->fd;
3786abb0f93cSkardel 
3787335f7552Schristos 		if (!FD_ISSET(fd, pfds))
3788b3d6264cSchristos 			continue;
3789b3d6264cSchristos 		buflen = read_refclock_packet(fd, rp, ts);
3790b3d6264cSchristos 		/*
3791335f7552Schristos 		 * The first read must succeed after select() indicates
3792335f7552Schristos 		 * readability, or we've reached a permanent EOF.
3793335f7552Schristos 		 * http://bugs.ntp.org/1732 reported ntpd munching CPU
3794335f7552Schristos 		 * after a USB GPS was unplugged because select was
3795335f7552Schristos 		 * indicating EOF but ntpd didn't remove the descriptor
3796b3d6264cSchristos 		 * from the activefds set.
3797b3d6264cSchristos 		 */
3798b3d6264cSchristos 		if (buflen < 0 && EAGAIN != errno) {
3799b3d6264cSchristos 			saved_errno = errno;
3800b3d6264cSchristos 			clk = refnumtoa(&rp->srcclock->srcadr);
3801b3d6264cSchristos 			errno = saved_errno;
3802b3d6264cSchristos 			msyslog(LOG_ERR, "%s read: %m", clk);
3803b3d6264cSchristos 			maintain_activefds(fd, TRUE);
3804b3d6264cSchristos 		} else if (0 == buflen) {
3805b3d6264cSchristos 			clk = refnumtoa(&rp->srcclock->srcadr);
3806b3d6264cSchristos 			msyslog(LOG_ERR, "%s read EOF", clk);
3807b3d6264cSchristos 			maintain_activefds(fd, TRUE);
3808b3d6264cSchristos 		} else {
3809b3d6264cSchristos 			/* drain any remaining refclock input */
3810b3d6264cSchristos 			do {
3811b3d6264cSchristos 				buflen = read_refclock_packet(fd, rp, ts);
3812abb0f93cSkardel 			} while (buflen > 0);
3813abb0f93cSkardel 		}
3814abb0f93cSkardel 	}
3815abb0f93cSkardel #endif /* REFCLOCK */
3816abb0f93cSkardel 
3817abb0f93cSkardel 	/*
3818abb0f93cSkardel 	 * Loop through the interfaces looking for data to read.
3819abb0f93cSkardel 	 */
382045530cf1Skardel 	for (ep = ep_list; ep != NULL; ep = ep->elink) {
382145530cf1Skardel 		for (doing = 0; doing < 2; doing++) {
382245530cf1Skardel 			if (!doing) {
382345530cf1Skardel 				fd = ep->fd;
382445530cf1Skardel 			} else {
382545530cf1Skardel 				if (!(ep->flags & INT_BCASTOPEN))
3826abb0f93cSkardel 					break;
382745530cf1Skardel 				fd = ep->bfd;
3828abb0f93cSkardel 			}
3829abb0f93cSkardel 			if (fd < 0)
3830abb0f93cSkardel 				continue;
3831335f7552Schristos 			if (FD_ISSET(fd, pfds))
3832abb0f93cSkardel 				do {
3833abb0f93cSkardel 					buflen = read_network_packet(
383445530cf1Skardel 							fd, ep, ts);
3835abb0f93cSkardel 				} while (buflen > 0);
3836abb0f93cSkardel 			/* Check more interfaces */
3837abb0f93cSkardel 		}
3838abb0f93cSkardel 	}
3839abb0f93cSkardel 
3840abb0f93cSkardel #ifdef HAS_ROUTING_SOCKET
3841abb0f93cSkardel 	/*
3842abb0f93cSkardel 	 * scan list of asyncio readers - currently only used for routing sockets
3843abb0f93cSkardel 	 */
3844abb0f93cSkardel 	asyncio_reader = asyncio_reader_list;
3845abb0f93cSkardel 
3846abb0f93cSkardel 	while (asyncio_reader != NULL) {
3847b3d6264cSchristos 		/* callback may unlink and free asyncio_reader */
3848b3d6264cSchristos 		next_asyncio_reader = asyncio_reader->link;
3849335f7552Schristos 		if (FD_ISSET(asyncio_reader->fd, pfds))
3850b3d6264cSchristos 			(*asyncio_reader->receiver)(asyncio_reader);
3851b3d6264cSchristos 		asyncio_reader = next_asyncio_reader;
3852abb0f93cSkardel 	}
3853abb0f93cSkardel #endif /* HAS_ROUTING_SOCKET */
3854abb0f93cSkardel 
3855abb0f93cSkardel 	/*
3856b3d6264cSchristos 	 * Check for a response from a blocking child
3857abb0f93cSkardel 	 */
3858b3d6264cSchristos 	for (idx = 0; idx < blocking_children_alloc; idx++) {
3859b3d6264cSchristos 		c = blocking_children[idx];
3860b3d6264cSchristos 		if (NULL == c || -1 == c->resp_read_pipe)
3861b3d6264cSchristos 			continue;
3862335f7552Schristos 		if (FD_ISSET(c->resp_read_pipe, pfds)) {
3863335f7552Schristos 			++c->resp_ready_seen;
3864335f7552Schristos 			++blocking_child_ready_seen;
3865b3d6264cSchristos 		}
3866b3d6264cSchristos 	}
3867abb0f93cSkardel 
3868abb0f93cSkardel 	/* We've done our work */
3869335f7552Schristos #if defined(DEBUG_TIMING)
3870abb0f93cSkardel 	get_systime(&ts_e);
3871abb0f93cSkardel 	/*
3872abb0f93cSkardel 	 * (ts_e - ts) is the amount of time we spent
3873abb0f93cSkardel 	 * processing this gob of file descriptors.  Log
3874abb0f93cSkardel 	 * it.
3875abb0f93cSkardel 	 */
3876abb0f93cSkardel 	L_SUB(&ts_e, &ts);
3877abb0f93cSkardel 	collect_timing(NULL, "input handler", 1, &ts_e);
3878abb0f93cSkardel 	if (debug > 3)
3879abb0f93cSkardel 		msyslog(LOG_DEBUG,
3880abb0f93cSkardel 			"input_handler: Processed a gob of fd's in %s msec",
3881abb0f93cSkardel 			lfptoms(&ts_e, 6));
3882b3d6264cSchristos #endif /* DEBUG_TIMING */
3883abb0f93cSkardel }
3884b3d6264cSchristos #endif /* !HAVE_IO_COMPLETION_PORT */
3885b3d6264cSchristos 
3886b3d6264cSchristos /*
3887b3d6264cSchristos  * find an interface suitable for the src address
3888b3d6264cSchristos  */
3889b3d6264cSchristos endpt *
3890b3d6264cSchristos select_peerinterface(
3891b3d6264cSchristos 	struct peer *	peer,
3892b3d6264cSchristos 	sockaddr_u *	srcadr,
3893b3d6264cSchristos 	endpt *		dstadr
3894b3d6264cSchristos 	)
3895b3d6264cSchristos {
3896b3d6264cSchristos 	endpt *ep;
3897b3d6264cSchristos #ifndef SIM
3898b3d6264cSchristos 	endpt *wild;
3899b3d6264cSchristos 
3900b3d6264cSchristos 	wild = ANY_INTERFACE_CHOOSE(srcadr);
3901b3d6264cSchristos 
3902b3d6264cSchristos 	/*
3903b3d6264cSchristos 	 * Initialize the peer structure and dance the interface jig.
3904b3d6264cSchristos 	 * Reference clocks step the loopback waltz, the others
3905b3d6264cSchristos 	 * squaredance around the interface list looking for a buddy. If
3906b3d6264cSchristos 	 * the dance peters out, there is always the wildcard interface.
3907b3d6264cSchristos 	 * This might happen in some systems and would preclude proper
3908b3d6264cSchristos 	 * operation with public key cryptography.
3909b3d6264cSchristos 	 */
3910b3d6264cSchristos 	if (ISREFCLOCKADR(srcadr)) {
3911b3d6264cSchristos 		ep = loopback_interface;
3912b3d6264cSchristos 	} else if (peer->cast_flags &
3913b3d6264cSchristos 		   (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) {
3914b3d6264cSchristos 		ep = findbcastinter(srcadr);
3915b3d6264cSchristos 		if (ep != NULL)
3916b3d6264cSchristos 			DPRINTF(4, ("Found *-cast interface %s for address %s\n",
3917b3d6264cSchristos 				stoa(&ep->sin), stoa(srcadr)));
3918b3d6264cSchristos 		else
3919b3d6264cSchristos 			DPRINTF(4, ("No *-cast local address found for address %s\n",
3920b3d6264cSchristos 				stoa(srcadr)));
3921b3d6264cSchristos 	} else {
3922b3d6264cSchristos 		ep = dstadr;
3923b3d6264cSchristos 		if (NULL == ep)
3924b3d6264cSchristos 			ep = wild;
3925b3d6264cSchristos 	}
3926b3d6264cSchristos 	/*
3927b3d6264cSchristos 	 * If it is a multicast address, findbcastinter() may not find
3928b3d6264cSchristos 	 * it.  For unicast, we get to find the interface when dstadr is
3929b3d6264cSchristos 	 * given to us as the wildcard (ANY_INTERFACE_CHOOSE).  Either
3930b3d6264cSchristos 	 * way, try a little harder.
3931b3d6264cSchristos 	 */
3932b3d6264cSchristos 	if (wild == ep)
3933b3d6264cSchristos 		ep = findinterface(srcadr);
3934b3d6264cSchristos 	/*
3935b3d6264cSchristos 	 * we do not bind to the wildcard interfaces for output
3936b3d6264cSchristos 	 * as our (network) source address would be undefined and
3937b3d6264cSchristos 	 * crypto will not work without knowing the own transmit address
3938b3d6264cSchristos 	 */
3939b3d6264cSchristos 	if (ep != NULL && INT_WILDCARD & ep->flags)
3940b3d6264cSchristos 		if (!accept_wildcard_if_for_winnt)
3941b3d6264cSchristos 			ep = NULL;
3942b3d6264cSchristos #else	/* SIM follows */
3943b3d6264cSchristos 	ep = loopback_interface;
3944abb0f93cSkardel #endif
3945abb0f93cSkardel 
3946b3d6264cSchristos 	return ep;
3947b3d6264cSchristos }
3948b3d6264cSchristos 
3949b3d6264cSchristos 
3950abb0f93cSkardel /*
3951abb0f93cSkardel  * findinterface - find local interface corresponding to address
3952abb0f93cSkardel  */
395345530cf1Skardel endpt *
3954abb0f93cSkardel findinterface(
3955abb0f93cSkardel 	sockaddr_u *addr
3956abb0f93cSkardel 	)
3957abb0f93cSkardel {
395845530cf1Skardel 	endpt *iface;
3959abb0f93cSkardel 
3960abb0f93cSkardel 	iface = findlocalinterface(addr, INT_WILDCARD, 0);
3961abb0f93cSkardel 
3962abb0f93cSkardel 	if (NULL == iface) {
3963abb0f93cSkardel 		DPRINTF(4, ("Found no interface for address %s - returning wildcard\n",
3964abb0f93cSkardel 			    stoa(addr)));
3965abb0f93cSkardel 
3966abb0f93cSkardel 		iface = ANY_INTERFACE_CHOOSE(addr);
3967abb0f93cSkardel 	} else
3968abb0f93cSkardel 		DPRINTF(4, ("Found interface #%d %s for address %s\n",
3969abb0f93cSkardel 			    iface->ifnum, iface->name, stoa(addr)));
3970abb0f93cSkardel 
3971abb0f93cSkardel 	return iface;
3972abb0f93cSkardel }
3973abb0f93cSkardel 
3974abb0f93cSkardel /*
3975abb0f93cSkardel  * findlocalinterface - find local interface corresponding to addr,
3976abb0f93cSkardel  * which does not have any of flags set.  If bast is nonzero, addr is
3977abb0f93cSkardel  * a broadcast address.
3978abb0f93cSkardel  *
3979abb0f93cSkardel  * This code attempts to find the local sending address for an outgoing
3980abb0f93cSkardel  * address by connecting a new socket to destinationaddress:NTP_PORT
3981abb0f93cSkardel  * and reading the sockname of the resulting connect.
3982abb0f93cSkardel  * the complicated sequence simulates the routing table lookup
3983abb0f93cSkardel  * for to first hop without duplicating any of the routing logic into
3984abb0f93cSkardel  * ntpd. preferably we would have used an API call - but its not there -
3985abb0f93cSkardel  * so this is the best we can do here short of duplicating to entire routing
3986abb0f93cSkardel  * logic in ntpd which would be a silly and really unportable thing to do.
3987abb0f93cSkardel  *
3988abb0f93cSkardel  */
398945530cf1Skardel static endpt *
3990abb0f93cSkardel findlocalinterface(
3991abb0f93cSkardel 	sockaddr_u *	addr,
3992abb0f93cSkardel 	int		flags,
3993abb0f93cSkardel 	int		bcast
3994abb0f93cSkardel 	)
3995abb0f93cSkardel {
3996abb0f93cSkardel 	GETSOCKNAME_SOCKLEN_TYPE	sockaddrlen;
399745530cf1Skardel 	endpt *				iface;
3998abb0f93cSkardel 	sockaddr_u			saddr;
3999abb0f93cSkardel 	SOCKET				s;
4000abb0f93cSkardel 	int				rtn;
4001abb0f93cSkardel 	int				on;
4002abb0f93cSkardel 
4003abb0f93cSkardel 	DPRINTF(4, ("Finding interface for addr %s in list of addresses\n",
4004abb0f93cSkardel 		    stoa(addr)));
4005abb0f93cSkardel 
4006abb0f93cSkardel 	s = socket(AF(addr), SOCK_DGRAM, 0);
4007abb0f93cSkardel 	if (INVALID_SOCKET == s)
4008abb0f93cSkardel 		return NULL;
4009abb0f93cSkardel 
4010abb0f93cSkardel 	/*
4011abb0f93cSkardel 	 * If we are looking for broadcast interface we need to set this
4012abb0f93cSkardel 	 * socket to allow broadcast
4013abb0f93cSkardel 	 */
4014abb0f93cSkardel 	if (bcast) {
4015abb0f93cSkardel 		on = 1;
4016b3d6264cSchristos 		if (SOCKET_ERROR == setsockopt(s, SOL_SOCKET,
4017b3d6264cSchristos 						SO_BROADCAST,
4018b3d6264cSchristos 						(char *)&on,
4019b3d6264cSchristos 						sizeof(on))) {
4020b3d6264cSchristos 			closesocket(s);
4021b3d6264cSchristos 			return NULL;
4022b3d6264cSchristos 		}
4023abb0f93cSkardel 	}
4024abb0f93cSkardel 
4025abb0f93cSkardel 	rtn = connect(s, &addr->sa, SOCKLEN(addr));
4026abb0f93cSkardel 	if (SOCKET_ERROR == rtn) {
4027abb0f93cSkardel 		closesocket(s);
4028abb0f93cSkardel 		return NULL;
4029abb0f93cSkardel 	}
4030abb0f93cSkardel 
4031abb0f93cSkardel 	sockaddrlen = sizeof(saddr);
4032abb0f93cSkardel 	rtn = getsockname(s, &saddr.sa, &sockaddrlen);
4033abb0f93cSkardel 	closesocket(s);
4034abb0f93cSkardel 	if (SOCKET_ERROR == rtn)
4035abb0f93cSkardel 		return NULL;
4036abb0f93cSkardel 
4037abb0f93cSkardel 	DPRINTF(4, ("findlocalinterface: kernel maps %s to %s\n",
4038abb0f93cSkardel 		    stoa(addr), stoa(&saddr)));
4039abb0f93cSkardel 
4040abb0f93cSkardel 	iface = getinterface(&saddr, flags);
4041abb0f93cSkardel 
4042abb0f93cSkardel 	/*
404345530cf1Skardel 	 * if we didn't find an exact match on saddr, find the closest
404445530cf1Skardel 	 * available local address.  This handles the case of the
404545530cf1Skardel 	 * address suggested by the kernel being excluded by nic rules
404645530cf1Skardel 	 * or the user's -I and -L options to ntpd.
404745530cf1Skardel 	 * See http://bugs.ntp.org/1184 and http://bugs.ntp.org/1683
404845530cf1Skardel 	 * for more background.
4049abb0f93cSkardel 	 */
4050abb0f93cSkardel 	if (NULL == iface || iface->ignore_packets)
405145530cf1Skardel 		iface = findclosestinterface(&saddr,
405245530cf1Skardel 					     flags | INT_LOOPBACK);
4053abb0f93cSkardel 
4054abb0f93cSkardel 	/* Don't use an interface which will ignore replies */
4055abb0f93cSkardel 	if (iface != NULL && iface->ignore_packets)
4056abb0f93cSkardel 		iface = NULL;
4057abb0f93cSkardel 
4058abb0f93cSkardel 	return iface;
4059abb0f93cSkardel }
4060abb0f93cSkardel 
4061abb0f93cSkardel 
4062abb0f93cSkardel /*
406345530cf1Skardel  * findclosestinterface
406445530cf1Skardel  *
406545530cf1Skardel  * If there are -I/--interface or -L/novirtualips command-line options,
406645530cf1Skardel  * or "nic" or "interface" rules in ntp.conf, findlocalinterface() may
406745530cf1Skardel  * find the kernel's preferred local address for a given peer address is
406845530cf1Skardel  * administratively unavailable to ntpd, and punt to this routine's more
406945530cf1Skardel  * expensive search.
407045530cf1Skardel  *
407145530cf1Skardel  * Find the numerically closest local address to the one connect()
407245530cf1Skardel  * suggested.  This matches an address on the same subnet first, as
407345530cf1Skardel  * needed by Bug 1184, and provides a consistent choice if there are
407445530cf1Skardel  * multiple feasible local addresses, regardless of the order ntpd
407545530cf1Skardel  * enumerated them.
4076abb0f93cSkardel  */
4077b3d6264cSchristos endpt *
407845530cf1Skardel findclosestinterface(
4079abb0f93cSkardel 	sockaddr_u *	addr,
4080abb0f93cSkardel 	int		flags
4081abb0f93cSkardel 	)
4082abb0f93cSkardel {
408345530cf1Skardel 	endpt *		ep;
408445530cf1Skardel 	endpt *		winner;
408545530cf1Skardel 	sockaddr_u	addr_dist;
408645530cf1Skardel 	sockaddr_u	min_dist;
408745530cf1Skardel 
4088b3d6264cSchristos 	ZERO_SOCK(&min_dist);
408945530cf1Skardel 	winner = NULL;
409045530cf1Skardel 
409145530cf1Skardel 	for (ep = ep_list; ep != NULL; ep = ep->elink) {
409245530cf1Skardel 		if (ep->ignore_packets ||
409345530cf1Skardel 		    AF(addr) != ep->family ||
409445530cf1Skardel 		    flags & ep->flags)
409545530cf1Skardel 			continue;
409645530cf1Skardel 
409745530cf1Skardel 		calc_addr_distance(&addr_dist, addr, &ep->sin);
409845530cf1Skardel 		if (NULL == winner ||
409945530cf1Skardel 		    -1 == cmp_addr_distance(&addr_dist, &min_dist)) {
410045530cf1Skardel 			min_dist = addr_dist;
410145530cf1Skardel 			winner = ep;
410245530cf1Skardel 		}
410345530cf1Skardel 	}
410445530cf1Skardel 	if (NULL == winner)
410545530cf1Skardel 		DPRINTF(4, ("findclosestinterface(%s) failed\n",
410645530cf1Skardel 			    stoa(addr)));
410745530cf1Skardel 	else
410845530cf1Skardel 		DPRINTF(4, ("findclosestinterface(%s) -> %s\n",
410945530cf1Skardel 			    stoa(addr), stoa(&winner->sin)));
411045530cf1Skardel 
411145530cf1Skardel 	return winner;
411245530cf1Skardel }
411345530cf1Skardel 
411445530cf1Skardel 
411545530cf1Skardel /*
411645530cf1Skardel  * calc_addr_distance - calculate the distance between two addresses,
411745530cf1Skardel  *			the absolute value of the difference between
411845530cf1Skardel  *			the addresses numerically, stored as an address.
411945530cf1Skardel  */
412045530cf1Skardel static void
412145530cf1Skardel calc_addr_distance(
412245530cf1Skardel 	sockaddr_u *		dist,
412345530cf1Skardel 	const sockaddr_u *	a1,
412445530cf1Skardel 	const sockaddr_u *	a2
412545530cf1Skardel 	)
412645530cf1Skardel {
412745530cf1Skardel 	u_int32	a1val;
412845530cf1Skardel 	u_int32	a2val;
412945530cf1Skardel 	u_int32	v4dist;
413045530cf1Skardel 	int	found_greater;
413145530cf1Skardel 	int	a1_greater;
413245530cf1Skardel 	int	i;
413345530cf1Skardel 
413409f14f80Schristos 	REQUIRE(AF(a1) == AF(a2));
413545530cf1Skardel 
4136b3d6264cSchristos 	ZERO_SOCK(dist);
413745530cf1Skardel 	AF(dist) = AF(a1);
413845530cf1Skardel 
413945530cf1Skardel 	/* v4 can be done a bit simpler */
414045530cf1Skardel 	if (IS_IPV4(a1)) {
414145530cf1Skardel 		a1val = SRCADR(a1);
414245530cf1Skardel 		a2val = SRCADR(a2);
414345530cf1Skardel 		v4dist = (a1val > a2val)
414445530cf1Skardel 			     ? a1val - a2val
414545530cf1Skardel 			     : a2val - a1val;
414645530cf1Skardel 		SET_ADDR4(dist, v4dist);
414745530cf1Skardel 
414845530cf1Skardel 		return;
414945530cf1Skardel 	}
415045530cf1Skardel 
415145530cf1Skardel 	found_greater = FALSE;
415245530cf1Skardel 	a1_greater = FALSE;	/* suppress pot. uninit. warning */
4153f40817b7Skardel 	for (i = 0; i < (int)sizeof(NSRCADR6(a1)); i++) {
415445530cf1Skardel 		if (!found_greater &&
415545530cf1Skardel 		    NSRCADR6(a1)[i] != NSRCADR6(a2)[i]) {
415645530cf1Skardel 			found_greater = TRUE;
415745530cf1Skardel 			a1_greater = (NSRCADR6(a1)[i] > NSRCADR6(a2)[i]);
415845530cf1Skardel 		}
415945530cf1Skardel 		if (!found_greater) {
416045530cf1Skardel 			NSRCADR6(dist)[i] = 0;
416145530cf1Skardel 		} else {
416245530cf1Skardel 			if (a1_greater)
416345530cf1Skardel 				NSRCADR6(dist)[i] = NSRCADR6(a1)[i] -
416445530cf1Skardel 						    NSRCADR6(a2)[i];
416545530cf1Skardel 			else
416645530cf1Skardel 				NSRCADR6(dist)[i] = NSRCADR6(a2)[i] -
416745530cf1Skardel 						    NSRCADR6(a1)[i];
416845530cf1Skardel 		}
416945530cf1Skardel 	}
417045530cf1Skardel }
417145530cf1Skardel 
417245530cf1Skardel 
417345530cf1Skardel /*
417445530cf1Skardel  * cmp_addr_distance - compare two address distances, returning -1, 0,
417545530cf1Skardel  *		       1 to indicate their relationship.
417645530cf1Skardel  */
417745530cf1Skardel static int
417845530cf1Skardel cmp_addr_distance(
417945530cf1Skardel 	const sockaddr_u *	d1,
418045530cf1Skardel 	const sockaddr_u *	d2
418145530cf1Skardel 	)
418245530cf1Skardel {
418345530cf1Skardel 	int	i;
418445530cf1Skardel 
418509f14f80Schristos 	REQUIRE(AF(d1) == AF(d2));
418645530cf1Skardel 
418745530cf1Skardel 	if (IS_IPV4(d1)) {
418845530cf1Skardel 		if (SRCADR(d1) < SRCADR(d2))
418945530cf1Skardel 			return -1;
419045530cf1Skardel 		else if (SRCADR(d1) == SRCADR(d2))
419145530cf1Skardel 			return 0;
419245530cf1Skardel 		else
419345530cf1Skardel 			return 1;
419445530cf1Skardel 	}
419545530cf1Skardel 
4196f40817b7Skardel 	for (i = 0; i < (int)sizeof(NSRCADR6(d1)); i++) {
419745530cf1Skardel 		if (NSRCADR6(d1)[i] < NSRCADR6(d2)[i])
419845530cf1Skardel 			return -1;
419945530cf1Skardel 		else if (NSRCADR6(d1)[i] > NSRCADR6(d2)[i])
420045530cf1Skardel 			return 1;
420145530cf1Skardel 	}
420245530cf1Skardel 
420345530cf1Skardel 	return 0;
420445530cf1Skardel }
420545530cf1Skardel 
420645530cf1Skardel 
420745530cf1Skardel 
420845530cf1Skardel /*
420945530cf1Skardel  * fetch an interface structure the matches the
421045530cf1Skardel  * address and has the given flags NOT set
421145530cf1Skardel  */
4212b3d6264cSchristos endpt *
421345530cf1Skardel getinterface(
421445530cf1Skardel 	sockaddr_u *	addr,
421545530cf1Skardel 	u_int32		flags
421645530cf1Skardel 	)
421745530cf1Skardel {
421845530cf1Skardel 	endpt *iface;
4219abb0f93cSkardel 
4220abb0f93cSkardel 	iface = find_addr_in_list(addr);
4221abb0f93cSkardel 
4222abb0f93cSkardel 	if (iface != NULL && (iface->flags & flags))
4223abb0f93cSkardel 		iface = NULL;
4224abb0f93cSkardel 
4225abb0f93cSkardel 	return iface;
4226abb0f93cSkardel }
4227abb0f93cSkardel 
4228abb0f93cSkardel 
4229abb0f93cSkardel /*
4230abb0f93cSkardel  * findbcastinter - find broadcast interface corresponding to address
4231abb0f93cSkardel  */
423245530cf1Skardel endpt *
4233abb0f93cSkardel findbcastinter(
4234abb0f93cSkardel 	sockaddr_u *addr
4235abb0f93cSkardel 	)
4236abb0f93cSkardel {
4237b3d6264cSchristos 	endpt *	iface;
4238b3d6264cSchristos 
4239b3d6264cSchristos 	iface = NULL;
4240abb0f93cSkardel #if !defined(MPE) && (defined(SIOCGIFCONF) || defined(SYS_WINNT))
4241abb0f93cSkardel 	DPRINTF(4, ("Finding broadcast/multicast interface for addr %s in list of addresses\n",
4242abb0f93cSkardel 		    stoa(addr)));
4243abb0f93cSkardel 
4244abb0f93cSkardel 	iface = findlocalinterface(addr, INT_LOOPBACK | INT_WILDCARD,
4245abb0f93cSkardel 				   1);
4246abb0f93cSkardel 	if (iface != NULL) {
4247abb0f93cSkardel 		DPRINTF(4, ("Easily found bcast-/mcast- interface index #%d %s\n",
4248abb0f93cSkardel 			    iface->ifnum, iface->name));
4249abb0f93cSkardel 		return iface;
4250abb0f93cSkardel 	}
4251abb0f93cSkardel 
4252abb0f93cSkardel 	/*
4253abb0f93cSkardel 	 * plan B - try to find something reasonable in our lists in
4254abb0f93cSkardel 	 * case kernel lookup doesn't help
4255abb0f93cSkardel 	 */
425645530cf1Skardel 	for (iface = ep_list; iface != NULL; iface = iface->elink) {
4257abb0f93cSkardel 		if (iface->flags & INT_WILDCARD)
4258abb0f93cSkardel 			continue;
4259abb0f93cSkardel 
4260abb0f93cSkardel 		/* Don't bother with ignored interfaces */
4261abb0f93cSkardel 		if (iface->ignore_packets)
4262abb0f93cSkardel 			continue;
4263abb0f93cSkardel 
4264abb0f93cSkardel 		/*
4265abb0f93cSkardel 		 * First look if this is the correct family
4266abb0f93cSkardel 		 */
4267abb0f93cSkardel 		if(AF(&iface->sin) != AF(addr))
4268abb0f93cSkardel 			continue;
4269abb0f93cSkardel 
4270abb0f93cSkardel 		/* Skip the loopback addresses */
4271abb0f93cSkardel 		if (iface->flags & INT_LOOPBACK)
4272abb0f93cSkardel 			continue;
4273abb0f93cSkardel 
4274abb0f93cSkardel 		/*
4275abb0f93cSkardel 		 * If we are looking to match a multicast address and
4276abb0f93cSkardel 		 * this interface is one...
4277abb0f93cSkardel 		 */
4278abb0f93cSkardel 		if (addr_ismulticast(addr)
4279abb0f93cSkardel 		    && (iface->flags & INT_MULTICAST)) {
4280abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT
4281abb0f93cSkardel 			/*
4282abb0f93cSkardel 			 * ...it is the winner unless we're looking for
4283abb0f93cSkardel 			 * an interface to use for link-local multicast
4284abb0f93cSkardel 			 * and its address is not link-local.
4285abb0f93cSkardel 			 */
4286abb0f93cSkardel 			if (IS_IPV6(addr)
4287abb0f93cSkardel 			    && IN6_IS_ADDR_MC_LINKLOCAL(PSOCK_ADDR6(addr))
4288abb0f93cSkardel 			    && !IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(&iface->sin)))
4289abb0f93cSkardel 				continue;
4290abb0f93cSkardel #endif
4291abb0f93cSkardel 			break;
4292abb0f93cSkardel 		}
4293abb0f93cSkardel 
4294abb0f93cSkardel 		/*
4295abb0f93cSkardel 		 * We match only those interfaces marked as
4296abb0f93cSkardel 		 * broadcastable and either the explicit broadcast
4297abb0f93cSkardel 		 * address or the network portion of the IP address.
4298abb0f93cSkardel 		 * Sloppy.
4299abb0f93cSkardel 		 */
4300abb0f93cSkardel 		if (IS_IPV4(addr)) {
4301abb0f93cSkardel 			if (SOCK_EQ(&iface->bcast, addr))
4302abb0f93cSkardel 				break;
4303abb0f93cSkardel 
4304abb0f93cSkardel 			if ((NSRCADR(&iface->sin) & NSRCADR(&iface->mask))
4305abb0f93cSkardel 			    == (NSRCADR(addr)	  & NSRCADR(&iface->mask)))
4306abb0f93cSkardel 				break;
4307abb0f93cSkardel 		}
4308abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT
4309abb0f93cSkardel 		else if (IS_IPV6(addr)) {
4310abb0f93cSkardel 			if (SOCK_EQ(&iface->bcast, addr))
4311abb0f93cSkardel 				break;
4312abb0f93cSkardel 
4313abb0f93cSkardel 			if (SOCK_EQ(netof(&iface->sin), netof(addr)))
4314abb0f93cSkardel 				break;
4315abb0f93cSkardel 		}
4316abb0f93cSkardel #endif
4317abb0f93cSkardel 	}
4318abb0f93cSkardel #endif /* SIOCGIFCONF */
4319abb0f93cSkardel 	if (NULL == iface) {
4320abb0f93cSkardel 		DPRINTF(4, ("No bcast interface found for %s\n",
4321abb0f93cSkardel 			    stoa(addr)));
4322abb0f93cSkardel 		iface = ANY_INTERFACE_CHOOSE(addr);
4323b3d6264cSchristos 	} else {
4324abb0f93cSkardel 		DPRINTF(4, ("Found bcast-/mcast- interface index #%d %s\n",
4325abb0f93cSkardel 			    iface->ifnum, iface->name));
4326b3d6264cSchristos 	}
4327b3d6264cSchristos 
4328abb0f93cSkardel 	return iface;
4329abb0f93cSkardel }
4330abb0f93cSkardel 
4331abb0f93cSkardel 
4332abb0f93cSkardel /*
4333abb0f93cSkardel  * io_clr_stats - clear I/O module statistics
4334abb0f93cSkardel  */
4335abb0f93cSkardel void
4336abb0f93cSkardel io_clr_stats(void)
4337abb0f93cSkardel {
4338abb0f93cSkardel 	packets_dropped = 0;
4339abb0f93cSkardel 	packets_ignored = 0;
4340abb0f93cSkardel 	packets_received = 0;
4341abb0f93cSkardel 	packets_sent = 0;
4342abb0f93cSkardel 	packets_notsent = 0;
4343abb0f93cSkardel 
4344abb0f93cSkardel 	handler_calls = 0;
4345abb0f93cSkardel 	handler_pkts = 0;
4346abb0f93cSkardel 	io_timereset = current_time;
4347abb0f93cSkardel }
4348abb0f93cSkardel 
4349abb0f93cSkardel 
4350abb0f93cSkardel #ifdef REFCLOCK
4351abb0f93cSkardel /*
4352abb0f93cSkardel  * io_addclock - add a reference clock to the list and arrange that we
4353abb0f93cSkardel  *				 get SIGIO interrupts from it.
4354abb0f93cSkardel  */
4355abb0f93cSkardel int
4356abb0f93cSkardel io_addclock(
4357abb0f93cSkardel 	struct refclockio *rio
4358abb0f93cSkardel 	)
4359abb0f93cSkardel {
4360abb0f93cSkardel 	BLOCKIO();
4361abb0f93cSkardel 
4362abb0f93cSkardel 	/*
4363abb0f93cSkardel 	 * Stuff the I/O structure in the list and mark the descriptor
4364abb0f93cSkardel 	 * in use.  There is a harmless (I hope) race condition here.
4365abb0f93cSkardel 	 */
4366b3d6264cSchristos 	rio->active = TRUE;
4367abb0f93cSkardel 
4368abb0f93cSkardel # ifdef HAVE_SIGNALED_IO
4369abb0f93cSkardel 	if (init_clock_sig(rio)) {
4370abb0f93cSkardel 		UNBLOCKIO();
4371abb0f93cSkardel 		return 0;
4372abb0f93cSkardel 	}
4373abb0f93cSkardel # elif defined(HAVE_IO_COMPLETION_PORT)
4374335f7552Schristos 	if (!io_completion_port_add_clock_io(rio)) {
4375abb0f93cSkardel 		UNBLOCKIO();
4376abb0f93cSkardel 		return 0;
4377abb0f93cSkardel 	}
4378abb0f93cSkardel # endif
4379abb0f93cSkardel 
4380abb0f93cSkardel 	/*
4381abb0f93cSkardel 	 * enqueue
4382abb0f93cSkardel 	 */
4383b3d6264cSchristos 	LINK_SLIST(refio, rio, next);
4384abb0f93cSkardel 
4385abb0f93cSkardel 	/*
4386abb0f93cSkardel 	 * register fd
4387abb0f93cSkardel 	 */
4388abb0f93cSkardel 	add_fd_to_list(rio->fd, FD_TYPE_FILE);
4389abb0f93cSkardel 
4390abb0f93cSkardel 	UNBLOCKIO();
4391abb0f93cSkardel 	return 1;
4392abb0f93cSkardel }
4393abb0f93cSkardel 
4394b3d6264cSchristos 
4395abb0f93cSkardel /*
4396abb0f93cSkardel  * io_closeclock - close the clock in the I/O structure given
4397abb0f93cSkardel  */
4398abb0f93cSkardel void
4399abb0f93cSkardel io_closeclock(
4400abb0f93cSkardel 	struct refclockio *rio
4401abb0f93cSkardel 	)
4402abb0f93cSkardel {
4403b3d6264cSchristos 	struct refclockio *unlinked;
4404abb0f93cSkardel 
4405abb0f93cSkardel 	BLOCKIO();
4406abb0f93cSkardel 
4407abb0f93cSkardel 	/*
4408abb0f93cSkardel 	 * Remove structure from the list
4409abb0f93cSkardel 	 */
4410b3d6264cSchristos 	rio->active = FALSE;
4411b3d6264cSchristos 	UNLINK_SLIST(unlinked, refio, rio, next, struct refclockio);
4412b3d6264cSchristos 	if (NULL != unlinked) {
4413335f7552Schristos 		/* Close the descriptor. The order of operations is
4414335f7552Schristos 		 * important here in case of async / overlapped IO:
4415335f7552Schristos 		 * only after we have removed the clock from the
4416335f7552Schristos 		 * IO completion port we can be sure no further
4417335f7552Schristos 		 * input is queued. So...
4418335f7552Schristos 		 *  - we first disable feeding to the queu by removing
4419335f7552Schristos 		 *    the clock from the IO engine
4420335f7552Schristos 		 *  - close the file (which brings down any IO on it)
4421335f7552Schristos 		 *  - clear the buffer from results for this fd
4422abb0f93cSkardel 		 */
4423335f7552Schristos #	    ifdef HAVE_IO_COMPLETION_PORT
4424335f7552Schristos 		io_completion_port_remove_clock_io(rio);
4425335f7552Schristos #	    endif
4426abb0f93cSkardel 		close_and_delete_fd_from_list(rio->fd);
4427335f7552Schristos 		purge_recv_buffers_for_fd(rio->fd);
4428b3d6264cSchristos 		rio->fd = -1;
4429335f7552Schristos 	}
4430b3d6264cSchristos 
4431abb0f93cSkardel 	UNBLOCKIO();
4432abb0f93cSkardel }
4433abb0f93cSkardel #endif	/* REFCLOCK */
4434abb0f93cSkardel 
4435b3d6264cSchristos 
4436abb0f93cSkardel /*
4437abb0f93cSkardel  * On NT a SOCKET is an unsigned int so we cannot possibly keep it in
4438abb0f93cSkardel  * an array. So we use one of the ISC_LIST functions to hold the
4439abb0f93cSkardel  * socket value and use that when we want to enumerate it.
4440abb0f93cSkardel  *
4441abb0f93cSkardel  * This routine is called by the forked intres child process to close
4442abb0f93cSkardel  * all open sockets.  On Windows there's no need as intres runs in
4443abb0f93cSkardel  * the same process as a thread.
4444abb0f93cSkardel  */
4445abb0f93cSkardel #ifndef SYS_WINNT
4446abb0f93cSkardel void
4447b3d6264cSchristos kill_asyncio(
4448b3d6264cSchristos 	int	startfd
4449b3d6264cSchristos 	)
4450abb0f93cSkardel {
4451abb0f93cSkardel 	BLOCKIO();
4452abb0f93cSkardel 
4453abb0f93cSkardel 	/*
4454abb0f93cSkardel 	 * In the child process we do not maintain activefds and
4455abb0f93cSkardel 	 * maxactivefd.  Zeroing maxactivefd disables code which
4456abb0f93cSkardel 	 * maintains it in close_and_delete_fd_from_list().
4457abb0f93cSkardel 	 */
4458abb0f93cSkardel 	maxactivefd = 0;
4459abb0f93cSkardel 
4460abb0f93cSkardel 	while (fd_list != NULL)
4461abb0f93cSkardel 		close_and_delete_fd_from_list(fd_list->fd);
4462abb0f93cSkardel 
4463abb0f93cSkardel 	UNBLOCKIO();
4464abb0f93cSkardel }
4465abb0f93cSkardel #endif	/* !SYS_WINNT */
4466abb0f93cSkardel 
4467b3d6264cSchristos 
4468abb0f93cSkardel /*
4469abb0f93cSkardel  * Add and delete functions for the list of open sockets
4470abb0f93cSkardel  */
4471abb0f93cSkardel static void
4472abb0f93cSkardel add_fd_to_list(
4473abb0f93cSkardel 	SOCKET fd,
4474abb0f93cSkardel 	enum desc_type type
4475abb0f93cSkardel 	)
4476abb0f93cSkardel {
4477abb0f93cSkardel 	vsock_t *lsock = emalloc(sizeof(*lsock));
4478abb0f93cSkardel 
4479abb0f93cSkardel 	lsock->fd = fd;
4480abb0f93cSkardel 	lsock->type = type;
4481abb0f93cSkardel 
4482abb0f93cSkardel 	LINK_SLIST(fd_list, lsock, link);
4483b3d6264cSchristos 	maintain_activefds(fd, 0);
4484abb0f93cSkardel }
4485abb0f93cSkardel 
4486abb0f93cSkardel 
4487abb0f93cSkardel static void
4488abb0f93cSkardel close_and_delete_fd_from_list(
4489abb0f93cSkardel 	SOCKET fd
4490abb0f93cSkardel 	)
4491abb0f93cSkardel {
4492abb0f93cSkardel 	vsock_t *lsock;
4493abb0f93cSkardel 
4494abb0f93cSkardel 	UNLINK_EXPR_SLIST(lsock, fd_list, fd ==
4495abb0f93cSkardel 	    UNLINK_EXPR_SLIST_CURRENT()->fd, link, vsock_t);
4496abb0f93cSkardel 
4497b3d6264cSchristos 	if (NULL == lsock)
4498b3d6264cSchristos 		return;
4499b3d6264cSchristos 
4500abb0f93cSkardel 	switch (lsock->type) {
4501b3d6264cSchristos 
4502abb0f93cSkardel 	case FD_TYPE_SOCKET:
4503abb0f93cSkardel 		closesocket(lsock->fd);
4504abb0f93cSkardel 		break;
4505abb0f93cSkardel 
4506abb0f93cSkardel 	case FD_TYPE_FILE:
4507bd25f4c4Schristos 		closeserial((int)lsock->fd);
4508abb0f93cSkardel 		break;
4509abb0f93cSkardel 
4510abb0f93cSkardel 	default:
4511abb0f93cSkardel 		msyslog(LOG_ERR,
4512abb0f93cSkardel 			"internal error - illegal descriptor type %d - EXITING",
4513abb0f93cSkardel 			(int)lsock->type);
4514abb0f93cSkardel 		exit(1);
4515abb0f93cSkardel 	}
4516abb0f93cSkardel 
4517abb0f93cSkardel 	free(lsock);
4518abb0f93cSkardel 	/*
4519abb0f93cSkardel 	 * remove from activefds
4520abb0f93cSkardel 	 */
4521b3d6264cSchristos 	maintain_activefds(fd, 1);
4522b3d6264cSchristos }
4523abb0f93cSkardel 
4524abb0f93cSkardel 
4525abb0f93cSkardel static void
4526abb0f93cSkardel add_addr_to_list(
4527abb0f93cSkardel 	sockaddr_u *	addr,
452845530cf1Skardel 	endpt *		ep
4529abb0f93cSkardel 	)
4530abb0f93cSkardel {
4531abb0f93cSkardel 	remaddr_t *laddr;
4532abb0f93cSkardel 
4533abb0f93cSkardel #ifdef DEBUG
4534abb0f93cSkardel 	if (find_addr_in_list(addr) == NULL) {
4535abb0f93cSkardel #endif
4536abb0f93cSkardel 		/* not there yet - add to list */
4537abb0f93cSkardel 		laddr = emalloc(sizeof(*laddr));
453845530cf1Skardel 		laddr->addr = *addr;
453945530cf1Skardel 		laddr->ep = ep;
4540abb0f93cSkardel 
4541abb0f93cSkardel 		LINK_SLIST(remoteaddr_list, laddr, link);
4542abb0f93cSkardel 
4543abb0f93cSkardel 		DPRINTF(4, ("Added addr %s to list of addresses\n",
4544abb0f93cSkardel 			    stoa(addr)));
4545abb0f93cSkardel #ifdef DEBUG
4546abb0f93cSkardel 	} else
4547abb0f93cSkardel 		DPRINTF(4, ("WARNING: Attempt to add duplicate addr %s to address list\n",
4548abb0f93cSkardel 			    stoa(addr)));
4549abb0f93cSkardel #endif
4550abb0f93cSkardel }
4551abb0f93cSkardel 
4552abb0f93cSkardel 
4553abb0f93cSkardel static void
4554abb0f93cSkardel delete_addr_from_list(
4555abb0f93cSkardel 	sockaddr_u *addr
4556abb0f93cSkardel 	)
4557abb0f93cSkardel {
4558abb0f93cSkardel 	remaddr_t *unlinked;
4559abb0f93cSkardel 
4560abb0f93cSkardel 	UNLINK_EXPR_SLIST(unlinked, remoteaddr_list, SOCK_EQ(addr,
4561abb0f93cSkardel 		&(UNLINK_EXPR_SLIST_CURRENT()->addr)), link, remaddr_t);
4562abb0f93cSkardel 
4563abb0f93cSkardel 	if (unlinked != NULL) {
4564abb0f93cSkardel 		DPRINTF(4, ("Deleted addr %s from list of addresses\n",
4565abb0f93cSkardel 			stoa(addr)));
4566abb0f93cSkardel 		free(unlinked);
4567abb0f93cSkardel 	}
4568abb0f93cSkardel }
4569abb0f93cSkardel 
4570abb0f93cSkardel 
4571abb0f93cSkardel static void
4572abb0f93cSkardel delete_interface_from_list(
457345530cf1Skardel 	endpt *iface
4574abb0f93cSkardel 	)
4575abb0f93cSkardel {
4576abb0f93cSkardel 	remaddr_t *unlinked;
4577abb0f93cSkardel 
4578ad131110Schristos 	for (;;) {
4579abb0f93cSkardel 		UNLINK_EXPR_SLIST(unlinked, remoteaddr_list, iface ==
458045530cf1Skardel 		    UNLINK_EXPR_SLIST_CURRENT()->ep, link,
4581abb0f93cSkardel 		    remaddr_t);
4582abb0f93cSkardel 
4583ad131110Schristos 		if (unlinked == NULL)
4584ad131110Schristos 			break;
4585abb0f93cSkardel 		DPRINTF(4, ("Deleted addr %s for interface #%d %s from list of addresses\n",
4586abb0f93cSkardel 			    stoa(&unlinked->addr), iface->ifnum,
4587abb0f93cSkardel 			    iface->name));
4588abb0f93cSkardel 		free(unlinked);
4589abb0f93cSkardel 	}
4590abb0f93cSkardel }
4591abb0f93cSkardel 
4592abb0f93cSkardel 
4593abb0f93cSkardel static struct interface *
4594abb0f93cSkardel find_addr_in_list(
4595abb0f93cSkardel 	sockaddr_u *addr
4596abb0f93cSkardel 	)
4597abb0f93cSkardel {
4598abb0f93cSkardel 	remaddr_t *entry;
4599abb0f93cSkardel 
4600abb0f93cSkardel 	DPRINTF(4, ("Searching for addr %s in list of addresses - ",
4601abb0f93cSkardel 		    stoa(addr)));
4602abb0f93cSkardel 
4603abb0f93cSkardel 	for (entry = remoteaddr_list;
4604abb0f93cSkardel 	     entry != NULL;
4605abb0f93cSkardel 	     entry = entry->link)
4606abb0f93cSkardel 		if (SOCK_EQ(&entry->addr, addr)) {
4607abb0f93cSkardel 			DPRINTF(4, ("FOUND\n"));
460845530cf1Skardel 			return entry->ep;
4609abb0f93cSkardel 		}
4610abb0f93cSkardel 
4611abb0f93cSkardel 	DPRINTF(4, ("NOT FOUND\n"));
4612abb0f93cSkardel 	return NULL;
4613abb0f93cSkardel }
4614abb0f93cSkardel 
4615abb0f93cSkardel 
4616abb0f93cSkardel /*
4617abb0f93cSkardel  * Find the given address with the all given flags set in the list
4618abb0f93cSkardel  */
461945530cf1Skardel static endpt *
4620abb0f93cSkardel find_flagged_addr_in_list(
4621abb0f93cSkardel 	sockaddr_u *	addr,
462245530cf1Skardel 	u_int32		flags
4623abb0f93cSkardel 	)
4624abb0f93cSkardel {
4625abb0f93cSkardel 	remaddr_t *entry;
4626abb0f93cSkardel 
4627abb0f93cSkardel 	DPRINTF(4, ("Finding addr %s with flags %d in list: ",
4628abb0f93cSkardel 		    stoa(addr), flags));
4629abb0f93cSkardel 
4630abb0f93cSkardel 	for (entry = remoteaddr_list;
4631abb0f93cSkardel 	     entry != NULL;
4632abb0f93cSkardel 	     entry = entry->link)
4633abb0f93cSkardel 
4634abb0f93cSkardel 		if (SOCK_EQ(&entry->addr, addr)
463545530cf1Skardel 		    && (entry->ep->flags & flags) == flags) {
4636abb0f93cSkardel 
4637abb0f93cSkardel 			DPRINTF(4, ("FOUND\n"));
463845530cf1Skardel 			return entry->ep;
4639abb0f93cSkardel 		}
4640abb0f93cSkardel 
4641abb0f93cSkardel 	DPRINTF(4, ("NOT FOUND\n"));
4642abb0f93cSkardel 	return NULL;
4643abb0f93cSkardel }
4644abb0f93cSkardel 
4645abb0f93cSkardel 
464645530cf1Skardel const char *
464745530cf1Skardel localaddrtoa(
464845530cf1Skardel 	endpt *la
464945530cf1Skardel 	)
465045530cf1Skardel {
465145530cf1Skardel 	return (NULL == la)
465245530cf1Skardel 		   ? "<null>"
465345530cf1Skardel 		   : stoa(&la->sin);
465445530cf1Skardel }
465545530cf1Skardel 
465645530cf1Skardel 
4657abb0f93cSkardel #ifdef HAS_ROUTING_SOCKET
4658abb0f93cSkardel # ifndef UPDATE_GRACE
4659abb0f93cSkardel #  define UPDATE_GRACE	2	/* wait UPDATE_GRACE seconds before scanning */
4660abb0f93cSkardel # endif
4661abb0f93cSkardel 
4662abb0f93cSkardel static void
4663abb0f93cSkardel process_routing_msgs(struct asyncio_reader *reader)
4664abb0f93cSkardel {
4665abb0f93cSkardel 	char buffer[5120];
4666abb0f93cSkardel 	int cnt, msg_type;
4667abb0f93cSkardel #ifdef HAVE_RTNETLINK
4668abb0f93cSkardel 	struct nlmsghdr *nh;
4669abb0f93cSkardel #else
4670b3d6264cSchristos 	struct rt_msghdr rtm;
4671abb0f93cSkardel 	char *p;
4672abb0f93cSkardel #endif
4673abb0f93cSkardel 
4674abb0f93cSkardel 	if (disable_dynamic_updates) {
4675abb0f93cSkardel 		/*
4676abb0f93cSkardel 		 * discard ourselves if we are not needed any more
4677abb0f93cSkardel 		 * usually happens when running unprivileged
4678abb0f93cSkardel 		 */
4679abb0f93cSkardel 		remove_asyncio_reader(reader);
4680abb0f93cSkardel 		delete_asyncio_reader(reader);
4681abb0f93cSkardel 		return;
4682abb0f93cSkardel 	}
4683abb0f93cSkardel 
4684abb0f93cSkardel 	cnt = read(reader->fd, buffer, sizeof(buffer));
4685abb0f93cSkardel 
4686abb0f93cSkardel 	if (cnt < 0) {
468709f14f80Schristos 		if (errno == ENOBUFS) {
4688abb0f93cSkardel 			msyslog(LOG_ERR,
468909f14f80Schristos 				"routing socket reports: %m");
469009f14f80Schristos 		} else {
469109f14f80Schristos 			msyslog(LOG_ERR,
469209f14f80Schristos 				"routing socket reports: %m - disabling");
4693abb0f93cSkardel 			remove_asyncio_reader(reader);
4694abb0f93cSkardel 			delete_asyncio_reader(reader);
469509f14f80Schristos 		}
4696abb0f93cSkardel 		return;
4697abb0f93cSkardel 	}
4698abb0f93cSkardel 
4699abb0f93cSkardel 	/*
4700abb0f93cSkardel 	 * process routing message
4701abb0f93cSkardel 	 */
4702abb0f93cSkardel #ifdef HAVE_RTNETLINK
4703bd25f4c4Schristos 	for (nh = UA_PTR(struct nlmsghdr, buffer);
4704abb0f93cSkardel 	     NLMSG_OK(nh, cnt);
4705abb0f93cSkardel 	     nh = NLMSG_NEXT(nh, cnt)) {
4706abb0f93cSkardel 		msg_type = nh->nlmsg_type;
4707abb0f93cSkardel #else
4708abb0f93cSkardel 	for (p = buffer;
4709abb0f93cSkardel 	     (p + sizeof(struct rt_msghdr)) <= (buffer + cnt);
4710b3d6264cSchristos 	     p += rtm.rtm_msglen) {
4711b3d6264cSchristos 		memcpy(&rtm, p, sizeof(rtm));
4712b3d6264cSchristos 		if (rtm.rtm_version != RTM_VERSION) {
4713abb0f93cSkardel 			msyslog(LOG_ERR,
4714abb0f93cSkardel 				"version mismatch (got %d - expected %d) on routing socket - disabling",
4715b3d6264cSchristos 				rtm.rtm_version, RTM_VERSION);
4716abb0f93cSkardel 
4717abb0f93cSkardel 			remove_asyncio_reader(reader);
4718abb0f93cSkardel 			delete_asyncio_reader(reader);
4719abb0f93cSkardel 			return;
4720abb0f93cSkardel 		}
4721b3d6264cSchristos 		msg_type = rtm.rtm_type;
4722abb0f93cSkardel #endif
4723abb0f93cSkardel 		switch (msg_type) {
4724abb0f93cSkardel #ifdef RTM_NEWADDR
4725abb0f93cSkardel 		case RTM_NEWADDR:
4726abb0f93cSkardel #endif
4727abb0f93cSkardel #ifdef RTM_DELADDR
4728abb0f93cSkardel 		case RTM_DELADDR:
4729abb0f93cSkardel #endif
4730abb0f93cSkardel #ifdef RTM_ADD
4731abb0f93cSkardel 		case RTM_ADD:
4732abb0f93cSkardel #endif
4733abb0f93cSkardel #ifdef RTM_DELETE
4734abb0f93cSkardel 		case RTM_DELETE:
4735abb0f93cSkardel #endif
4736abb0f93cSkardel #ifdef RTM_REDIRECT
4737abb0f93cSkardel 		case RTM_REDIRECT:
4738abb0f93cSkardel #endif
4739abb0f93cSkardel #ifdef RTM_CHANGE
4740abb0f93cSkardel 		case RTM_CHANGE:
4741abb0f93cSkardel #endif
4742abb0f93cSkardel #ifdef RTM_LOSING
4743abb0f93cSkardel 		case RTM_LOSING:
4744abb0f93cSkardel #endif
4745abb0f93cSkardel #ifdef RTM_IFINFO
4746abb0f93cSkardel 		case RTM_IFINFO:
4747abb0f93cSkardel #endif
4748abb0f93cSkardel #ifdef RTM_IFANNOUNCE
4749abb0f93cSkardel 		case RTM_IFANNOUNCE:
4750abb0f93cSkardel #endif
4751abb0f93cSkardel #ifdef RTM_NEWLINK
4752abb0f93cSkardel 		case RTM_NEWLINK:
4753abb0f93cSkardel #endif
4754abb0f93cSkardel #ifdef RTM_DELLINK
4755abb0f93cSkardel 		case RTM_DELLINK:
4756abb0f93cSkardel #endif
4757abb0f93cSkardel #ifdef RTM_NEWROUTE
4758abb0f93cSkardel 		case RTM_NEWROUTE:
4759abb0f93cSkardel #endif
4760abb0f93cSkardel #ifdef RTM_DELROUTE
4761abb0f93cSkardel 		case RTM_DELROUTE:
4762abb0f93cSkardel #endif
4763abb0f93cSkardel 			/*
4764abb0f93cSkardel 			 * we are keen on new and deleted addresses and
4765abb0f93cSkardel 			 * if an interface goes up and down or routing
4766abb0f93cSkardel 			 * changes
4767abb0f93cSkardel 			 */
4768abb0f93cSkardel 			DPRINTF(3, ("routing message op = %d: scheduling interface update\n",
4769abb0f93cSkardel 				    msg_type));
4770abb0f93cSkardel 			timer_interfacetimeout(current_time + UPDATE_GRACE);
4771abb0f93cSkardel 			break;
4772abb0f93cSkardel #ifdef HAVE_RTNETLINK
4773abb0f93cSkardel 		case NLMSG_DONE:
4774abb0f93cSkardel 			/* end of multipart message */
4775abb0f93cSkardel 			return;
4776abb0f93cSkardel #endif
4777abb0f93cSkardel 		default:
4778abb0f93cSkardel 			/*
4779abb0f93cSkardel 			 * the rest doesn't bother us.
4780abb0f93cSkardel 			 */
4781abb0f93cSkardel 			DPRINTF(4, ("routing message op = %d: ignored\n",
4782abb0f93cSkardel 				    msg_type));
4783abb0f93cSkardel 			break;
4784abb0f93cSkardel 		}
4785abb0f93cSkardel 	}
4786abb0f93cSkardel }
4787abb0f93cSkardel 
4788abb0f93cSkardel /*
4789abb0f93cSkardel  * set up routing notifications
4790abb0f93cSkardel  */
4791abb0f93cSkardel static void
4792abb0f93cSkardel init_async_notifications()
4793abb0f93cSkardel {
4794abb0f93cSkardel 	struct asyncio_reader *reader;
4795abb0f93cSkardel #ifdef HAVE_RTNETLINK
4796abb0f93cSkardel 	int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
4797abb0f93cSkardel 	struct sockaddr_nl sa;
4798abb0f93cSkardel #else
4799abb0f93cSkardel 	int fd = socket(PF_ROUTE, SOCK_RAW, 0);
4800abb0f93cSkardel #endif
4801867deecaSroy #ifdef RO_MSGFILTER
4802867deecaSroy 	unsigned char msgfilter[] = {
4803867deecaSroy #ifdef RTM_NEWADDR
4804867deecaSroy 		RTM_NEWADDR,
4805867deecaSroy #endif
4806867deecaSroy #ifdef RTM_DELADDR
4807867deecaSroy 		RTM_DELADDR,
4808867deecaSroy #endif
4809867deecaSroy #ifdef RTM_ADD
4810867deecaSroy 		RTM_ADD,
4811867deecaSroy #endif
4812867deecaSroy #ifdef RTM_DELETE
4813867deecaSroy 		RTM_DELETE,
4814867deecaSroy #endif
4815867deecaSroy #ifdef RTM_REDIRECT
4816867deecaSroy 		RTM_REDIRECT,
4817867deecaSroy #endif
4818867deecaSroy #ifdef RTM_CHANGE
4819867deecaSroy 		RTM_CHANGE,
4820867deecaSroy #endif
4821867deecaSroy #ifdef RTM_LOSING
4822867deecaSroy 		RTM_LOSING,
4823867deecaSroy #endif
4824867deecaSroy #ifdef RTM_IFINFO
4825867deecaSroy 		RTM_IFINFO,
4826867deecaSroy #endif
4827867deecaSroy #ifdef RTM_IFANNOUNCE
4828867deecaSroy 		RTM_IFANNOUNCE,
4829867deecaSroy #endif
4830867deecaSroy #ifdef RTM_NEWLINK
4831867deecaSroy 		RTM_NEWLINK,
4832867deecaSroy #endif
4833867deecaSroy #ifdef RTM_DELLINK
4834867deecaSroy 		RTM_DELLINK,
4835867deecaSroy #endif
4836867deecaSroy #ifdef RTM_NEWROUTE
4837867deecaSroy 		RTM_NEWROUTE,
4838867deecaSroy #endif
4839867deecaSroy #ifdef RTM_DELROUTE
4840867deecaSroy 		RTM_DELROUTE,
4841867deecaSroy #endif
4842867deecaSroy 	};
4843867deecaSroy #endif /* !RO_MSGFILTER */
4844867deecaSroy 
4845abb0f93cSkardel 	if (fd < 0) {
4846abb0f93cSkardel 		msyslog(LOG_ERR,
4847abb0f93cSkardel 			"unable to open routing socket (%m) - using polled interface update");
4848abb0f93cSkardel 		return;
4849abb0f93cSkardel 	}
4850abb0f93cSkardel 
4851abb0f93cSkardel 	fd = move_fd(fd);
4852abb0f93cSkardel #ifdef HAVE_RTNETLINK
4853b3d6264cSchristos 	ZERO(sa);
4854abb0f93cSkardel 	sa.nl_family = PF_NETLINK;
4855abb0f93cSkardel 	sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR
4856abb0f93cSkardel 		       | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_ROUTE
4857abb0f93cSkardel 		       | RTMGRP_IPV4_MROUTE | RTMGRP_IPV6_ROUTE
4858abb0f93cSkardel 		       | RTMGRP_IPV6_MROUTE;
4859abb0f93cSkardel 	if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
4860abb0f93cSkardel 		msyslog(LOG_ERR,
4861abb0f93cSkardel 			"bind failed on routing socket (%m) - using polled interface update");
4862abb0f93cSkardel 		return;
4863abb0f93cSkardel 	}
4864abb0f93cSkardel #endif
4865867deecaSroy #ifdef RO_MSGFILTER
4866867deecaSroy 	if (setsockopt(fd, PF_ROUTE, RO_MSGFILTER,
4867867deecaSroy 	    &msgfilter, sizeof(msgfilter)) == -1)
4868867deecaSroy 		msyslog(LOG_ERR, "RO_MSGFILTER: %m");
4869867deecaSroy #endif
4870b3d6264cSchristos 	make_socket_nonblocking(fd);
4871abb0f93cSkardel #if defined(HAVE_SIGNALED_IO)
4872abb0f93cSkardel 	init_socket_sig(fd);
4873abb0f93cSkardel #endif /* HAVE_SIGNALED_IO */
4874abb0f93cSkardel 
4875abb0f93cSkardel 	reader = new_asyncio_reader();
4876abb0f93cSkardel 
4877abb0f93cSkardel 	reader->fd = fd;
4878abb0f93cSkardel 	reader->receiver = process_routing_msgs;
4879abb0f93cSkardel 
4880abb0f93cSkardel 	add_asyncio_reader(reader, FD_TYPE_SOCKET);
4881abb0f93cSkardel 	msyslog(LOG_INFO,
4882abb0f93cSkardel 		"Listening on routing socket on fd #%d for interface updates",
4883abb0f93cSkardel 		fd);
4884abb0f93cSkardel }
4885abb0f93cSkardel #else
4886abb0f93cSkardel /* HAS_ROUTING_SOCKET not defined */
4887abb0f93cSkardel static void
4888abb0f93cSkardel init_async_notifications(void)
4889abb0f93cSkardel {
4890abb0f93cSkardel }
4891abb0f93cSkardel #endif
4892b3d6264cSchristos 
4893