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