1*e03b00c8Schristos /* $NetBSD: ntp_io.c,v 1.32 2022/10/09 21:41:03 christos Exp $ */
2abb0f93cSkardel
3abb0f93cSkardel /*
4abb0f93cSkardel * ntp_io.c - input/output routines for ntpd. The socket-opening code
5abb0f93cSkardel * was shamelessly stolen from ntpd.
6abb0f93cSkardel */
7abb0f93cSkardel
8abb0f93cSkardel #ifdef HAVE_CONFIG_H
9abb0f93cSkardel # include <config.h>
10abb0f93cSkardel #endif
11abb0f93cSkardel
12abb0f93cSkardel #include <stdio.h>
13abb0f93cSkardel #include <signal.h>
14ad131110Schristos #ifdef HAVE_FNMATCH_H
15ad131110Schristos # include <fnmatch.h>
16ad131110Schristos # if !defined(FNM_CASEFOLD) && defined(FNM_IGNORECASE)
17ad131110Schristos # define FNM_CASEFOLD FNM_IGNORECASE
18ad131110Schristos # endif
19ad131110Schristos #endif
20abb0f93cSkardel #ifdef HAVE_SYS_PARAM_H
21abb0f93cSkardel # include <sys/param.h>
22abb0f93cSkardel #endif
23abb0f93cSkardel #ifdef HAVE_SYS_IOCTL_H
24abb0f93cSkardel # include <sys/ioctl.h>
25abb0f93cSkardel #endif
26abb0f93cSkardel #ifdef HAVE_SYS_SOCKIO_H /* UXPV: SIOC* #defines (Frank Vance <fvance@waii.com>) */
27abb0f93cSkardel # include <sys/sockio.h>
28abb0f93cSkardel #endif
29abb0f93cSkardel #ifdef HAVE_SYS_UIO_H
30abb0f93cSkardel # include <sys/uio.h>
31abb0f93cSkardel #endif
32abb0f93cSkardel
33abb0f93cSkardel #include "ntp_machine.h"
34abb0f93cSkardel #include "ntpd.h"
35abb0f93cSkardel #include "ntp_io.h"
36abb0f93cSkardel #include "iosignal.h"
37abb0f93cSkardel #include "ntp_lists.h"
38abb0f93cSkardel #include "ntp_refclock.h"
39abb0f93cSkardel #include "ntp_stdlib.h"
40b3d6264cSchristos #include "ntp_worker.h"
41abb0f93cSkardel #include "ntp_request.h"
42abb0f93cSkardel #include "ntp_assert.h"
43b3d6264cSchristos #include "timevalops.h"
44b3d6264cSchristos #include "timespecops.h"
45abb0f93cSkardel #include "ntpd-opts.h"
46bd25f4c4Schristos #include "safecast.h"
47abb0f93cSkardel
48abb0f93cSkardel /* Don't include ISC's version of IPv6 variables and structures */
49abb0f93cSkardel #define ISC_IPV6_H 1
50abb0f93cSkardel #include <isc/mem.h>
51abb0f93cSkardel #include <isc/interfaceiter.h>
52abb0f93cSkardel #include <isc/netaddr.h>
53abb0f93cSkardel #include <isc/result.h>
54abb0f93cSkardel #include <isc/sockaddr.h>
55abb0f93cSkardel
56abb0f93cSkardel #ifdef SIM
57abb0f93cSkardel #include "ntpsim.h"
58abb0f93cSkardel #endif
59abb0f93cSkardel
60abb0f93cSkardel #ifdef HAS_ROUTING_SOCKET
61abb0f93cSkardel # include <net/route.h>
62abb0f93cSkardel # ifdef HAVE_RTNETLINK
63abb0f93cSkardel # include <linux/rtnetlink.h>
64abb0f93cSkardel # endif
65abb0f93cSkardel #endif
66abb0f93cSkardel
67abb0f93cSkardel /*
68abb0f93cSkardel * setsockopt does not always have the same arg declaration
69abb0f93cSkardel * across all platforms. If it's not defined we make it empty
70abb0f93cSkardel */
71abb0f93cSkardel
72abb0f93cSkardel #ifndef SETSOCKOPT_ARG_CAST
73abb0f93cSkardel #define SETSOCKOPT_ARG_CAST
74abb0f93cSkardel #endif
75abb0f93cSkardel
76abb0f93cSkardel extern int listen_to_virtual_ips;
77abb0f93cSkardel
784e3b3909Schristos #ifndef IPTOS_DSCP_EF
794e3b3909Schristos #define IPTOS_DSCP_EF 0xb8
804e3b3909Schristos #endif
814e3b3909Schristos int qos = IPTOS_DSCP_EF; /* QoS RFC3246 */
824e3b3909Schristos
834e3b3909Schristos #ifdef LEAP_SMEAR
844e3b3909Schristos /* TODO burnicki: This should be moved to ntp_timer.c, but if we do so
854e3b3909Schristos * we get a linker error. Since we're running out of time before the leap
864e3b3909Schristos * second occurs, we let it here where it just works.
874e3b3909Schristos */
884e3b3909Schristos int leap_smear_intv;
894e3b3909Schristos #endif
904e3b3909Schristos
91abb0f93cSkardel /*
92abb0f93cSkardel * NIC rule entry
93abb0f93cSkardel */
94abb0f93cSkardel typedef struct nic_rule_tag nic_rule;
95abb0f93cSkardel
96abb0f93cSkardel struct nic_rule_tag {
97abb0f93cSkardel nic_rule * next;
98abb0f93cSkardel nic_rule_action action;
99abb0f93cSkardel nic_rule_match match_type;
100abb0f93cSkardel char * if_name;
10145530cf1Skardel sockaddr_u addr;
102abb0f93cSkardel int prefixlen;
103abb0f93cSkardel };
104abb0f93cSkardel
105abb0f93cSkardel /*
106abb0f93cSkardel * NIC rule listhead. Entries are added at the head so that the first
107abb0f93cSkardel * match in the list is the last matching rule specified.
108abb0f93cSkardel */
109abb0f93cSkardel nic_rule *nic_rule_list;
110abb0f93cSkardel
111abb0f93cSkardel
112b3d6264cSchristos #if defined(SO_BINTIME) && defined(SCM_BINTIME) && defined(CMSG_FIRSTHDR)
113b3d6264cSchristos # define HAVE_PACKET_TIMESTAMP
114b3d6264cSchristos # define HAVE_BINTIME
115b3d6264cSchristos # ifdef BINTIME_CTLMSGBUF_SIZE
116b3d6264cSchristos # define CMSG_BUFSIZE BINTIME_CTLMSGBUF_SIZE
117b3d6264cSchristos # else
118b3d6264cSchristos # define CMSG_BUFSIZE 1536 /* moderate default */
119b3d6264cSchristos # endif
120b3d6264cSchristos #elif defined(SO_TIMESTAMPNS) && defined(SCM_TIMESTAMPNS) && defined(CMSG_FIRSTHDR)
121b3d6264cSchristos # define HAVE_PACKET_TIMESTAMP
122b3d6264cSchristos # define HAVE_TIMESTAMPNS
123b3d6264cSchristos # ifdef TIMESTAMPNS_CTLMSGBUF_SIZE
124b3d6264cSchristos # define CMSG_BUFSIZE TIMESTAMPNS_CTLMSGBUF_SIZE
125b3d6264cSchristos # else
126b3d6264cSchristos # define CMSG_BUFSIZE 1536 /* moderate default */
127b3d6264cSchristos # endif
128b3d6264cSchristos #elif defined(SO_TIMESTAMP) && defined(SCM_TIMESTAMP) && defined(CMSG_FIRSTHDR)
129b3d6264cSchristos # define HAVE_PACKET_TIMESTAMP
130abb0f93cSkardel # define HAVE_TIMESTAMP
131b3d6264cSchristos # ifdef TIMESTAMP_CTLMSGBUF_SIZE
132b3d6264cSchristos # define CMSG_BUFSIZE TIMESTAMP_CTLMSGBUF_SIZE
133b3d6264cSchristos # else
134b3d6264cSchristos # define CMSG_BUFSIZE 1536 /* moderate default */
135abb0f93cSkardel # endif
136abb0f93cSkardel #else
137abb0f93cSkardel /* fill in for old/other timestamp interfaces */
138abb0f93cSkardel #endif
139abb0f93cSkardel
140abb0f93cSkardel #if defined(SYS_WINNT)
141b3d6264cSchristos #include "win32_io.h"
142abb0f93cSkardel #include <isc/win32os.h>
143b3d6264cSchristos #endif
144abb0f93cSkardel
145abb0f93cSkardel /*
146abb0f93cSkardel * We do asynchronous input using the SIGIO facility. A number of
147abb0f93cSkardel * recvbuf buffers are preallocated for input. In the signal
148abb0f93cSkardel * handler we poll to see which sockets are ready and read the
149abb0f93cSkardel * packets from them into the recvbuf's along with a time stamp and
150abb0f93cSkardel * an indication of the source host and the interface it was received
151abb0f93cSkardel * through. This allows us to get as accurate receive time stamps
152abb0f93cSkardel * as possible independent of other processing going on.
153abb0f93cSkardel *
154abb0f93cSkardel * We watch the number of recvbufs available to the signal handler
155abb0f93cSkardel * and allocate more when this number drops below the low water
156abb0f93cSkardel * mark. If the signal handler should run out of buffers in the
157abb0f93cSkardel * interim it will drop incoming frames, the idea being that it is
158abb0f93cSkardel * better to drop a packet than to be inaccurate.
159abb0f93cSkardel */
160abb0f93cSkardel
161abb0f93cSkardel
162abb0f93cSkardel /*
163abb0f93cSkardel * Other statistics of possible interest
164abb0f93cSkardel */
165abb0f93cSkardel volatile u_long packets_dropped; /* total number of packets dropped on reception */
166abb0f93cSkardel volatile u_long packets_ignored; /* packets received on wild card interface */
167abb0f93cSkardel volatile u_long packets_received; /* total number of packets received */
168abb0f93cSkardel u_long packets_sent; /* total number of packets sent */
169abb0f93cSkardel u_long packets_notsent; /* total number of packets which couldn't be sent */
170abb0f93cSkardel
171abb0f93cSkardel volatile u_long handler_calls; /* number of calls to interrupt handler */
172abb0f93cSkardel volatile u_long handler_pkts; /* number of pkts received by handler */
173abb0f93cSkardel u_long io_timereset; /* time counters were reset */
174abb0f93cSkardel
175abb0f93cSkardel /*
176abb0f93cSkardel * Interface stuff
177abb0f93cSkardel */
17845530cf1Skardel endpt * any_interface; /* wildcard ipv4 interface */
17945530cf1Skardel endpt * any6_interface; /* wildcard ipv6 interface */
18045530cf1Skardel endpt * loopback_interface; /* loopback ipv4 interface */
181abb0f93cSkardel
1829034ec65Schristos static isc_boolean_t broadcast_client_enabled; /* is broadcast client enabled */
183b3d6264cSchristos u_int sys_ifnum; /* next .ifnum to assign */
184abb0f93cSkardel int ninterfaces; /* Total number of interfaces */
185abb0f93cSkardel
186abb0f93cSkardel int disable_dynamic_updates; /* scan interfaces once only */
187abb0f93cSkardel
188abb0f93cSkardel #ifdef REFCLOCK
189abb0f93cSkardel /*
190abb0f93cSkardel * Refclock stuff. We keep a chain of structures with data concerning
191abb0f93cSkardel * the guys we are doing I/O for.
192abb0f93cSkardel */
193abb0f93cSkardel static struct refclockio *refio;
194abb0f93cSkardel #endif /* REFCLOCK */
195abb0f93cSkardel
196abb0f93cSkardel /*
197abb0f93cSkardel * File descriptor masks etc. for call to select
198b3d6264cSchristos * Not needed for I/O Completion Ports or anything outside this file
199abb0f93cSkardel */
200b3d6264cSchristos static fd_set activefds;
201b3d6264cSchristos static int maxactivefd;
202b3d6264cSchristos
203abb0f93cSkardel /*
204abb0f93cSkardel * bit alternating value to detect verified interfaces during an update cycle
205abb0f93cSkardel */
206abb0f93cSkardel static u_short sys_interphase = 0;
207abb0f93cSkardel
20845530cf1Skardel static endpt * new_interface(endpt *);
20945530cf1Skardel static void add_interface(endpt *);
21045530cf1Skardel static int update_interfaces(u_short, interface_receiver_t,
21145530cf1Skardel void *);
21245530cf1Skardel static void remove_interface(endpt *);
21345530cf1Skardel static endpt * create_interface(u_short, endpt *);
214abb0f93cSkardel
21545530cf1Skardel static int is_wildcard_addr (const sockaddr_u *);
216abb0f93cSkardel
217abb0f93cSkardel /*
218abb0f93cSkardel * Multicast functions
219abb0f93cSkardel */
220abb0f93cSkardel static isc_boolean_t addr_ismulticast (sockaddr_u *);
22145530cf1Skardel static isc_boolean_t is_anycast (sockaddr_u *,
22245530cf1Skardel const char *);
22345530cf1Skardel
224abb0f93cSkardel /*
225abb0f93cSkardel * Not all platforms support multicast
226abb0f93cSkardel */
227abb0f93cSkardel #ifdef MCAST
22845530cf1Skardel static isc_boolean_t socket_multicast_enable (endpt *, sockaddr_u *);
22945530cf1Skardel static isc_boolean_t socket_multicast_disable(endpt *, sockaddr_u *);
230abb0f93cSkardel #endif
231abb0f93cSkardel
232abb0f93cSkardel #ifdef DEBUG
23345530cf1Skardel static void interface_dump (const endpt *);
23445530cf1Skardel static void sockaddr_dump (const sockaddr_u *);
235f40817b7Skardel static void print_interface (const endpt *, const char *, const char *);
236abb0f93cSkardel #define DPRINT_INTERFACE(level, args) do { if (debug >= (level)) { print_interface args; } } while (0)
237abb0f93cSkardel #else
238abb0f93cSkardel #define DPRINT_INTERFACE(level, args) do {} while (0)
239abb0f93cSkardel #endif
240abb0f93cSkardel
241abb0f93cSkardel typedef struct vsock vsock_t;
242abb0f93cSkardel enum desc_type { FD_TYPE_SOCKET, FD_TYPE_FILE };
243abb0f93cSkardel
244abb0f93cSkardel struct vsock {
245abb0f93cSkardel vsock_t * link;
246abb0f93cSkardel SOCKET fd;
247abb0f93cSkardel enum desc_type type;
248abb0f93cSkardel };
249abb0f93cSkardel
250abb0f93cSkardel vsock_t *fd_list;
251abb0f93cSkardel
252abb0f93cSkardel #if !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET)
253abb0f93cSkardel /*
254abb0f93cSkardel * async notification processing (e. g. routing sockets)
255abb0f93cSkardel */
256abb0f93cSkardel /*
257abb0f93cSkardel * support for receiving data on fd that is not a refclock or a socket
258abb0f93cSkardel * like e. g. routing sockets
259abb0f93cSkardel */
260abb0f93cSkardel struct asyncio_reader {
261abb0f93cSkardel struct asyncio_reader *link; /* the list this is being kept in */
262abb0f93cSkardel SOCKET fd; /* fd to be read */
263abb0f93cSkardel void *data; /* possibly local data */
264abb0f93cSkardel void (*receiver)(struct asyncio_reader *); /* input handler */
265abb0f93cSkardel };
266abb0f93cSkardel
267abb0f93cSkardel struct asyncio_reader *asyncio_reader_list;
268abb0f93cSkardel
269abb0f93cSkardel static void delete_asyncio_reader (struct asyncio_reader *);
270abb0f93cSkardel static struct asyncio_reader *new_asyncio_reader (void);
271abb0f93cSkardel static void add_asyncio_reader (struct asyncio_reader *, enum desc_type);
272abb0f93cSkardel static void remove_asyncio_reader (struct asyncio_reader *);
273abb0f93cSkardel
274abb0f93cSkardel #endif /* !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) */
275abb0f93cSkardel
276abb0f93cSkardel static void init_async_notifications (void);
277abb0f93cSkardel
27845530cf1Skardel static int addr_eqprefix (const sockaddr_u *, const sockaddr_u *,
27945530cf1Skardel int);
28045530cf1Skardel static int addr_samesubnet (const sockaddr_u *, const sockaddr_u *,
28145530cf1Skardel const sockaddr_u *, const sockaddr_u *);
282abb0f93cSkardel static int create_sockets (u_short);
28345530cf1Skardel static SOCKET open_socket (sockaddr_u *, int, int, endpt *);
284abb0f93cSkardel static void set_reuseaddr (int);
285abb0f93cSkardel static isc_boolean_t socket_broadcast_enable (struct interface *, SOCKET, sockaddr_u *);
286335f7552Schristos
287335f7552Schristos #if !defined(HAVE_IO_COMPLETION_PORT) && !defined(HAVE_SIGNALED_IO)
288335f7552Schristos static char * fdbits (int, const fd_set *);
289335f7552Schristos #endif
290ad131110Schristos #ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES
291abb0f93cSkardel static isc_boolean_t socket_broadcast_disable (struct interface *, sockaddr_u *);
292ad131110Schristos #endif
293abb0f93cSkardel
294abb0f93cSkardel typedef struct remaddr remaddr_t;
295abb0f93cSkardel
296abb0f93cSkardel struct remaddr {
297abb0f93cSkardel remaddr_t * link;
298abb0f93cSkardel sockaddr_u addr;
29945530cf1Skardel endpt * ep;
300abb0f93cSkardel };
301abb0f93cSkardel
302abb0f93cSkardel remaddr_t * remoteaddr_list;
30345530cf1Skardel endpt * ep_list; /* complete endpt list */
30445530cf1Skardel endpt * mc4_list; /* IPv4 mcast-capable unicast endpts */
30545530cf1Skardel endpt * mc6_list; /* IPv6 mcast-capable unicast endpts */
306abb0f93cSkardel
30745530cf1Skardel static endpt * wildipv4;
30845530cf1Skardel static endpt * wildipv6;
309abb0f93cSkardel
310b3d6264cSchristos #ifdef SYS_WINNT
311b3d6264cSchristos int accept_wildcard_if_for_winnt;
312b3d6264cSchristos #else
313b3d6264cSchristos const int accept_wildcard_if_for_winnt = FALSE;
314b3d6264cSchristos #endif
315b3d6264cSchristos
31645530cf1Skardel static void add_fd_to_list (SOCKET, enum desc_type);
31745530cf1Skardel static endpt * find_addr_in_list (sockaddr_u *);
31845530cf1Skardel static endpt * find_flagged_addr_in_list(sockaddr_u *, u_int32);
319abb0f93cSkardel static void delete_addr_from_list (sockaddr_u *);
32045530cf1Skardel static void delete_interface_from_list(endpt *);
321abb0f93cSkardel static void close_and_delete_fd_from_list(SOCKET);
32245530cf1Skardel static void add_addr_to_list (sockaddr_u *, endpt *);
323abb0f93cSkardel static void create_wildcards (u_short);
32445530cf1Skardel static endpt * findlocalinterface (sockaddr_u *, int, int);
32545530cf1Skardel static endpt * findclosestinterface (sockaddr_u *, int);
326abb0f93cSkardel #ifdef DEBUG
327abb0f93cSkardel static const char * action_text (nic_rule_action);
328abb0f93cSkardel #endif
32945530cf1Skardel static nic_rule_action interface_action(char *, sockaddr_u *, u_int32);
330abb0f93cSkardel static void convert_isc_if (isc_interface_t *,
33145530cf1Skardel endpt *, u_short);
33245530cf1Skardel static void calc_addr_distance(sockaddr_u *,
33345530cf1Skardel const sockaddr_u *,
33445530cf1Skardel const sockaddr_u *);
33545530cf1Skardel static int cmp_addr_distance(const sockaddr_u *,
33645530cf1Skardel const sockaddr_u *);
337abb0f93cSkardel
338abb0f93cSkardel /*
339abb0f93cSkardel * Routines to read the ntp packets
340abb0f93cSkardel */
341abb0f93cSkardel #if !defined(HAVE_IO_COMPLETION_PORT)
342abb0f93cSkardel static inline int read_network_packet (SOCKET, struct interface *, l_fp);
343b3d6264cSchristos static void ntpd_addremove_io_fd (int, int, int);
344335f7552Schristos static void input_handler_scan (const l_fp*, const fd_set*);
345335f7552Schristos static int/*BOOL*/ sanitize_fdset (int errc);
346b3d6264cSchristos #ifdef REFCLOCK
347abb0f93cSkardel static inline int read_refclock_packet (SOCKET, struct refclockio *, l_fp);
348abb0f93cSkardel #endif
349335f7552Schristos #ifdef HAVE_SIGNALED_IO
350335f7552Schristos static void input_handler (l_fp*);
351b3d6264cSchristos #endif
352335f7552Schristos #endif
353abb0f93cSkardel
354b3d6264cSchristos
355b3d6264cSchristos #ifndef HAVE_IO_COMPLETION_PORT
356abb0f93cSkardel void
maintain_activefds(int fd,int closing)357b3d6264cSchristos maintain_activefds(
358b3d6264cSchristos int fd,
359b3d6264cSchristos int closing
360abb0f93cSkardel )
361abb0f93cSkardel {
362b3d6264cSchristos int i;
363abb0f93cSkardel
364b3d6264cSchristos if (fd < 0 || fd >= FD_SETSIZE) {
365abb0f93cSkardel msyslog(LOG_ERR,
366b3d6264cSchristos "Too many sockets in use, FD_SETSIZE %d exceeded by fd %d",
367b3d6264cSchristos FD_SETSIZE, fd);
368b3d6264cSchristos exit(1);
369abb0f93cSkardel }
370abb0f93cSkardel
371b3d6264cSchristos if (!closing) {
372b3d6264cSchristos FD_SET(fd, &activefds);
373b3d6264cSchristos maxactivefd = max(fd, maxactivefd);
374abb0f93cSkardel } else {
375b3d6264cSchristos FD_CLR(fd, &activefds);
376b3d6264cSchristos if (maxactivefd && fd == maxactivefd) {
377b3d6264cSchristos for (i = maxactivefd - 1; i >= 0; i--)
378b3d6264cSchristos if (FD_ISSET(i, &activefds)) {
379b3d6264cSchristos maxactivefd = i;
380b3d6264cSchristos break;
381abb0f93cSkardel }
38209f14f80Schristos INSIST(fd != maxactivefd);
383abb0f93cSkardel }
384b3d6264cSchristos }
385b3d6264cSchristos }
386b3d6264cSchristos #endif /* !HAVE_IO_COMPLETION_PORT */
387b3d6264cSchristos
388abb0f93cSkardel
389abb0f93cSkardel #ifdef DEBUG_TIMING
390abb0f93cSkardel /*
391abb0f93cSkardel * collect timing information for various processing
392b3d6264cSchristos * paths. currently we only pass them on to the file
393abb0f93cSkardel * for later processing. this could also do histogram
394abb0f93cSkardel * based analysis in other to reduce the load (and skew)
395abb0f93cSkardel * dur to the file output
396abb0f93cSkardel */
397abb0f93cSkardel void
collect_timing(struct recvbuf * rb,const char * tag,int count,l_fp * dts)398abb0f93cSkardel collect_timing(struct recvbuf *rb, const char *tag, int count, l_fp *dts)
399abb0f93cSkardel {
400abb0f93cSkardel char buf[256];
401abb0f93cSkardel
402abb0f93cSkardel snprintf(buf, sizeof(buf), "%s %d %s %s",
403abb0f93cSkardel (rb != NULL)
404abb0f93cSkardel ? ((rb->dstadr != NULL)
405abb0f93cSkardel ? stoa(&rb->recv_srcadr)
406abb0f93cSkardel : "-REFCLOCK-")
407abb0f93cSkardel : "-",
408abb0f93cSkardel count, lfptoa(dts, 9), tag);
409abb0f93cSkardel record_timing_stats(buf);
410abb0f93cSkardel }
411abb0f93cSkardel #endif
412abb0f93cSkardel
413abb0f93cSkardel /*
414abb0f93cSkardel * About dynamic interfaces, sockets, reception and more...
415abb0f93cSkardel *
416abb0f93cSkardel * the code solves following tasks:
417abb0f93cSkardel *
418abb0f93cSkardel * - keep a current list of active interfaces in order
419abb0f93cSkardel * to bind to to the interface address on NTP_PORT so that
420abb0f93cSkardel * all wild and specific bindings for NTP_PORT are taken by ntpd
421abb0f93cSkardel * to avoid other daemons messing with the time or sockets.
422abb0f93cSkardel * - all interfaces keep a list of peers that are referencing
423abb0f93cSkardel * the interface in order to quickly re-assign the peers to
424abb0f93cSkardel * new interface in case an interface is deleted (=> gone from system or
425abb0f93cSkardel * down)
426abb0f93cSkardel * - have a preconfigured socket ready with the right local address
427abb0f93cSkardel * for transmission and reception
428abb0f93cSkardel * - have an address list for all destination addresses used within ntpd
429abb0f93cSkardel * to find the "right" preconfigured socket.
430abb0f93cSkardel * - facilitate updating the internal interface list with respect to
431abb0f93cSkardel * the current kernel state
432abb0f93cSkardel *
433abb0f93cSkardel * special issues:
434abb0f93cSkardel *
435abb0f93cSkardel * - mapping of multicast addresses to the interface affected is not always
436abb0f93cSkardel * one to one - especially on hosts with multiple interfaces
437abb0f93cSkardel * the code here currently allocates a separate interface entry for those
438abb0f93cSkardel * multicast addresses
439abb0f93cSkardel * iff it is able to bind to a *new* socket with the multicast address (flags |= MCASTIF)
440abb0f93cSkardel * in case of failure the multicast address is bound to an existing interface.
441abb0f93cSkardel * - on some systems it is perfectly legal to assign the same address to
442abb0f93cSkardel * multiple interfaces. Therefore this code does not keep a list of interfaces
443abb0f93cSkardel * but a list of interfaces that represent a unique address as determined by the kernel
444abb0f93cSkardel * by the procedure in findlocalinterface. Thus it is perfectly legal to see only
445abb0f93cSkardel * one representative of a group of real interfaces if they share the same address.
446abb0f93cSkardel *
447abb0f93cSkardel * Frank Kardel 20050910
448abb0f93cSkardel */
449abb0f93cSkardel
450abb0f93cSkardel /*
451b3d6264cSchristos * init_io - initialize I/O module.
452abb0f93cSkardel */
453abb0f93cSkardel void
init_io(void)454abb0f93cSkardel init_io(void)
455abb0f93cSkardel {
456b3d6264cSchristos /* Init buffer free list and stat counters */
457abb0f93cSkardel init_recvbuff(RECV_INIT);
458dd91765eSroy #ifdef SO_RERROR
459dd91765eSroy /* route(4) overflow can be observed */
460dd91765eSroy interface_interval = 0;
461dd91765eSroy #else
462b3d6264cSchristos /* update interface every 5 minutes as default */
463b3d6264cSchristos interface_interval = 300;
464dd91765eSroy #endif
465b3d6264cSchristos
466b3d6264cSchristos #ifdef WORK_PIPE
467b3d6264cSchristos addremove_io_fd = &ntpd_addremove_io_fd;
468b3d6264cSchristos #endif
469abb0f93cSkardel
470335f7552Schristos #if defined(SYS_WINNT)
471abb0f93cSkardel init_io_completion_port();
472335f7552Schristos #elif defined(HAVE_SIGNALED_IO)
473b3d6264cSchristos (void) set_signal(input_handler);
474abb0f93cSkardel #endif
475abb0f93cSkardel }
476abb0f93cSkardel
477abb0f93cSkardel
478b3d6264cSchristos static void
ntpd_addremove_io_fd(int fd,int is_pipe,int remove_it)479b3d6264cSchristos ntpd_addremove_io_fd(
480b3d6264cSchristos int fd,
481b3d6264cSchristos int is_pipe,
482b3d6264cSchristos int remove_it
483b3d6264cSchristos )
484b3d6264cSchristos {
485b3d6264cSchristos UNUSED_ARG(is_pipe);
486b3d6264cSchristos
487b3d6264cSchristos #ifdef HAVE_SIGNALED_IO
488335f7552Schristos if (!remove_it)
489b3d6264cSchristos init_socket_sig(fd);
490b3d6264cSchristos #endif /* not HAVE_SIGNALED_IO */
491b3d6264cSchristos
492b3d6264cSchristos maintain_activefds(fd, remove_it);
493b3d6264cSchristos }
494b3d6264cSchristos
495b3d6264cSchristos
496abb0f93cSkardel /*
497abb0f93cSkardel * io_open_sockets - call socket creation routine
498abb0f93cSkardel */
499abb0f93cSkardel void
io_open_sockets(void)500abb0f93cSkardel io_open_sockets(void)
501abb0f93cSkardel {
502abb0f93cSkardel static int already_opened;
503abb0f93cSkardel
504abb0f93cSkardel if (already_opened || HAVE_OPT( SAVECONFIGQUIT ))
505abb0f93cSkardel return;
506abb0f93cSkardel
507abb0f93cSkardel already_opened = 1;
508abb0f93cSkardel
509abb0f93cSkardel /*
510abb0f93cSkardel * Create the sockets
511abb0f93cSkardel */
512abb0f93cSkardel BLOCKIO();
513abb0f93cSkardel create_sockets(NTP_PORT);
514abb0f93cSkardel UNBLOCKIO();
515abb0f93cSkardel
516abb0f93cSkardel init_async_notifications();
517abb0f93cSkardel
518abb0f93cSkardel DPRINTF(3, ("io_open_sockets: maxactivefd %d\n", maxactivefd));
519abb0f93cSkardel }
520abb0f93cSkardel
521abb0f93cSkardel
522abb0f93cSkardel #ifdef DEBUG
523abb0f93cSkardel /*
524abb0f93cSkardel * function to dump the contents of the interface structure
525abb0f93cSkardel * for debugging use only.
5261c24ec91Schristos * We face a dilemma here -- sockets are FDs under POSIX and
5271c24ec91Schristos * actually HANDLES under Windows. So we use '%lld' as format
5281c24ec91Schristos * and cast the value to 'long long'; this should not hurt
5291c24ec91Schristos * with UNIX-like systems and does not truncate values on Win64.
530abb0f93cSkardel */
531abb0f93cSkardel void
interface_dump(const endpt * itf)53245530cf1Skardel interface_dump(const endpt *itf)
533abb0f93cSkardel {
534abb0f93cSkardel printf("Dumping interface: %p\n", itf);
5351c24ec91Schristos printf("fd = %lld\n", (long long)itf->fd);
5361c24ec91Schristos printf("bfd = %lld\n", (long long)itf->bfd);
537abb0f93cSkardel printf("sin = %s,\n", stoa(&itf->sin));
538abb0f93cSkardel sockaddr_dump(&itf->sin);
539abb0f93cSkardel printf("bcast = %s,\n", stoa(&itf->bcast));
540abb0f93cSkardel sockaddr_dump(&itf->bcast);
541abb0f93cSkardel printf("mask = %s,\n", stoa(&itf->mask));
542abb0f93cSkardel sockaddr_dump(&itf->mask);
543abb0f93cSkardel printf("name = %s\n", itf->name);
544abb0f93cSkardel printf("flags = 0x%08x\n", itf->flags);
545abb0f93cSkardel printf("last_ttl = %d\n", itf->last_ttl);
546abb0f93cSkardel printf("addr_refid = %08x\n", itf->addr_refid);
547abb0f93cSkardel printf("num_mcast = %d\n", itf->num_mcast);
548abb0f93cSkardel printf("received = %ld\n", itf->received);
549abb0f93cSkardel printf("sent = %ld\n", itf->sent);
550abb0f93cSkardel printf("notsent = %ld\n", itf->notsent);
55145530cf1Skardel printf("ifindex = %u\n", itf->ifindex);
552abb0f93cSkardel printf("peercnt = %u\n", itf->peercnt);
553abb0f93cSkardel printf("phase = %u\n", itf->phase);
554abb0f93cSkardel }
555abb0f93cSkardel
556abb0f93cSkardel /*
557abb0f93cSkardel * sockaddr_dump - hex dump the start of a sockaddr_u
558abb0f93cSkardel */
559abb0f93cSkardel static void
sockaddr_dump(const sockaddr_u * psau)56045530cf1Skardel sockaddr_dump(const sockaddr_u *psau)
561abb0f93cSkardel {
562b3d6264cSchristos /* Limit the size of the sockaddr_in6 hex dump */
56345530cf1Skardel const int maxsize = min(32, sizeof(psau->sa6));
56445530cf1Skardel const u_char * cp;
565abb0f93cSkardel int i;
566abb0f93cSkardel
567b3d6264cSchristos /* XXX: Should we limit maxsize based on psau->saX.sin_family? */
568b3d6264cSchristos cp = (const void *)&psau->sa6;
569abb0f93cSkardel
57045530cf1Skardel for(i = 0; i < maxsize; i++) {
571abb0f93cSkardel printf("%02x", *cp++);
572abb0f93cSkardel if (!((i + 1) % 4))
573abb0f93cSkardel printf(" ");
574abb0f93cSkardel }
575abb0f93cSkardel printf("\n");
576abb0f93cSkardel }
577abb0f93cSkardel
578abb0f93cSkardel /*
579abb0f93cSkardel * print_interface - helper to output debug information
580abb0f93cSkardel */
581abb0f93cSkardel static void
print_interface(const endpt * iface,const char * pfx,const char * sfx)582f40817b7Skardel print_interface(const endpt *iface, const char *pfx, const char *sfx)
583abb0f93cSkardel {
5841c24ec91Schristos printf("%sinterface #%d: fd=%lld, bfd=%lld, name=%s, flags=0x%x, ifindex=%u, sin=%s",
585abb0f93cSkardel pfx,
586abb0f93cSkardel iface->ifnum,
5871c24ec91Schristos (long long)iface->fd,
5881c24ec91Schristos (long long)iface->bfd,
589abb0f93cSkardel iface->name,
590abb0f93cSkardel iface->flags,
59145530cf1Skardel iface->ifindex,
592abb0f93cSkardel stoa(&iface->sin));
593abb0f93cSkardel if (AF_INET == iface->family) {
594abb0f93cSkardel if (iface->flags & INT_BROADCAST)
595abb0f93cSkardel printf(", bcast=%s", stoa(&iface->bcast));
596abb0f93cSkardel printf(", mask=%s", stoa(&iface->mask));
597abb0f93cSkardel }
598abb0f93cSkardel printf(", %s:%s",
599abb0f93cSkardel (iface->ignore_packets)
600abb0f93cSkardel ? "Disabled"
601abb0f93cSkardel : "Enabled",
602abb0f93cSkardel sfx);
603abb0f93cSkardel if (debug > 4) /* in-depth debugging only */
604abb0f93cSkardel interface_dump(iface);
605abb0f93cSkardel }
606abb0f93cSkardel #endif
607abb0f93cSkardel
608abb0f93cSkardel #if !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET)
609abb0f93cSkardel /*
610abb0f93cSkardel * create an asyncio_reader structure
611abb0f93cSkardel */
612abb0f93cSkardel static struct asyncio_reader *
new_asyncio_reader(void)613abb0f93cSkardel new_asyncio_reader(void)
614abb0f93cSkardel {
615abb0f93cSkardel struct asyncio_reader *reader;
616abb0f93cSkardel
617b3d6264cSchristos reader = emalloc_zero(sizeof(*reader));
618abb0f93cSkardel reader->fd = INVALID_SOCKET;
619b3d6264cSchristos
620abb0f93cSkardel return reader;
621abb0f93cSkardel }
622abb0f93cSkardel
623abb0f93cSkardel /*
624abb0f93cSkardel * delete a reader
625abb0f93cSkardel */
626abb0f93cSkardel static void
delete_asyncio_reader(struct asyncio_reader * reader)627abb0f93cSkardel delete_asyncio_reader(
628abb0f93cSkardel struct asyncio_reader *reader
629abb0f93cSkardel )
630abb0f93cSkardel {
631abb0f93cSkardel free(reader);
632abb0f93cSkardel }
633abb0f93cSkardel
634abb0f93cSkardel /*
635abb0f93cSkardel * add asynchio_reader
636abb0f93cSkardel */
637abb0f93cSkardel static void
add_asyncio_reader(struct asyncio_reader * reader,enum desc_type type)638abb0f93cSkardel add_asyncio_reader(
639abb0f93cSkardel struct asyncio_reader * reader,
640abb0f93cSkardel enum desc_type type)
641abb0f93cSkardel {
642abb0f93cSkardel LINK_SLIST(asyncio_reader_list, reader, link);
643abb0f93cSkardel add_fd_to_list(reader->fd, type);
644abb0f93cSkardel }
645abb0f93cSkardel
646abb0f93cSkardel /*
647abb0f93cSkardel * remove asynchio_reader
648abb0f93cSkardel */
649abb0f93cSkardel static void
remove_asyncio_reader(struct asyncio_reader * reader)650abb0f93cSkardel remove_asyncio_reader(
651abb0f93cSkardel struct asyncio_reader *reader
652abb0f93cSkardel )
653abb0f93cSkardel {
654abb0f93cSkardel struct asyncio_reader *unlinked;
655abb0f93cSkardel
656abb0f93cSkardel UNLINK_SLIST(unlinked, asyncio_reader_list, reader, link,
657abb0f93cSkardel struct asyncio_reader);
658abb0f93cSkardel
659abb0f93cSkardel if (reader->fd != INVALID_SOCKET)
660abb0f93cSkardel close_and_delete_fd_from_list(reader->fd);
661abb0f93cSkardel
662abb0f93cSkardel reader->fd = INVALID_SOCKET;
663abb0f93cSkardel }
664abb0f93cSkardel #endif /* !defined(HAVE_IO_COMPLETION_PORT) && defined(HAS_ROUTING_SOCKET) */
665abb0f93cSkardel
66645530cf1Skardel
66745530cf1Skardel /* compare two sockaddr prefixes */
66845530cf1Skardel static int
addr_eqprefix(const sockaddr_u * a,const sockaddr_u * b,int prefixlen)66945530cf1Skardel addr_eqprefix(
67045530cf1Skardel const sockaddr_u * a,
67145530cf1Skardel const sockaddr_u * b,
67245530cf1Skardel int prefixlen
67345530cf1Skardel )
67445530cf1Skardel {
67545530cf1Skardel isc_netaddr_t isc_a;
67645530cf1Skardel isc_netaddr_t isc_b;
67745530cf1Skardel isc_sockaddr_t isc_sa;
67845530cf1Skardel
679b3d6264cSchristos ZERO(isc_sa);
680b3d6264cSchristos memcpy(&isc_sa.type, a, min(sizeof(isc_sa.type), sizeof(*a)));
68145530cf1Skardel isc_netaddr_fromsockaddr(&isc_a, &isc_sa);
68245530cf1Skardel
683b3d6264cSchristos ZERO(isc_sa);
684b3d6264cSchristos memcpy(&isc_sa.type, b, min(sizeof(isc_sa.type), sizeof(*b)));
68545530cf1Skardel isc_netaddr_fromsockaddr(&isc_b, &isc_sa);
68645530cf1Skardel
68745530cf1Skardel return (int)isc_netaddr_eqprefix(&isc_a, &isc_b,
68845530cf1Skardel (u_int)prefixlen);
68945530cf1Skardel }
69045530cf1Skardel
69145530cf1Skardel
69245530cf1Skardel static int
addr_samesubnet(const sockaddr_u * a,const sockaddr_u * a_mask,const sockaddr_u * b,const sockaddr_u * b_mask)69345530cf1Skardel addr_samesubnet(
69445530cf1Skardel const sockaddr_u * a,
69545530cf1Skardel const sockaddr_u * a_mask,
69645530cf1Skardel const sockaddr_u * b,
69745530cf1Skardel const sockaddr_u * b_mask
69845530cf1Skardel )
69945530cf1Skardel {
70045530cf1Skardel const u_int32 * pa;
70145530cf1Skardel const u_int32 * pa_limit;
70245530cf1Skardel const u_int32 * pb;
70345530cf1Skardel const u_int32 * pm;
70445530cf1Skardel size_t loops;
70545530cf1Skardel
70609f14f80Schristos REQUIRE(AF(a) == AF(a_mask));
70709f14f80Schristos REQUIRE(AF(b) == AF(b_mask));
70845530cf1Skardel /*
70945530cf1Skardel * With address and mask families verified to match, comparing
71045530cf1Skardel * the masks also validates the address's families match.
71145530cf1Skardel */
71245530cf1Skardel if (!SOCK_EQ(a_mask, b_mask))
71345530cf1Skardel return FALSE;
71445530cf1Skardel
71545530cf1Skardel if (IS_IPV6(a)) {
71645530cf1Skardel loops = sizeof(NSRCADR6(a)) / sizeof(*pa);
71745530cf1Skardel pa = (const void *)&NSRCADR6(a);
71845530cf1Skardel pb = (const void *)&NSRCADR6(b);
71945530cf1Skardel pm = (const void *)&NSRCADR6(a_mask);
72045530cf1Skardel } else {
72145530cf1Skardel loops = sizeof(NSRCADR(a)) / sizeof(*pa);
72245530cf1Skardel pa = (const void *)&NSRCADR(a);
72345530cf1Skardel pb = (const void *)&NSRCADR(b);
72445530cf1Skardel pm = (const void *)&NSRCADR(a_mask);
72545530cf1Skardel }
72645530cf1Skardel for (pa_limit = pa + loops; pa < pa_limit; pa++, pb++, pm++)
72745530cf1Skardel if ((*pa & *pm) != (*pb & *pm))
72845530cf1Skardel return FALSE;
72945530cf1Skardel
73045530cf1Skardel return TRUE;
73145530cf1Skardel }
73245530cf1Skardel
73345530cf1Skardel
734abb0f93cSkardel /*
735abb0f93cSkardel * interface list enumerator - visitor pattern
736abb0f93cSkardel */
737abb0f93cSkardel void
interface_enumerate(interface_receiver_t receiver,void * data)738abb0f93cSkardel interface_enumerate(
739abb0f93cSkardel interface_receiver_t receiver,
740abb0f93cSkardel void * data
741abb0f93cSkardel )
742abb0f93cSkardel {
743abb0f93cSkardel interface_info_t ifi;
744abb0f93cSkardel
745abb0f93cSkardel ifi.action = IFS_EXISTS;
74645530cf1Skardel for (ifi.ep = ep_list; ifi.ep != NULL; ifi.ep = ifi.ep->elink)
747abb0f93cSkardel (*receiver)(data, &ifi);
748abb0f93cSkardel }
749abb0f93cSkardel
750abb0f93cSkardel /*
751abb0f93cSkardel * do standard initialization of interface structure
752abb0f93cSkardel */
753abb0f93cSkardel static void
init_interface(endpt * ep)754abb0f93cSkardel init_interface(
75545530cf1Skardel endpt *ep
756abb0f93cSkardel )
757abb0f93cSkardel {
758b3d6264cSchristos ZERO(*ep);
75945530cf1Skardel ep->fd = INVALID_SOCKET;
76045530cf1Skardel ep->bfd = INVALID_SOCKET;
76145530cf1Skardel ep->phase = sys_interphase;
762abb0f93cSkardel }
763abb0f93cSkardel
764abb0f93cSkardel
765abb0f93cSkardel /*
766abb0f93cSkardel * create new interface structure initialize from
767abb0f93cSkardel * template structure or via standard initialization
768abb0f93cSkardel * function
769abb0f93cSkardel */
770abb0f93cSkardel static struct interface *
new_interface(struct interface * interface)771abb0f93cSkardel new_interface(
772abb0f93cSkardel struct interface *interface
773abb0f93cSkardel )
774abb0f93cSkardel {
775abb0f93cSkardel struct interface * iface;
776abb0f93cSkardel
777abb0f93cSkardel iface = emalloc(sizeof(*iface));
778abb0f93cSkardel
779abb0f93cSkardel if (NULL == interface)
780abb0f93cSkardel init_interface(iface);
781abb0f93cSkardel else /* use the template */
782abb0f93cSkardel memcpy(iface, interface, sizeof(*iface));
783abb0f93cSkardel
784abb0f93cSkardel /* count every new instance of an interface in the system */
785abb0f93cSkardel iface->ifnum = sys_ifnum++;
786abb0f93cSkardel iface->starttime = current_time;
787abb0f93cSkardel
788335f7552Schristos # ifdef HAVE_IO_COMPLETION_PORT
789335f7552Schristos if (!io_completion_port_add_interface(iface)) {
790335f7552Schristos msyslog(LOG_EMERG, "cannot register interface with IO engine -- will exit now");
791335f7552Schristos exit(1);
792335f7552Schristos }
793335f7552Schristos # endif
794abb0f93cSkardel return iface;
795abb0f93cSkardel }
796abb0f93cSkardel
797abb0f93cSkardel
798abb0f93cSkardel /*
799abb0f93cSkardel * return interface storage into free memory pool
800abb0f93cSkardel */
801335f7552Schristos static void
delete_interface(endpt * ep)802abb0f93cSkardel delete_interface(
80345530cf1Skardel endpt *ep
804abb0f93cSkardel )
805abb0f93cSkardel {
806335f7552Schristos # ifdef HAVE_IO_COMPLETION_PORT
807335f7552Schristos io_completion_port_remove_interface(ep);
808335f7552Schristos # endif
80945530cf1Skardel free(ep);
810abb0f93cSkardel }
811abb0f93cSkardel
812abb0f93cSkardel
813abb0f93cSkardel /*
814abb0f93cSkardel * link interface into list of known interfaces
815abb0f93cSkardel */
816abb0f93cSkardel static void
add_interface(endpt * ep)817abb0f93cSkardel add_interface(
81845530cf1Skardel endpt * ep
819abb0f93cSkardel )
820abb0f93cSkardel {
82145530cf1Skardel endpt ** pmclisthead;
82245530cf1Skardel endpt * scan;
82345530cf1Skardel endpt * scan_next;
82445530cf1Skardel endpt * unlinked;
82545530cf1Skardel sockaddr_u * addr;
82645530cf1Skardel int ep_local;
82745530cf1Skardel int scan_local;
82845530cf1Skardel int same_subnet;
82945530cf1Skardel int ep_univ_iid; /* iface ID from MAC address */
83045530cf1Skardel int scan_univ_iid; /* see RFC 4291 */
83145530cf1Skardel int ep_privacy; /* random local iface ID */
83245530cf1Skardel int scan_privacy; /* see RFC 4941 */
83345530cf1Skardel int rc;
83445530cf1Skardel
835b3d6264cSchristos /* Calculate the refid */
83645530cf1Skardel ep->addr_refid = addr2refid(&ep->sin);
837b3d6264cSchristos /* link at tail so ntpdc -c ifstats index increases each row */
838b3d6264cSchristos LINK_TAIL_SLIST(ep_list, ep, elink, endpt);
839abb0f93cSkardel ninterfaces++;
84045530cf1Skardel #ifdef MCAST
84145530cf1Skardel /* the rest is for enabled multicast-capable addresses only */
84245530cf1Skardel if (ep->ignore_packets || !(INT_MULTICAST & ep->flags) ||
84345530cf1Skardel INT_LOOPBACK & ep->flags)
84445530cf1Skardel return;
84545530cf1Skardel # ifndef INCLUDE_IPV6_MULTICAST_SUPPORT
84645530cf1Skardel if (AF_INET6 == ep->family)
84745530cf1Skardel return;
84845530cf1Skardel # endif
84945530cf1Skardel pmclisthead = (AF_INET == ep->family)
85045530cf1Skardel ? &mc4_list
85145530cf1Skardel : &mc6_list;
85245530cf1Skardel
85345530cf1Skardel if (AF_INET6 == ep->family) {
85445530cf1Skardel ep_local =
85545530cf1Skardel IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(&ep->sin)) ||
85645530cf1Skardel IN6_IS_ADDR_SITELOCAL(PSOCK_ADDR6(&ep->sin));
85745530cf1Skardel ep_univ_iid = IS_IID_UNIV(&ep->sin);
85845530cf1Skardel ep_privacy = !!(INT_PRIVACY & ep->flags);
85945530cf1Skardel } else {
86045530cf1Skardel ep_local = FALSE;
86145530cf1Skardel ep_univ_iid = FALSE;
86245530cf1Skardel ep_privacy = FALSE;
86345530cf1Skardel }
86445530cf1Skardel DPRINTF(4, ("add_interface mcast-capable %s%s%s%s\n",
86545530cf1Skardel stoa(&ep->sin),
86645530cf1Skardel (ep_local) ? " link/scope-local" : "",
86745530cf1Skardel (ep_univ_iid) ? " univ-IID" : "",
86845530cf1Skardel (ep_privacy) ? " privacy" : ""));
86945530cf1Skardel /*
87045530cf1Skardel * If we have multiple local addresses on the same network
87145530cf1Skardel * interface, and some are link- or site-local, do not multicast
87245530cf1Skardel * out from the link-/site-local addresses by default, to avoid
87345530cf1Skardel * duplicate manycastclient associations between v6 peers using
87445530cf1Skardel * link-local and global addresses. link-local can still be
87545530cf1Skardel * chosen using "nic ignore myv6globalprefix::/64".
87645530cf1Skardel * Similarly, if we have multiple global addresses from the same
87745530cf1Skardel * prefix on the same network interface, multicast from one,
87845530cf1Skardel * preferring EUI-64, then static, then least RFC 4941 privacy
87945530cf1Skardel * addresses.
88045530cf1Skardel */
88145530cf1Skardel for (scan = *pmclisthead; scan != NULL; scan = scan_next) {
88245530cf1Skardel scan_next = scan->mclink;
88345530cf1Skardel if (ep->family != scan->family)
88445530cf1Skardel continue;
88545530cf1Skardel if (strcmp(ep->name, scan->name))
88645530cf1Skardel continue;
88745530cf1Skardel same_subnet = addr_samesubnet(&ep->sin, &ep->mask,
88845530cf1Skardel &scan->sin, &scan->mask);
88945530cf1Skardel if (AF_INET6 == ep->family) {
89045530cf1Skardel addr = &scan->sin;
89145530cf1Skardel scan_local =
89245530cf1Skardel IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(addr)) ||
89345530cf1Skardel IN6_IS_ADDR_SITELOCAL(PSOCK_ADDR6(addr));
89445530cf1Skardel scan_univ_iid = IS_IID_UNIV(addr);
89545530cf1Skardel scan_privacy = !!(INT_PRIVACY & scan->flags);
89645530cf1Skardel } else {
89745530cf1Skardel scan_local = FALSE;
89845530cf1Skardel scan_univ_iid = FALSE;
89945530cf1Skardel scan_privacy = FALSE;
90045530cf1Skardel }
90145530cf1Skardel DPRINTF(4, ("add_interface mcast-capable scan %s%s%s%s\n",
90245530cf1Skardel stoa(&scan->sin),
90345530cf1Skardel (scan_local) ? " link/scope-local" : "",
90445530cf1Skardel (scan_univ_iid) ? " univ-IID" : "",
90545530cf1Skardel (scan_privacy) ? " privacy" : ""));
90645530cf1Skardel if ((ep_local && !scan_local) || (same_subnet &&
90745530cf1Skardel ((ep_privacy && !scan_privacy) ||
90845530cf1Skardel (!ep_univ_iid && scan_univ_iid)))) {
90945530cf1Skardel DPRINTF(4, ("did not add %s to %s of IPv6 multicast-capable list which already has %s\n",
91045530cf1Skardel stoa(&ep->sin),
91145530cf1Skardel (ep_local)
91245530cf1Skardel ? "tail"
91345530cf1Skardel : "head",
91445530cf1Skardel stoa(&scan->sin)));
91545530cf1Skardel return;
91645530cf1Skardel }
91745530cf1Skardel if ((scan_local && !ep_local) || (same_subnet &&
91845530cf1Skardel ((scan_privacy && !ep_privacy) ||
91945530cf1Skardel (!scan_univ_iid && ep_univ_iid)))) {
92045530cf1Skardel UNLINK_SLIST(unlinked, *pmclisthead,
92145530cf1Skardel scan, mclink, endpt);
92245530cf1Skardel DPRINTF(4, ("%s %s from IPv6 multicast-capable list to add %s\n",
92345530cf1Skardel (unlinked != scan)
92445530cf1Skardel ? "Failed to remove"
92545530cf1Skardel : "removed",
92645530cf1Skardel stoa(&scan->sin), stoa(&ep->sin)));
92745530cf1Skardel }
92845530cf1Skardel }
92945530cf1Skardel /*
93045530cf1Skardel * Add link/site local at the tail of the multicast-
93145530cf1Skardel * capable unicast interfaces list, so that ntpd will
93245530cf1Skardel * send from global addresses before link-/site-local
93345530cf1Skardel * ones.
93445530cf1Skardel */
93545530cf1Skardel if (ep_local)
93645530cf1Skardel LINK_TAIL_SLIST(*pmclisthead, ep, mclink, endpt);
93745530cf1Skardel else
93845530cf1Skardel LINK_SLIST(*pmclisthead, ep, mclink);
93945530cf1Skardel DPRINTF(4, ("added %s to %s of IPv%s multicast-capable unicast local address list\n",
94045530cf1Skardel stoa(&ep->sin),
94145530cf1Skardel (ep_local)
94245530cf1Skardel ? "tail"
94345530cf1Skardel : "head",
94445530cf1Skardel (AF_INET == ep->family)
94545530cf1Skardel ? "4"
94645530cf1Skardel : "6"));
94745530cf1Skardel
948b3d6264cSchristos if (INVALID_SOCKET == ep->fd)
949b3d6264cSchristos return;
950b3d6264cSchristos
95145530cf1Skardel /*
95245530cf1Skardel * select the local address from which to send to multicast.
95345530cf1Skardel */
95445530cf1Skardel switch (AF(&ep->sin)) {
955b3d6264cSchristos
95645530cf1Skardel case AF_INET :
95745530cf1Skardel rc = setsockopt(ep->fd, IPPROTO_IP,
95845530cf1Skardel IP_MULTICAST_IF,
95945530cf1Skardel (void *)&NSRCADR(&ep->sin),
96045530cf1Skardel sizeof(NSRCADR(&ep->sin)));
96145530cf1Skardel if (rc)
96245530cf1Skardel msyslog(LOG_ERR,
96345530cf1Skardel "setsockopt IP_MULTICAST_IF %s fails: %m",
96445530cf1Skardel stoa(&ep->sin));
96545530cf1Skardel break;
966b3d6264cSchristos
96745530cf1Skardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
96845530cf1Skardel case AF_INET6 :
96945530cf1Skardel rc = setsockopt(ep->fd, IPPROTO_IPV6,
97045530cf1Skardel IPV6_MULTICAST_IF,
97145530cf1Skardel (void *)&ep->ifindex,
97245530cf1Skardel sizeof(ep->ifindex));
973b3d6264cSchristos /* do not complain if bound addr scope is ifindex */
974b3d6264cSchristos if (rc && ep->ifindex != SCOPE(&ep->sin))
97545530cf1Skardel msyslog(LOG_ERR,
97645530cf1Skardel "setsockopt IPV6_MULTICAST_IF %u for %s fails: %m",
97745530cf1Skardel ep->ifindex, stoa(&ep->sin));
97845530cf1Skardel break;
97945530cf1Skardel # endif
98045530cf1Skardel }
98145530cf1Skardel #endif /* MCAST */
982abb0f93cSkardel }
983abb0f93cSkardel
984abb0f93cSkardel
985abb0f93cSkardel /*
986abb0f93cSkardel * remove interface from known interface list and clean up
987abb0f93cSkardel * associated resources
988abb0f93cSkardel */
989abb0f93cSkardel static void
remove_interface(endpt * ep)990abb0f93cSkardel remove_interface(
99145530cf1Skardel endpt * ep
992abb0f93cSkardel )
993abb0f93cSkardel {
99445530cf1Skardel endpt * unlinked;
99545530cf1Skardel endpt ** pmclisthead;
996abb0f93cSkardel sockaddr_u resmask;
997abb0f93cSkardel
99845530cf1Skardel UNLINK_SLIST(unlinked, ep_list, ep, elink, endpt);
99945530cf1Skardel if (!ep->ignore_packets && INT_MULTICAST & ep->flags) {
100045530cf1Skardel pmclisthead = (AF_INET == ep->family)
100145530cf1Skardel ? &mc4_list
100245530cf1Skardel : &mc6_list;
100345530cf1Skardel UNLINK_SLIST(unlinked, *pmclisthead, ep, mclink, endpt);
100445530cf1Skardel DPRINTF(4, ("%s %s IPv%s multicast-capable unicast local address list\n",
100545530cf1Skardel stoa(&ep->sin),
100645530cf1Skardel (unlinked != NULL)
100745530cf1Skardel ? "removed from"
100845530cf1Skardel : "not found on",
100945530cf1Skardel (AF_INET == ep->family)
101045530cf1Skardel ? "4"
101145530cf1Skardel : "6"));
101245530cf1Skardel }
101345530cf1Skardel delete_interface_from_list(ep);
1014abb0f93cSkardel
101545530cf1Skardel if (ep->fd != INVALID_SOCKET) {
1016abb0f93cSkardel msyslog(LOG_INFO,
1017abb0f93cSkardel "Deleting interface #%d %s, %s#%d, interface stats: received=%ld, sent=%ld, dropped=%ld, active_time=%ld secs",
101845530cf1Skardel ep->ifnum,
101945530cf1Skardel ep->name,
102045530cf1Skardel stoa(&ep->sin),
102145530cf1Skardel SRCPORT(&ep->sin),
102245530cf1Skardel ep->received,
102345530cf1Skardel ep->sent,
102445530cf1Skardel ep->notsent,
102545530cf1Skardel current_time - ep->starttime);
1026335f7552Schristos # ifdef HAVE_IO_COMPLETION_PORT
1027335f7552Schristos io_completion_port_remove_socket(ep->fd, ep);
1028335f7552Schristos # endif
102945530cf1Skardel close_and_delete_fd_from_list(ep->fd);
1030b3d6264cSchristos ep->fd = INVALID_SOCKET;
1031abb0f93cSkardel }
1032abb0f93cSkardel
103345530cf1Skardel if (ep->bfd != INVALID_SOCKET) {
1034abb0f93cSkardel msyslog(LOG_INFO,
1035b3d6264cSchristos "stop listening for broadcasts to %s on interface #%d %s",
1036b3d6264cSchristos stoa(&ep->bcast), ep->ifnum, ep->name);
1037335f7552Schristos # ifdef HAVE_IO_COMPLETION_PORT
1038335f7552Schristos io_completion_port_remove_socket(ep->bfd, ep);
1039335f7552Schristos # endif
104045530cf1Skardel close_and_delete_fd_from_list(ep->bfd);
1041b3d6264cSchristos ep->bfd = INVALID_SOCKET;
1042abb0f93cSkardel }
1043335f7552Schristos # ifdef HAVE_IO_COMPLETION_PORT
1044335f7552Schristos io_completion_port_remove_interface(ep);
1045335f7552Schristos # endif
1046abb0f93cSkardel
1047abb0f93cSkardel ninterfaces--;
1048b3d6264cSchristos mon_clearinterface(ep);
1049abb0f93cSkardel
1050abb0f93cSkardel /* remove restrict interface entry */
105145530cf1Skardel SET_HOSTMASK(&resmask, AF(&ep->sin));
105245530cf1Skardel hack_restrict(RESTRICT_REMOVEIF, &ep->sin, &resmask,
1053169394abSchristos -3, RESM_NTPONLY | RESM_INTERFACE, RES_IGNORE, 0);
1054abb0f93cSkardel }
1055abb0f93cSkardel
1056abb0f93cSkardel
1057abb0f93cSkardel static void
log_listen_address(endpt * ep)105845530cf1Skardel log_listen_address(
105945530cf1Skardel endpt * ep
1060abb0f93cSkardel )
1061abb0f93cSkardel {
1062b3d6264cSchristos msyslog(LOG_INFO, "%s on %d %s %s",
106345530cf1Skardel (ep->ignore_packets)
1064abb0f93cSkardel ? "Listen and drop"
1065abb0f93cSkardel : "Listen normally",
106645530cf1Skardel ep->ifnum,
106745530cf1Skardel ep->name,
1068b3d6264cSchristos sptoa(&ep->sin));
1069abb0f93cSkardel }
1070abb0f93cSkardel
1071abb0f93cSkardel
1072abb0f93cSkardel static void
create_wildcards(u_short port)1073abb0f93cSkardel create_wildcards(
1074abb0f93cSkardel u_short port
1075abb0f93cSkardel )
1076abb0f93cSkardel {
107743476b9eSkardel int v4wild;
107843476b9eSkardel #ifdef INCLUDE_IPV6_SUPPORT
107943476b9eSkardel int v6wild;
108043476b9eSkardel #endif
1081abb0f93cSkardel sockaddr_u wildaddr;
1082abb0f93cSkardel nic_rule_action action;
1083abb0f93cSkardel struct interface * wildif;
1084abb0f93cSkardel
1085abb0f93cSkardel /*
1086abb0f93cSkardel * silence "potentially uninitialized" warnings from VC9
1087abb0f93cSkardel * failing to follow the logic. Ideally action could remain
1088abb0f93cSkardel * uninitialized, and the memset be the first statement under
1089abb0f93cSkardel * the first if (v4wild).
1090abb0f93cSkardel */
1091abb0f93cSkardel action = ACTION_LISTEN;
1092b3d6264cSchristos ZERO(wildaddr);
1093abb0f93cSkardel
1094abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT
1095abb0f93cSkardel /*
1096abb0f93cSkardel * create pseudo-interface with wildcard IPv6 address
1097abb0f93cSkardel */
1098abb0f93cSkardel v6wild = ipv6_works;
1099abb0f93cSkardel if (v6wild) {
1100abb0f93cSkardel /* set wildaddr to the v6 wildcard address :: */
1101b3d6264cSchristos ZERO(wildaddr);
1102abb0f93cSkardel AF(&wildaddr) = AF_INET6;
1103abb0f93cSkardel SET_ADDR6N(&wildaddr, in6addr_any);
1104abb0f93cSkardel SET_PORT(&wildaddr, port);
1105abb0f93cSkardel SET_SCOPE(&wildaddr, 0);
1106abb0f93cSkardel
1107abb0f93cSkardel /* check for interface/nic rules affecting the wildcard */
110845530cf1Skardel action = interface_action(NULL, &wildaddr, 0);
1109abb0f93cSkardel v6wild = (ACTION_IGNORE != action);
1110abb0f93cSkardel }
1111abb0f93cSkardel if (v6wild) {
1112abb0f93cSkardel wildif = new_interface(NULL);
1113abb0f93cSkardel
1114b3d6264cSchristos strlcpy(wildif->name, "v6wildcard", sizeof(wildif->name));
1115abb0f93cSkardel memcpy(&wildif->sin, &wildaddr, sizeof(wildif->sin));
1116abb0f93cSkardel wildif->family = AF_INET6;
1117abb0f93cSkardel AF(&wildif->mask) = AF_INET6;
1118abb0f93cSkardel SET_ONESMASK(&wildif->mask);
1119abb0f93cSkardel
1120abb0f93cSkardel wildif->flags = INT_UP | INT_WILDCARD;
1121abb0f93cSkardel wildif->ignore_packets = (ACTION_DROP == action);
1122abb0f93cSkardel
1123abb0f93cSkardel wildif->fd = open_socket(&wildif->sin, 0, 1, wildif);
1124abb0f93cSkardel
1125abb0f93cSkardel if (wildif->fd != INVALID_SOCKET) {
1126abb0f93cSkardel wildipv6 = wildif;
1127abb0f93cSkardel any6_interface = wildif;
1128abb0f93cSkardel add_addr_to_list(&wildif->sin, wildif);
1129abb0f93cSkardel add_interface(wildif);
113045530cf1Skardel log_listen_address(wildif);
1131abb0f93cSkardel } else {
1132abb0f93cSkardel msyslog(LOG_ERR,
1133abb0f93cSkardel "unable to bind to wildcard address %s - another process may be running - EXITING",
1134abb0f93cSkardel stoa(&wildif->sin));
1135abb0f93cSkardel exit(1);
1136abb0f93cSkardel }
1137abb0f93cSkardel DPRINT_INTERFACE(2, (wildif, "created ", "\n"));
1138abb0f93cSkardel }
1139abb0f93cSkardel #endif
1140b3d6264cSchristos
1141b3d6264cSchristos /*
1142b3d6264cSchristos * create pseudo-interface with wildcard IPv4 address
1143b3d6264cSchristos */
1144b3d6264cSchristos v4wild = ipv4_works;
1145b3d6264cSchristos if (v4wild) {
1146b3d6264cSchristos /* set wildaddr to the v4 wildcard address 0.0.0.0 */
1147b3d6264cSchristos AF(&wildaddr) = AF_INET;
1148b3d6264cSchristos SET_ADDR4N(&wildaddr, INADDR_ANY);
1149b3d6264cSchristos SET_PORT(&wildaddr, port);
1150b3d6264cSchristos
1151b3d6264cSchristos /* check for interface/nic rules affecting the wildcard */
1152b3d6264cSchristos action = interface_action(NULL, &wildaddr, 0);
1153b3d6264cSchristos v4wild = (ACTION_IGNORE != action);
1154b3d6264cSchristos }
1155b3d6264cSchristos if (v4wild) {
1156b3d6264cSchristos wildif = new_interface(NULL);
1157b3d6264cSchristos
1158b3d6264cSchristos strlcpy(wildif->name, "v4wildcard", sizeof(wildif->name));
1159b3d6264cSchristos memcpy(&wildif->sin, &wildaddr, sizeof(wildif->sin));
1160b3d6264cSchristos wildif->family = AF_INET;
1161b3d6264cSchristos AF(&wildif->mask) = AF_INET;
1162b3d6264cSchristos SET_ONESMASK(&wildif->mask);
1163b3d6264cSchristos
1164b3d6264cSchristos wildif->flags = INT_BROADCAST | INT_UP | INT_WILDCARD;
1165b3d6264cSchristos wildif->ignore_packets = (ACTION_DROP == action);
1166b3d6264cSchristos #if defined(MCAST)
1167b3d6264cSchristos /*
1168b3d6264cSchristos * enable multicast reception on the broadcast socket
1169b3d6264cSchristos */
1170b3d6264cSchristos AF(&wildif->bcast) = AF_INET;
1171b3d6264cSchristos SET_ADDR4N(&wildif->bcast, INADDR_ANY);
1172b3d6264cSchristos SET_PORT(&wildif->bcast, port);
1173b3d6264cSchristos #endif /* MCAST */
1174b3d6264cSchristos wildif->fd = open_socket(&wildif->sin, 0, 1, wildif);
1175b3d6264cSchristos
1176b3d6264cSchristos if (wildif->fd != INVALID_SOCKET) {
1177b3d6264cSchristos wildipv4 = wildif;
1178b3d6264cSchristos any_interface = wildif;
1179b3d6264cSchristos
1180b3d6264cSchristos add_addr_to_list(&wildif->sin, wildif);
1181b3d6264cSchristos add_interface(wildif);
1182b3d6264cSchristos log_listen_address(wildif);
1183b3d6264cSchristos } else {
1184b3d6264cSchristos msyslog(LOG_ERR,
1185b3d6264cSchristos "unable to bind to wildcard address %s - another process may be running - EXITING",
1186b3d6264cSchristos stoa(&wildif->sin));
1187b3d6264cSchristos exit(1);
1188b3d6264cSchristos }
1189b3d6264cSchristos DPRINT_INTERFACE(2, (wildif, "created ", "\n"));
1190b3d6264cSchristos }
1191abb0f93cSkardel }
1192abb0f93cSkardel
1193abb0f93cSkardel
1194abb0f93cSkardel /*
1195abb0f93cSkardel * add_nic_rule() -- insert a rule entry at the head of nic_rule_list.
1196abb0f93cSkardel */
1197abb0f93cSkardel void
add_nic_rule(nic_rule_match match_type,const char * if_name,int prefixlen,nic_rule_action action)1198abb0f93cSkardel add_nic_rule(
1199abb0f93cSkardel nic_rule_match match_type,
1200abb0f93cSkardel const char * if_name, /* interface name or numeric address */
1201abb0f93cSkardel int prefixlen,
1202abb0f93cSkardel nic_rule_action action
1203abb0f93cSkardel )
1204abb0f93cSkardel {
1205abb0f93cSkardel nic_rule * rule;
1206abb0f93cSkardel isc_boolean_t is_ip;
1207abb0f93cSkardel
1208b3d6264cSchristos rule = emalloc_zero(sizeof(*rule));
1209abb0f93cSkardel rule->match_type = match_type;
1210abb0f93cSkardel rule->prefixlen = prefixlen;
1211abb0f93cSkardel rule->action = action;
1212abb0f93cSkardel
1213abb0f93cSkardel if (MATCH_IFNAME == match_type) {
121409f14f80Schristos REQUIRE(NULL != if_name);
1215abb0f93cSkardel rule->if_name = estrdup(if_name);
1216abb0f93cSkardel } else if (MATCH_IFADDR == match_type) {
121709f14f80Schristos REQUIRE(NULL != if_name);
121845530cf1Skardel /* set rule->addr */
1219b3d6264cSchristos is_ip = is_ip_address(if_name, AF_UNSPEC, &rule->addr);
122009f14f80Schristos REQUIRE(is_ip);
1221abb0f93cSkardel } else
122209f14f80Schristos REQUIRE(NULL == if_name);
1223abb0f93cSkardel
1224abb0f93cSkardel LINK_SLIST(nic_rule_list, rule, next);
1225abb0f93cSkardel }
1226abb0f93cSkardel
1227abb0f93cSkardel
1228abb0f93cSkardel #ifdef DEBUG
1229abb0f93cSkardel static const char *
action_text(nic_rule_action action)1230abb0f93cSkardel action_text(
1231abb0f93cSkardel nic_rule_action action
1232abb0f93cSkardel )
1233abb0f93cSkardel {
1234abb0f93cSkardel const char *t;
1235abb0f93cSkardel
1236abb0f93cSkardel switch (action) {
1237abb0f93cSkardel
1238abb0f93cSkardel default:
1239abb0f93cSkardel t = "ERROR"; /* quiet uninit warning */
1240abb0f93cSkardel DPRINTF(1, ("fatal: unknown nic_rule_action %d\n",
1241abb0f93cSkardel action));
124209f14f80Schristos ENSURE(0);
1243abb0f93cSkardel break;
1244abb0f93cSkardel
1245abb0f93cSkardel case ACTION_LISTEN:
1246abb0f93cSkardel t = "listen";
1247abb0f93cSkardel break;
1248abb0f93cSkardel
1249abb0f93cSkardel case ACTION_IGNORE:
1250abb0f93cSkardel t = "ignore";
1251abb0f93cSkardel break;
1252abb0f93cSkardel
1253abb0f93cSkardel case ACTION_DROP:
1254abb0f93cSkardel t = "drop";
1255abb0f93cSkardel break;
1256abb0f93cSkardel }
1257abb0f93cSkardel
1258abb0f93cSkardel return t;
1259abb0f93cSkardel }
1260abb0f93cSkardel #endif /* DEBUG */
1261abb0f93cSkardel
1262abb0f93cSkardel
1263abb0f93cSkardel static nic_rule_action
interface_action(char * if_name,sockaddr_u * if_addr,u_int32 if_flags)1264abb0f93cSkardel interface_action(
1265abb0f93cSkardel char * if_name,
126645530cf1Skardel sockaddr_u * if_addr,
126745530cf1Skardel u_int32 if_flags
1268abb0f93cSkardel )
1269abb0f93cSkardel {
1270abb0f93cSkardel nic_rule * rule;
1271abb0f93cSkardel int isloopback;
1272abb0f93cSkardel int iswildcard;
1273abb0f93cSkardel
1274b3d6264cSchristos DPRINTF(4, ("interface_action: interface %s ",
1275b3d6264cSchristos (if_name != NULL) ? if_name : "wildcard"));
1276abb0f93cSkardel
127745530cf1Skardel iswildcard = is_wildcard_addr(if_addr);
1278b3d6264cSchristos isloopback = !!(INT_LOOPBACK & if_flags);
1279abb0f93cSkardel
1280abb0f93cSkardel /*
1281abb0f93cSkardel * Find any matching NIC rule from --interface / -I or ntp.conf
1282abb0f93cSkardel * interface/nic rules.
1283abb0f93cSkardel */
1284abb0f93cSkardel for (rule = nic_rule_list; rule != NULL; rule = rule->next) {
1285abb0f93cSkardel
1286abb0f93cSkardel switch (rule->match_type) {
1287abb0f93cSkardel
1288abb0f93cSkardel case MATCH_ALL:
1289abb0f93cSkardel /* loopback and wildcard excluded from "all" */
1290abb0f93cSkardel if (isloopback || iswildcard)
1291abb0f93cSkardel break;
1292abb0f93cSkardel DPRINTF(4, ("nic all %s\n",
1293abb0f93cSkardel action_text(rule->action)));
1294abb0f93cSkardel return rule->action;
1295abb0f93cSkardel
1296abb0f93cSkardel case MATCH_IPV4:
129745530cf1Skardel if (IS_IPV4(if_addr)) {
1298abb0f93cSkardel DPRINTF(4, ("nic ipv4 %s\n",
1299abb0f93cSkardel action_text(rule->action)));
1300abb0f93cSkardel return rule->action;
1301abb0f93cSkardel }
1302abb0f93cSkardel break;
1303abb0f93cSkardel
1304abb0f93cSkardel case MATCH_IPV6:
130545530cf1Skardel if (IS_IPV6(if_addr)) {
1306abb0f93cSkardel DPRINTF(4, ("nic ipv6 %s\n",
1307abb0f93cSkardel action_text(rule->action)));
1308abb0f93cSkardel return rule->action;
1309abb0f93cSkardel }
1310abb0f93cSkardel break;
1311abb0f93cSkardel
1312abb0f93cSkardel case MATCH_WILDCARD:
1313abb0f93cSkardel if (iswildcard) {
1314abb0f93cSkardel DPRINTF(4, ("nic wildcard %s\n",
1315abb0f93cSkardel action_text(rule->action)));
1316abb0f93cSkardel return rule->action;
1317abb0f93cSkardel }
1318abb0f93cSkardel break;
1319abb0f93cSkardel
1320abb0f93cSkardel case MATCH_IFADDR:
1321abb0f93cSkardel if (rule->prefixlen != -1) {
132245530cf1Skardel if (addr_eqprefix(if_addr, &rule->addr,
132345530cf1Skardel rule->prefixlen)) {
1324abb0f93cSkardel
1325abb0f93cSkardel DPRINTF(4, ("subnet address match - %s\n",
1326abb0f93cSkardel action_text(rule->action)));
1327abb0f93cSkardel return rule->action;
1328abb0f93cSkardel }
1329abb0f93cSkardel } else
133045530cf1Skardel if (SOCK_EQ(if_addr, &rule->addr)) {
1331abb0f93cSkardel
1332abb0f93cSkardel DPRINTF(4, ("address match - %s\n",
1333abb0f93cSkardel action_text(rule->action)));
1334abb0f93cSkardel return rule->action;
1335abb0f93cSkardel }
1336abb0f93cSkardel break;
1337abb0f93cSkardel
1338abb0f93cSkardel case MATCH_IFNAME:
1339abb0f93cSkardel if (if_name != NULL
1340ad131110Schristos #if defined(HAVE_FNMATCH) && defined(FNM_CASEFOLD)
1341ad131110Schristos && !fnmatch(rule->if_name, if_name, FNM_CASEFOLD)
1342ad131110Schristos #else
1343ad131110Schristos && !strcasecmp(if_name, rule->if_name)
1344ad131110Schristos #endif
1345ad131110Schristos ) {
1346abb0f93cSkardel
1347abb0f93cSkardel DPRINTF(4, ("interface name match - %s\n",
1348abb0f93cSkardel action_text(rule->action)));
1349abb0f93cSkardel return rule->action;
1350abb0f93cSkardel }
1351abb0f93cSkardel break;
1352abb0f93cSkardel }
1353abb0f93cSkardel }
1354abb0f93cSkardel
1355abb0f93cSkardel /*
1356abb0f93cSkardel * Unless explicitly disabled such as with "nic ignore ::1"
1357abb0f93cSkardel * listen on loopback addresses. Since ntpq and ntpdc query
1358abb0f93cSkardel * "localhost" by default, which typically resolves to ::1 and
1359abb0f93cSkardel * 127.0.0.1, it's useful to default to listening on both.
1360abb0f93cSkardel */
1361abb0f93cSkardel if (isloopback) {
1362abb0f93cSkardel DPRINTF(4, ("default loopback listen\n"));
1363abb0f93cSkardel return ACTION_LISTEN;
1364abb0f93cSkardel }
1365abb0f93cSkardel
1366abb0f93cSkardel /*
1367abb0f93cSkardel * Treat wildcard addresses specially. If there is no explicit
1368abb0f93cSkardel * "nic ... wildcard" or "nic ... 0.0.0.0" or "nic ... ::" rule
1369abb0f93cSkardel * default to drop.
1370abb0f93cSkardel */
1371abb0f93cSkardel if (iswildcard) {
1372abb0f93cSkardel DPRINTF(4, ("default wildcard drop\n"));
1373abb0f93cSkardel return ACTION_DROP;
1374abb0f93cSkardel }
1375abb0f93cSkardel
1376abb0f93cSkardel /*
1377abb0f93cSkardel * Check for "virtual IP" (colon in the interface name) after
1378abb0f93cSkardel * the rules so that "ntpd --interface eth0:1 -novirtualips"
1379abb0f93cSkardel * does indeed listen on eth0:1's addresses.
1380abb0f93cSkardel */
1381abb0f93cSkardel if (!listen_to_virtual_ips && if_name != NULL
1382abb0f93cSkardel && (strchr(if_name, ':') != NULL)) {
1383abb0f93cSkardel
1384abb0f93cSkardel DPRINTF(4, ("virtual ip - ignore\n"));
1385abb0f93cSkardel return ACTION_IGNORE;
1386abb0f93cSkardel }
1387abb0f93cSkardel
1388abb0f93cSkardel /*
1389abb0f93cSkardel * If there are no --interface/-I command-line options and no
1390abb0f93cSkardel * interface/nic rules in ntp.conf, the default action is to
1391abb0f93cSkardel * listen. In the presence of rules from either, the default
1392abb0f93cSkardel * is to ignore. This implements ntpd's traditional listen-
1393abb0f93cSkardel * every default with no interface listen configuration, and
1394abb0f93cSkardel * ensures a single -I eth0 or "nic listen eth0" means do not
1395abb0f93cSkardel * listen on any other addresses.
1396abb0f93cSkardel */
1397abb0f93cSkardel if (NULL == nic_rule_list) {
1398abb0f93cSkardel DPRINTF(4, ("default listen\n"));
1399abb0f93cSkardel return ACTION_LISTEN;
1400abb0f93cSkardel }
1401abb0f93cSkardel
1402abb0f93cSkardel DPRINTF(4, ("implicit ignore\n"));
1403abb0f93cSkardel return ACTION_IGNORE;
1404abb0f93cSkardel }
1405abb0f93cSkardel
1406abb0f93cSkardel
1407abb0f93cSkardel static void
convert_isc_if(isc_interface_t * isc_if,endpt * itf,u_short port)1408abb0f93cSkardel convert_isc_if(
1409abb0f93cSkardel isc_interface_t *isc_if,
141045530cf1Skardel endpt *itf,
1411abb0f93cSkardel u_short port
1412abb0f93cSkardel )
1413abb0f93cSkardel {
141445530cf1Skardel const u_char v6loop[16] = {0, 0, 0, 0, 0, 0, 0, 0,
141545530cf1Skardel 0, 0, 0, 0, 0, 0, 0, 1};
141645530cf1Skardel
1417b3d6264cSchristos strlcpy(itf->name, isc_if->name, sizeof(itf->name));
141845530cf1Skardel itf->ifindex = isc_if->ifindex;
1419abb0f93cSkardel itf->family = (u_short)isc_if->af;
1420abb0f93cSkardel AF(&itf->sin) = itf->family;
1421abb0f93cSkardel AF(&itf->mask) = itf->family;
1422abb0f93cSkardel AF(&itf->bcast) = itf->family;
1423abb0f93cSkardel SET_PORT(&itf->sin, port);
1424abb0f93cSkardel SET_PORT(&itf->mask, port);
1425abb0f93cSkardel SET_PORT(&itf->bcast, port);
1426abb0f93cSkardel
1427abb0f93cSkardel if (IS_IPV4(&itf->sin)) {
1428abb0f93cSkardel NSRCADR(&itf->sin) = isc_if->address.type.in.s_addr;
1429abb0f93cSkardel NSRCADR(&itf->mask) = isc_if->netmask.type.in.s_addr;
1430abb0f93cSkardel
1431abb0f93cSkardel if (isc_if->flags & INTERFACE_F_BROADCAST) {
1432abb0f93cSkardel itf->flags |= INT_BROADCAST;
1433abb0f93cSkardel NSRCADR(&itf->bcast) =
1434abb0f93cSkardel isc_if->broadcast.type.in.s_addr;
1435abb0f93cSkardel }
1436abb0f93cSkardel }
1437abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT
1438abb0f93cSkardel else if (IS_IPV6(&itf->sin)) {
1439abb0f93cSkardel SET_ADDR6N(&itf->sin, isc_if->address.type.in6);
1440abb0f93cSkardel SET_ADDR6N(&itf->mask, isc_if->netmask.type.in6);
1441abb0f93cSkardel
144245530cf1Skardel SET_SCOPE(&itf->sin, isc_if->address.zone);
1443abb0f93cSkardel }
1444abb0f93cSkardel #endif /* INCLUDE_IPV6_SUPPORT */
1445abb0f93cSkardel
1446abb0f93cSkardel
1447abb0f93cSkardel /* Process the rest of the flags */
1448abb0f93cSkardel
1449abb0f93cSkardel itf->flags |=
1450abb0f93cSkardel ((INTERFACE_F_UP & isc_if->flags)
1451abb0f93cSkardel ? INT_UP : 0)
1452abb0f93cSkardel | ((INTERFACE_F_LOOPBACK & isc_if->flags)
1453abb0f93cSkardel ? INT_LOOPBACK : 0)
1454abb0f93cSkardel | ((INTERFACE_F_POINTTOPOINT & isc_if->flags)
1455abb0f93cSkardel ? INT_PPP : 0)
1456abb0f93cSkardel | ((INTERFACE_F_MULTICAST & isc_if->flags)
1457abb0f93cSkardel ? INT_MULTICAST : 0)
145845530cf1Skardel | ((INTERFACE_F_PRIVACY & isc_if->flags)
145945530cf1Skardel ? INT_PRIVACY : 0)
1460abb0f93cSkardel ;
146145530cf1Skardel
146245530cf1Skardel /*
146345530cf1Skardel * Clear the loopback flag if the address is not localhost.
146445530cf1Skardel * http://bugs.ntp.org/1683
146545530cf1Skardel */
146645530cf1Skardel if (INT_LOOPBACK & itf->flags) {
146745530cf1Skardel if (AF_INET == itf->family) {
146845530cf1Skardel if (127 != (SRCADR(&itf->sin) >> 24))
146945530cf1Skardel itf->flags &= ~INT_LOOPBACK;
147045530cf1Skardel } else {
147145530cf1Skardel if (memcmp(v6loop, NSRCADR6(&itf->sin),
147245530cf1Skardel sizeof(NSRCADR6(&itf->sin))))
147345530cf1Skardel itf->flags &= ~INT_LOOPBACK;
147445530cf1Skardel }
147545530cf1Skardel }
1476abb0f93cSkardel }
1477abb0f93cSkardel
1478abb0f93cSkardel
1479abb0f93cSkardel /*
1480abb0f93cSkardel * refresh_interface
1481abb0f93cSkardel *
1482abb0f93cSkardel * some OSes have been observed to keep
1483abb0f93cSkardel * cached routes even when more specific routes
1484abb0f93cSkardel * become available.
1485abb0f93cSkardel * this can be mitigated by re-binding
1486abb0f93cSkardel * the socket.
1487abb0f93cSkardel */
1488abb0f93cSkardel static int
refresh_interface(struct interface * interface)1489abb0f93cSkardel refresh_interface(
1490abb0f93cSkardel struct interface * interface
1491abb0f93cSkardel )
1492abb0f93cSkardel {
1493abb0f93cSkardel #ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES
1494abb0f93cSkardel if (interface->fd != INVALID_SOCKET) {
1495b3d6264cSchristos int bcast = (interface->flags & INT_BCASTXMIT) != 0;
1496b3d6264cSchristos /* as we forcibly close() the socket remove the
1497b3d6264cSchristos broadcast permission indication */
1498b3d6264cSchristos if (bcast)
1499b3d6264cSchristos socket_broadcast_disable(interface, &interface->sin);
1500b3d6264cSchristos
1501abb0f93cSkardel close_and_delete_fd_from_list(interface->fd);
1502b3d6264cSchristos
1503b3d6264cSchristos /* create new socket picking up a new first hop binding
1504b3d6264cSchristos at connect() time */
1505abb0f93cSkardel interface->fd = open_socket(&interface->sin,
1506766d83b9Skardel bcast, 0, interface);
1507abb0f93cSkardel /*
1508abb0f93cSkardel * reset TTL indication so TTL is is set again
1509abb0f93cSkardel * next time around
1510abb0f93cSkardel */
1511abb0f93cSkardel interface->last_ttl = 0;
1512abb0f93cSkardel return (interface->fd != INVALID_SOCKET);
1513abb0f93cSkardel } else
1514abb0f93cSkardel return 0; /* invalid sockets are not refreshable */
1515abb0f93cSkardel #else /* !OS_MISSES_SPECIFIC_ROUTE_UPDATES */
1516abb0f93cSkardel return (interface->fd != INVALID_SOCKET);
1517abb0f93cSkardel #endif /* !OS_MISSES_SPECIFIC_ROUTE_UPDATES */
1518abb0f93cSkardel }
1519abb0f93cSkardel
1520abb0f93cSkardel /*
1521abb0f93cSkardel * interface_update - externally callable update function
1522abb0f93cSkardel */
1523abb0f93cSkardel void
interface_update(interface_receiver_t receiver,void * data)1524abb0f93cSkardel interface_update(
1525abb0f93cSkardel interface_receiver_t receiver,
1526abb0f93cSkardel void * data)
1527abb0f93cSkardel {
1528abb0f93cSkardel int new_interface_found;
1529abb0f93cSkardel
1530abb0f93cSkardel if (disable_dynamic_updates)
1531abb0f93cSkardel return;
1532abb0f93cSkardel
1533abb0f93cSkardel BLOCKIO();
1534abb0f93cSkardel new_interface_found = update_interfaces(NTP_PORT, receiver, data);
1535abb0f93cSkardel UNBLOCKIO();
1536abb0f93cSkardel
1537abb0f93cSkardel if (!new_interface_found)
1538abb0f93cSkardel return;
1539abb0f93cSkardel
1540abb0f93cSkardel #ifdef DEBUG
1541abb0f93cSkardel msyslog(LOG_DEBUG, "new interface(s) found: waking up resolver");
1542abb0f93cSkardel #endif
1543b3d6264cSchristos interrupt_worker_sleep();
1544abb0f93cSkardel }
1545abb0f93cSkardel
1546abb0f93cSkardel
1547abb0f93cSkardel /*
1548abb0f93cSkardel * sau_from_netaddr() - convert network address on-wire formats.
1549abb0f93cSkardel * Convert from libisc's isc_netaddr_t to NTP's sockaddr_u
1550abb0f93cSkardel */
1551abb0f93cSkardel void
sau_from_netaddr(sockaddr_u * psau,const isc_netaddr_t * pna)1552abb0f93cSkardel sau_from_netaddr(
1553abb0f93cSkardel sockaddr_u *psau,
1554abb0f93cSkardel const isc_netaddr_t *pna
1555abb0f93cSkardel )
1556abb0f93cSkardel {
1557b3d6264cSchristos ZERO_SOCK(psau);
1558abb0f93cSkardel AF(psau) = (u_short)pna->family;
1559abb0f93cSkardel switch (pna->family) {
1560abb0f93cSkardel
1561abb0f93cSkardel case AF_INET:
1562abb0f93cSkardel memcpy(&psau->sa4.sin_addr, &pna->type.in,
1563abb0f93cSkardel sizeof(psau->sa4.sin_addr));
1564abb0f93cSkardel break;
1565abb0f93cSkardel
1566abb0f93cSkardel case AF_INET6:
1567abb0f93cSkardel memcpy(&psau->sa6.sin6_addr, &pna->type.in6,
1568abb0f93cSkardel sizeof(psau->sa6.sin6_addr));
1569abb0f93cSkardel break;
1570abb0f93cSkardel }
1571abb0f93cSkardel }
1572abb0f93cSkardel
1573abb0f93cSkardel
1574abb0f93cSkardel static int
is_wildcard_addr(const sockaddr_u * psau)1575abb0f93cSkardel is_wildcard_addr(
157645530cf1Skardel const sockaddr_u *psau
1577abb0f93cSkardel )
1578abb0f93cSkardel {
1579abb0f93cSkardel if (IS_IPV4(psau) && !NSRCADR(psau))
1580abb0f93cSkardel return 1;
1581abb0f93cSkardel
1582abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT
1583abb0f93cSkardel if (IS_IPV6(psau) && S_ADDR6_EQ(psau, &in6addr_any))
1584abb0f93cSkardel return 1;
1585abb0f93cSkardel #endif
1586abb0f93cSkardel
1587abb0f93cSkardel return 0;
1588abb0f93cSkardel }
1589abb0f93cSkardel
1590abb0f93cSkardel
1591abb0f93cSkardel #ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND
1592abb0f93cSkardel /*
1593abb0f93cSkardel * enable/disable re-use of wildcard address socket
1594abb0f93cSkardel */
1595abb0f93cSkardel static void
set_wildcard_reuse(u_short family,int on)1596abb0f93cSkardel set_wildcard_reuse(
1597abb0f93cSkardel u_short family,
1598abb0f93cSkardel int on
1599abb0f93cSkardel )
1600abb0f93cSkardel {
1601abb0f93cSkardel struct interface *any;
1602abb0f93cSkardel SOCKET fd = INVALID_SOCKET;
1603abb0f93cSkardel
1604abb0f93cSkardel any = ANY_INTERFACE_BYFAM(family);
1605abb0f93cSkardel if (any != NULL)
1606abb0f93cSkardel fd = any->fd;
1607abb0f93cSkardel
1608abb0f93cSkardel if (fd != INVALID_SOCKET) {
1609abb0f93cSkardel if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
1610169394abSchristos (void *)&on, sizeof(on)))
1611abb0f93cSkardel msyslog(LOG_ERR,
1612abb0f93cSkardel "set_wildcard_reuse: setsockopt(SO_REUSEADDR, %s) failed: %m",
1613abb0f93cSkardel on ? "on" : "off");
1614abb0f93cSkardel
1615abb0f93cSkardel DPRINTF(4, ("set SO_REUSEADDR to %s on %s\n",
1616abb0f93cSkardel on ? "on" : "off",
1617abb0f93cSkardel stoa(&any->sin)));
1618abb0f93cSkardel }
1619abb0f93cSkardel }
1620abb0f93cSkardel #endif /* OS_NEEDS_REUSEADDR_FOR_IFADDRBIND */
1621abb0f93cSkardel
16227469785fSroy static isc_boolean_t
check_flags(sockaddr_u * psau,const char * name,u_int32 flags)16237469785fSroy check_flags(
16247469785fSroy sockaddr_u *psau,
16257469785fSroy const char *name,
16267469785fSroy u_int32 flags
16277469785fSroy )
16287469785fSroy {
16297469785fSroy #if defined(SIOCGIFAFLAG_IN)
16307469785fSroy struct ifreq ifr;
16317469785fSroy int fd;
16327469785fSroy
16337469785fSroy if (psau->sa.sa_family != AF_INET)
16347469785fSroy return ISC_FALSE;
16357469785fSroy if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
16367469785fSroy return ISC_FALSE;
16377469785fSroy ZERO(ifr);
16387469785fSroy memcpy(&ifr.ifr_addr, &psau->sa, sizeof(ifr.ifr_addr));
16397469785fSroy strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
16407469785fSroy if (ioctl(fd, SIOCGIFAFLAG_IN, &ifr) < 0) {
16417469785fSroy close(fd);
16427469785fSroy return ISC_FALSE;
16437469785fSroy }
16447469785fSroy close(fd);
16457469785fSroy if ((ifr.ifr_addrflags & flags) != 0)
16467469785fSroy return ISC_TRUE;
16477469785fSroy #endif /* SIOCGIFAFLAG_IN */
16487469785fSroy return ISC_FALSE;
16497469785fSroy }
165045530cf1Skardel
165145530cf1Skardel static isc_boolean_t
check_flags6(sockaddr_u * psau,const char * name,u_int32 flags6)1652df44c210Sroy check_flags6(
165345530cf1Skardel sockaddr_u *psau,
1654df44c210Sroy const char *name,
1655df44c210Sroy u_int32 flags6
165645530cf1Skardel )
165745530cf1Skardel {
1658df44c210Sroy #if defined(INCLUDE_IPV6_SUPPORT) && defined(SIOCGIFAFLAG_IN6)
165945530cf1Skardel struct in6_ifreq ifr6;
166045530cf1Skardel int fd;
166145530cf1Skardel
166245530cf1Skardel if (psau->sa.sa_family != AF_INET6)
166345530cf1Skardel return ISC_FALSE;
166445530cf1Skardel if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
166545530cf1Skardel return ISC_FALSE;
1666b3d6264cSchristos ZERO(ifr6);
166745530cf1Skardel memcpy(&ifr6.ifr_addr, &psau->sa6, sizeof(ifr6.ifr_addr));
1668b3d6264cSchristos strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
166945530cf1Skardel if (ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
167045530cf1Skardel close(fd);
167145530cf1Skardel return ISC_FALSE;
167245530cf1Skardel }
167345530cf1Skardel close(fd);
1674df44c210Sroy if ((ifr6.ifr_ifru.ifru_flags6 & flags6) != 0)
167545530cf1Skardel return ISC_TRUE;
1676df44c210Sroy #endif /* INCLUDE_IPV6_SUPPORT && SIOCGIFAFLAG_IN6 */
167745530cf1Skardel return ISC_FALSE;
167845530cf1Skardel }
167945530cf1Skardel
1680df44c210Sroy static isc_boolean_t
is_anycast(sockaddr_u * psau,const char * name)1681df44c210Sroy is_anycast(
1682df44c210Sroy sockaddr_u *psau,
1683df44c210Sroy const char *name
1684df44c210Sroy )
1685df44c210Sroy {
1686df44c210Sroy #ifdef IN6_IFF_ANYCAST
1687df44c210Sroy return check_flags6(psau, name, IN6_IFF_ANYCAST);
1688df44c210Sroy #else
1689df44c210Sroy return ISC_FALSE;
1690df44c210Sroy #endif
1691df44c210Sroy }
1692df44c210Sroy
1693df44c210Sroy static isc_boolean_t
is_valid(sockaddr_u * psau,const char * name)1694df44c210Sroy is_valid(
1695df44c210Sroy sockaddr_u *psau,
1696df44c210Sroy const char *name
1697df44c210Sroy )
1698df44c210Sroy {
16997469785fSroy u_int32 flags;
1700df44c210Sroy
17017469785fSroy flags = 0;
17027469785fSroy switch (psau->sa.sa_family) {
17037469785fSroy case AF_INET:
17047469785fSroy #ifdef IN_IFF_DETACHED
17057469785fSroy flags |= IN_IFF_DETACHED;
17067469785fSroy #endif
17077469785fSroy #ifdef IN_IFF_TENTATIVE
17087469785fSroy flags |= IN_IFF_TENTATIVE;
17097469785fSroy #endif
17107469785fSroy return check_flags(psau, name, flags) ? ISC_FALSE : ISC_TRUE;
17117469785fSroy case AF_INET6:
1712df44c210Sroy #ifdef IN6_IFF_DEPARTED
17137469785fSroy flags |= IN6_IFF_DEPARTED;
1714df44c210Sroy #endif
1715df44c210Sroy #ifdef IN6_IFF_DETACHED
17167469785fSroy flags |= IN6_IFF_DETACHED;
1717df44c210Sroy #endif
1718df44c210Sroy #ifdef IN6_IFF_TENTATIVE
17197469785fSroy flags |= IN6_IFF_TENTATIVE;
1720df44c210Sroy #endif
17217469785fSroy return check_flags6(psau, name, flags) ? ISC_FALSE : ISC_TRUE;
17227469785fSroy default:
17237469785fSroy return ISC_FALSE;
17247469785fSroy }
1725df44c210Sroy }
172645530cf1Skardel
1727abb0f93cSkardel /*
1728abb0f93cSkardel * update_interface strategy
1729abb0f93cSkardel *
1730abb0f93cSkardel * toggle configuration phase
1731abb0f93cSkardel *
1732abb0f93cSkardel * Phase 1:
1733abb0f93cSkardel * forall currently existing interfaces
1734abb0f93cSkardel * if address is known:
1735abb0f93cSkardel * drop socket - rebind again
1736abb0f93cSkardel *
1737abb0f93cSkardel * if address is NOT known:
1738abb0f93cSkardel * attempt to create a new interface entry
1739abb0f93cSkardel *
1740abb0f93cSkardel * Phase 2:
1741abb0f93cSkardel * forall currently known non MCAST and WILDCARD interfaces
1742abb0f93cSkardel * if interface does not match configuration phase (not seen in phase 1):
1743abb0f93cSkardel * remove interface from known interface list
1744abb0f93cSkardel * forall peers associated with this interface
1745abb0f93cSkardel * disconnect peer from this interface
1746abb0f93cSkardel *
1747abb0f93cSkardel * Phase 3:
1748abb0f93cSkardel * attempt to re-assign interfaces to peers
1749abb0f93cSkardel *
1750abb0f93cSkardel */
1751abb0f93cSkardel
1752abb0f93cSkardel static int
update_interfaces(u_short port,interface_receiver_t receiver,void * data)1753abb0f93cSkardel update_interfaces(
1754abb0f93cSkardel u_short port,
1755abb0f93cSkardel interface_receiver_t receiver,
1756abb0f93cSkardel void * data
1757abb0f93cSkardel )
1758abb0f93cSkardel {
1759abb0f93cSkardel isc_mem_t * mctx = (void *)-1;
1760abb0f93cSkardel interface_info_t ifi;
1761abb0f93cSkardel isc_interfaceiter_t * iter;
1762abb0f93cSkardel isc_result_t result;
1763abb0f93cSkardel isc_interface_t isc_if;
1764abb0f93cSkardel int new_interface_found;
1765abb0f93cSkardel unsigned int family;
176645530cf1Skardel endpt enumep;
176745530cf1Skardel endpt * ep;
176845530cf1Skardel endpt * next_ep;
1769abb0f93cSkardel
1770abb0f93cSkardel DPRINTF(3, ("update_interfaces(%d)\n", port));
1771abb0f93cSkardel
1772abb0f93cSkardel /*
1773abb0f93cSkardel * phase one - scan interfaces
1774abb0f93cSkardel * - create those that are not found
1775abb0f93cSkardel * - update those that are found
1776abb0f93cSkardel */
1777abb0f93cSkardel
177845530cf1Skardel new_interface_found = FALSE;
1779abb0f93cSkardel iter = NULL;
1780abb0f93cSkardel result = isc_interfaceiter_create(mctx, &iter);
1781abb0f93cSkardel
1782abb0f93cSkardel if (result != ISC_R_SUCCESS)
1783abb0f93cSkardel return 0;
1784abb0f93cSkardel
1785abb0f93cSkardel /*
1786abb0f93cSkardel * Toggle system interface scan phase to find untouched
1787abb0f93cSkardel * interfaces to be deleted.
1788abb0f93cSkardel */
1789abb0f93cSkardel sys_interphase ^= 0x1;
1790abb0f93cSkardel
1791abb0f93cSkardel for (result = isc_interfaceiter_first(iter);
1792abb0f93cSkardel ISC_R_SUCCESS == result;
1793abb0f93cSkardel result = isc_interfaceiter_next(iter)) {
1794abb0f93cSkardel
1795abb0f93cSkardel result = isc_interfaceiter_current(iter, &isc_if);
1796abb0f93cSkardel
1797abb0f93cSkardel if (result != ISC_R_SUCCESS)
1798abb0f93cSkardel break;
1799abb0f93cSkardel
1800abb0f93cSkardel /* See if we have a valid family to use */
1801abb0f93cSkardel family = isc_if.address.family;
1802abb0f93cSkardel if (AF_INET != family && AF_INET6 != family)
1803abb0f93cSkardel continue;
1804abb0f93cSkardel if (AF_INET == family && !ipv4_works)
1805abb0f93cSkardel continue;
1806abb0f93cSkardel if (AF_INET6 == family && !ipv6_works)
1807abb0f93cSkardel continue;
1808abb0f93cSkardel
1809abb0f93cSkardel /* create prototype */
181045530cf1Skardel init_interface(&enumep);
1811abb0f93cSkardel
181245530cf1Skardel convert_isc_if(&isc_if, &enumep, port);
1813abb0f93cSkardel
1814b3d6264cSchristos DPRINT_INTERFACE(4, (&enumep, "examining ", "\n"));
1815b3d6264cSchristos
1816abb0f93cSkardel /*
1817abb0f93cSkardel * Check if and how we are going to use the interface.
1818abb0f93cSkardel */
181945530cf1Skardel switch (interface_action(enumep.name, &enumep.sin,
182045530cf1Skardel enumep.flags)) {
1821abb0f93cSkardel
1822abb0f93cSkardel case ACTION_IGNORE:
1823b3d6264cSchristos DPRINTF(4, ("ignoring interface %s (%s) - by nic rules\n",
1824b3d6264cSchristos enumep.name, stoa(&enumep.sin)));
1825abb0f93cSkardel continue;
1826abb0f93cSkardel
1827abb0f93cSkardel case ACTION_LISTEN:
1828b3d6264cSchristos DPRINTF(4, ("listen interface %s (%s) - by nic rules\n",
1829b3d6264cSchristos enumep.name, stoa(&enumep.sin)));
183045530cf1Skardel enumep.ignore_packets = ISC_FALSE;
1831abb0f93cSkardel break;
1832abb0f93cSkardel
1833abb0f93cSkardel case ACTION_DROP:
1834b3d6264cSchristos DPRINTF(4, ("drop on interface %s (%s) - by nic rules\n",
1835b3d6264cSchristos enumep.name, stoa(&enumep.sin)));
183645530cf1Skardel enumep.ignore_packets = ISC_TRUE;
1837abb0f93cSkardel break;
1838abb0f93cSkardel }
1839abb0f93cSkardel
1840abb0f93cSkardel /* interfaces must be UP to be usable */
184145530cf1Skardel if (!(enumep.flags & INT_UP)) {
1842abb0f93cSkardel DPRINTF(4, ("skipping interface %s (%s) - DOWN\n",
184345530cf1Skardel enumep.name, stoa(&enumep.sin)));
1844abb0f93cSkardel continue;
1845abb0f93cSkardel }
1846abb0f93cSkardel
1847abb0f93cSkardel /*
1848abb0f93cSkardel * skip any interfaces UP and bound to a wildcard
1849abb0f93cSkardel * address - some dhcp clients produce that in the
1850abb0f93cSkardel * wild
1851abb0f93cSkardel */
185245530cf1Skardel if (is_wildcard_addr(&enumep.sin))
185345530cf1Skardel continue;
185445530cf1Skardel
185545530cf1Skardel if (is_anycast(&enumep.sin, isc_if.name))
1856abb0f93cSkardel continue;
1857abb0f93cSkardel
1858abb0f93cSkardel /*
1859df44c210Sroy * skip any address that is an invalid state to be used
1860df44c210Sroy */
1861df44c210Sroy if (!is_valid(&enumep.sin, isc_if.name))
1862df44c210Sroy continue;
1863df44c210Sroy
1864df44c210Sroy /*
1865abb0f93cSkardel * map to local *address* in order to map all duplicate
186645530cf1Skardel * interfaces to an endpt structure with the appropriate
186745530cf1Skardel * socket. Our name space is (ip-address), NOT
186845530cf1Skardel * (interface name, ip-address).
1869abb0f93cSkardel */
187045530cf1Skardel ep = getinterface(&enumep.sin, INT_WILDCARD);
1871abb0f93cSkardel
187245530cf1Skardel if (ep != NULL && refresh_interface(ep)) {
1873abb0f93cSkardel /*
1874abb0f93cSkardel * found existing and up to date interface -
1875abb0f93cSkardel * mark present.
1876abb0f93cSkardel */
187745530cf1Skardel if (ep->phase != sys_interphase) {
1878abb0f93cSkardel /*
1879abb0f93cSkardel * On a new round we reset the name so
1880abb0f93cSkardel * the interface name shows up again if
1881abb0f93cSkardel * this address is no longer shared.
188245530cf1Skardel * We reset ignore_packets from the
188345530cf1Skardel * new prototype to respect any runtime
188445530cf1Skardel * changes to the nic rules.
1885abb0f93cSkardel */
1886b3d6264cSchristos strlcpy(ep->name, enumep.name,
188745530cf1Skardel sizeof(ep->name));
188845530cf1Skardel ep->ignore_packets =
188945530cf1Skardel enumep.ignore_packets;
189045530cf1Skardel } else {
1891abb0f93cSkardel /* name collision - rename interface */
1892b3d6264cSchristos strlcpy(ep->name, "*multiple*",
189345530cf1Skardel sizeof(ep->name));
189445530cf1Skardel }
1895abb0f93cSkardel
189645530cf1Skardel DPRINT_INTERFACE(4, (ep, "updating ",
1897abb0f93cSkardel " present\n"));
1898abb0f93cSkardel
189945530cf1Skardel if (ep->ignore_packets !=
190045530cf1Skardel enumep.ignore_packets) {
1901abb0f93cSkardel /*
1902abb0f93cSkardel * We have conflicting configurations
1903abb0f93cSkardel * for the interface address. This is
1904abb0f93cSkardel * caused by using -I <interfacename>
1905abb0f93cSkardel * for an interface that shares its
1906abb0f93cSkardel * address with other interfaces. We
1907abb0f93cSkardel * can not disambiguate incoming
1908abb0f93cSkardel * packets delivered to this socket
1909abb0f93cSkardel * without extra syscalls/features.
1910abb0f93cSkardel * These are not (commonly) available.
1911abb0f93cSkardel * Note this is a more unusual
1912abb0f93cSkardel * configuration where several
1913abb0f93cSkardel * interfaces share an address but
1914abb0f93cSkardel * filtering via interface name is
1915abb0f93cSkardel * attempted. We resolve the
1916abb0f93cSkardel * configuration conflict by disabling
1917abb0f93cSkardel * the processing of received packets.
1918abb0f93cSkardel * This leads to no service on the
1919abb0f93cSkardel * interface address where the conflict
1920abb0f93cSkardel * occurs.
1921abb0f93cSkardel */
1922abb0f93cSkardel msyslog(LOG_ERR,
1923abb0f93cSkardel "WARNING: conflicting enable configuration for interfaces %s and %s for address %s - unsupported configuration - address DISABLED",
192445530cf1Skardel enumep.name, ep->name,
192545530cf1Skardel stoa(&enumep.sin));
1926abb0f93cSkardel
192745530cf1Skardel ep->ignore_packets = ISC_TRUE;
1928abb0f93cSkardel }
1929abb0f93cSkardel
193045530cf1Skardel ep->phase = sys_interphase;
1931abb0f93cSkardel
1932abb0f93cSkardel ifi.action = IFS_EXISTS;
193345530cf1Skardel ifi.ep = ep;
1934abb0f93cSkardel if (receiver != NULL)
1935abb0f93cSkardel (*receiver)(data, &ifi);
1936abb0f93cSkardel } else {
1937abb0f93cSkardel /*
1938abb0f93cSkardel * This is new or refreshing failed - add to
1939abb0f93cSkardel * our interface list. If refreshing failed we
1940abb0f93cSkardel * will delete the interface structure in phase
1941abb0f93cSkardel * 2 as the interface was not marked current.
1942abb0f93cSkardel * We can bind to the address as the refresh
1943abb0f93cSkardel * code already closed the offending socket
1944abb0f93cSkardel */
194545530cf1Skardel ep = create_interface(port, &enumep);
1946abb0f93cSkardel
194745530cf1Skardel if (ep != NULL) {
1948abb0f93cSkardel ifi.action = IFS_CREATED;
194945530cf1Skardel ifi.ep = ep;
1950abb0f93cSkardel if (receiver != NULL)
1951abb0f93cSkardel (*receiver)(data, &ifi);
1952abb0f93cSkardel
195345530cf1Skardel new_interface_found = TRUE;
1954abb0f93cSkardel DPRINT_INTERFACE(3,
195545530cf1Skardel (ep, "updating ",
1956abb0f93cSkardel " new - created\n"));
1957abb0f93cSkardel } else {
1958abb0f93cSkardel DPRINT_INTERFACE(3,
195945530cf1Skardel (&enumep, "updating ",
1960abb0f93cSkardel " new - creation FAILED"));
1961abb0f93cSkardel
1962abb0f93cSkardel msyslog(LOG_INFO,
1963abb0f93cSkardel "failed to init interface for address %s",
196445530cf1Skardel stoa(&enumep.sin));
1965abb0f93cSkardel continue;
1966abb0f93cSkardel }
1967abb0f93cSkardel }
1968abb0f93cSkardel }
1969abb0f93cSkardel
1970abb0f93cSkardel isc_interfaceiter_destroy(&iter);
1971abb0f93cSkardel
1972abb0f93cSkardel /*
1973abb0f93cSkardel * phase 2 - delete gone interfaces - reassigning peers to
1974abb0f93cSkardel * other interfaces
1975abb0f93cSkardel */
197645530cf1Skardel for (ep = ep_list; ep != NULL; ep = next_ep) {
197745530cf1Skardel next_ep = ep->elink;
1978abb0f93cSkardel
1979abb0f93cSkardel /*
198045530cf1Skardel * if phase does not match sys_phase this interface was
198145530cf1Skardel * not enumerated during the last interface scan - so it
198245530cf1Skardel * is gone and will be deleted here unless it did not
198345530cf1Skardel * originate from interface enumeration (INT_WILDCARD,
198445530cf1Skardel * INT_MCASTIF).
1985abb0f93cSkardel */
198645530cf1Skardel if (((INT_WILDCARD | INT_MCASTIF) & ep->flags) ||
198745530cf1Skardel ep->phase == sys_interphase)
198845530cf1Skardel continue;
198945530cf1Skardel
199045530cf1Skardel DPRINT_INTERFACE(3, (ep, "updating ",
1991abb0f93cSkardel "GONE - deleting\n"));
199245530cf1Skardel remove_interface(ep);
1993abb0f93cSkardel
1994abb0f93cSkardel ifi.action = IFS_DELETED;
199545530cf1Skardel ifi.ep = ep;
1996abb0f93cSkardel if (receiver != NULL)
1997abb0f93cSkardel (*receiver)(data, &ifi);
1998abb0f93cSkardel
199945530cf1Skardel /* disconnect peers from deleted endpt. */
200045530cf1Skardel while (ep->peers != NULL)
200145530cf1Skardel set_peerdstadr(ep->peers, NULL);
2002abb0f93cSkardel
2003abb0f93cSkardel /*
2004abb0f93cSkardel * update globals in case we lose
2005abb0f93cSkardel * a loopback interface
2006abb0f93cSkardel */
200745530cf1Skardel if (ep == loopback_interface)
2008abb0f93cSkardel loopback_interface = NULL;
2009abb0f93cSkardel
201045530cf1Skardel delete_interface(ep);
2011abb0f93cSkardel }
2012abb0f93cSkardel
2013abb0f93cSkardel /*
2014b3d6264cSchristos * phase 3 - re-configure as the world has possibly changed
2015b3d6264cSchristos *
2016b3d6264cSchristos * never ever make this conditional again - it is needed to track
2017b3d6264cSchristos * routing updates. see bug #2506
2018abb0f93cSkardel */
2019abb0f93cSkardel refresh_all_peerinterfaces();
2020b3d6264cSchristos
20219034ec65Schristos if (broadcast_client_enabled || sys_bclient)
2022766d83b9Skardel io_setbclient();
2023766d83b9Skardel
202409f14f80Schristos #ifdef MCAST
20254e3b3909Schristos /*
20264e3b3909Schristos * Check multicast interfaces and try to join multicast groups if
20274e3b3909Schristos * not joined yet.
20284e3b3909Schristos */
20294e3b3909Schristos for (ep = ep_list; ep != NULL; ep = ep->elink) {
20304e3b3909Schristos remaddr_t *entry;
20314e3b3909Schristos
20324e3b3909Schristos if (!(INT_MCASTIF & ep->flags) || (INT_MCASTOPEN & ep->flags))
20334e3b3909Schristos continue;
20344e3b3909Schristos
20354e3b3909Schristos /* Find remote address that was linked to this interface */
20364e3b3909Schristos for (entry = remoteaddr_list;
20374e3b3909Schristos entry != NULL;
20384e3b3909Schristos entry = entry->link) {
20394e3b3909Schristos if (entry->ep == ep) {
20404e3b3909Schristos if (socket_multicast_enable(ep, &entry->addr)) {
20414e3b3909Schristos msyslog(LOG_INFO,
20424e3b3909Schristos "Joined %s socket to multicast group %s",
20434e3b3909Schristos stoa(&ep->sin),
20444e3b3909Schristos stoa(&entry->addr));
20454e3b3909Schristos }
20464e3b3909Schristos break;
20474e3b3909Schristos }
20484e3b3909Schristos }
20494e3b3909Schristos }
205009f14f80Schristos #endif /* MCAST */
20514e3b3909Schristos
2052abb0f93cSkardel return new_interface_found;
2053abb0f93cSkardel }
2054abb0f93cSkardel
2055abb0f93cSkardel
2056abb0f93cSkardel /*
2057abb0f93cSkardel * create_sockets - create a socket for each interface plus a default
2058abb0f93cSkardel * socket for when we don't know where to send
2059abb0f93cSkardel */
2060abb0f93cSkardel static int
create_sockets(u_short port)2061abb0f93cSkardel create_sockets(
2062abb0f93cSkardel u_short port
2063abb0f93cSkardel )
2064abb0f93cSkardel {
2065abb0f93cSkardel #ifndef HAVE_IO_COMPLETION_PORT
2066abb0f93cSkardel /*
2067abb0f93cSkardel * I/O Completion Ports don't care about the select and FD_SET
2068abb0f93cSkardel */
2069abb0f93cSkardel maxactivefd = 0;
2070abb0f93cSkardel FD_ZERO(&activefds);
2071abb0f93cSkardel #endif
2072abb0f93cSkardel
2073abb0f93cSkardel DPRINTF(2, ("create_sockets(%d)\n", port));
2074abb0f93cSkardel
2075abb0f93cSkardel create_wildcards(port);
2076abb0f93cSkardel
2077abb0f93cSkardel update_interfaces(port, NULL, NULL);
2078abb0f93cSkardel
2079abb0f93cSkardel /*
2080abb0f93cSkardel * Now that we have opened all the sockets, turn off the reuse
2081abb0f93cSkardel * flag for security.
2082abb0f93cSkardel */
2083abb0f93cSkardel set_reuseaddr(0);
2084abb0f93cSkardel
2085abb0f93cSkardel DPRINTF(2, ("create_sockets: Total interfaces = %d\n", ninterfaces));
2086abb0f93cSkardel
2087abb0f93cSkardel return ninterfaces;
2088abb0f93cSkardel }
2089abb0f93cSkardel
2090abb0f93cSkardel /*
2091abb0f93cSkardel * create_interface - create a new interface for a given prototype
2092abb0f93cSkardel * binding the socket.
2093abb0f93cSkardel */
2094abb0f93cSkardel static struct interface *
create_interface(u_short port,struct interface * protot)2095abb0f93cSkardel create_interface(
2096abb0f93cSkardel u_short port,
2097abb0f93cSkardel struct interface * protot
2098abb0f93cSkardel )
2099abb0f93cSkardel {
2100abb0f93cSkardel sockaddr_u resmask;
210145530cf1Skardel endpt * iface;
210245530cf1Skardel #if defined(MCAST) && defined(MULTICAST_NONEWSOCKET)
210345530cf1Skardel remaddr_t * entry;
210445530cf1Skardel remaddr_t * next_entry;
210545530cf1Skardel #endif
2106abb0f93cSkardel DPRINTF(2, ("create_interface(%s#%d)\n", stoa(&protot->sin),
2107abb0f93cSkardel port));
2108abb0f93cSkardel
2109abb0f93cSkardel /* build an interface */
2110abb0f93cSkardel iface = new_interface(protot);
2111abb0f93cSkardel
2112abb0f93cSkardel /*
2113abb0f93cSkardel * create socket
2114abb0f93cSkardel */
2115abb0f93cSkardel iface->fd = open_socket(&iface->sin, 0, 0, iface);
2116abb0f93cSkardel
2117abb0f93cSkardel if (iface->fd != INVALID_SOCKET)
211845530cf1Skardel log_listen_address(iface);
2119abb0f93cSkardel
2120abb0f93cSkardel if ((INT_BROADCAST & iface->flags)
2121abb0f93cSkardel && iface->bfd != INVALID_SOCKET)
2122abb0f93cSkardel msyslog(LOG_INFO, "Listening on broadcast address %s#%d",
2123abb0f93cSkardel stoa((&iface->bcast)), port);
2124abb0f93cSkardel
2125abb0f93cSkardel if (INVALID_SOCKET == iface->fd
2126abb0f93cSkardel && INVALID_SOCKET == iface->bfd) {
2127abb0f93cSkardel msyslog(LOG_ERR, "unable to create socket on %s (%d) for %s#%d",
2128abb0f93cSkardel iface->name,
2129abb0f93cSkardel iface->ifnum,
2130abb0f93cSkardel stoa((&iface->sin)),
2131abb0f93cSkardel port);
2132abb0f93cSkardel delete_interface(iface);
2133abb0f93cSkardel return NULL;
2134abb0f93cSkardel }
2135abb0f93cSkardel
2136abb0f93cSkardel /*
2137abb0f93cSkardel * Blacklist our own addresses, no use talking to ourself
2138abb0f93cSkardel */
2139abb0f93cSkardel SET_HOSTMASK(&resmask, AF(&iface->sin));
2140abb0f93cSkardel hack_restrict(RESTRICT_FLAGS, &iface->sin, &resmask,
2141169394abSchristos -4, RESM_NTPONLY | RESM_INTERFACE, RES_IGNORE, 0);
2142abb0f93cSkardel
2143abb0f93cSkardel /*
2144abb0f93cSkardel * set globals with the first found
2145abb0f93cSkardel * loopback interface of the appropriate class
2146abb0f93cSkardel */
2147abb0f93cSkardel if (NULL == loopback_interface && AF_INET == iface->family
2148abb0f93cSkardel && (INT_LOOPBACK & iface->flags))
2149abb0f93cSkardel loopback_interface = iface;
2150abb0f93cSkardel
2151abb0f93cSkardel /*
2152abb0f93cSkardel * put into our interface list
2153abb0f93cSkardel */
2154abb0f93cSkardel add_addr_to_list(&iface->sin, iface);
2155abb0f93cSkardel add_interface(iface);
2156abb0f93cSkardel
215745530cf1Skardel #if defined(MCAST) && defined(MULTICAST_NONEWSOCKET)
215845530cf1Skardel /*
215945530cf1Skardel * Join any previously-configured compatible multicast groups.
216045530cf1Skardel */
216145530cf1Skardel if (INT_MULTICAST & iface->flags &&
216245530cf1Skardel !((INT_LOOPBACK | INT_WILDCARD) & iface->flags) &&
216345530cf1Skardel !iface->ignore_packets) {
216445530cf1Skardel for (entry = remoteaddr_list;
216545530cf1Skardel entry != NULL;
216645530cf1Skardel entry = next_entry) {
216745530cf1Skardel next_entry = entry->link;
216845530cf1Skardel if (AF(&iface->sin) != AF(&entry->addr) ||
216945530cf1Skardel !IS_MCAST(&entry->addr))
217045530cf1Skardel continue;
217145530cf1Skardel if (socket_multicast_enable(iface,
217245530cf1Skardel &entry->addr))
217345530cf1Skardel msyslog(LOG_INFO,
217445530cf1Skardel "Joined %s socket to multicast group %s",
217545530cf1Skardel stoa(&iface->sin),
217645530cf1Skardel stoa(&entry->addr));
217745530cf1Skardel else
217845530cf1Skardel msyslog(LOG_ERR,
217945530cf1Skardel "Failed to join %s socket to multicast group %s",
218045530cf1Skardel stoa(&iface->sin),
218145530cf1Skardel stoa(&entry->addr));
218245530cf1Skardel }
218345530cf1Skardel }
218445530cf1Skardel #endif /* MCAST && MCAST_NONEWSOCKET */
218545530cf1Skardel
2186abb0f93cSkardel DPRINT_INTERFACE(2, (iface, "created ", "\n"));
2187abb0f93cSkardel return iface;
2188abb0f93cSkardel }
2189abb0f93cSkardel
2190abb0f93cSkardel
2191abb0f93cSkardel #ifdef SO_EXCLUSIVEADDRUSE
2192abb0f93cSkardel static void
set_excladdruse(SOCKET fd)2193abb0f93cSkardel set_excladdruse(
2194abb0f93cSkardel SOCKET fd
2195abb0f93cSkardel )
2196abb0f93cSkardel {
2197abb0f93cSkardel int one = 1;
2198abb0f93cSkardel int failed;
2199abb0f93cSkardel #ifdef SYS_WINNT
2200abb0f93cSkardel DWORD err;
2201abb0f93cSkardel #endif
2202abb0f93cSkardel
2203abb0f93cSkardel failed = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
2204169394abSchristos (void *)&one, sizeof(one));
2205abb0f93cSkardel
2206abb0f93cSkardel if (!failed)
2207abb0f93cSkardel return;
2208abb0f93cSkardel
2209abb0f93cSkardel #ifdef SYS_WINNT
2210abb0f93cSkardel /*
2211abb0f93cSkardel * Prior to Windows XP setting SO_EXCLUSIVEADDRUSE can fail with
2212abb0f93cSkardel * error WSAINVAL depending on service pack level and whether
2213abb0f93cSkardel * the user account is in the Administrators group. Do not
2214abb0f93cSkardel * complain if it fails that way on versions prior to XP (5.1).
2215abb0f93cSkardel */
2216abb0f93cSkardel err = GetLastError();
2217abb0f93cSkardel
2218abb0f93cSkardel if (isc_win32os_versioncheck(5, 1, 0, 0) < 0 /* < 5.1/XP */
2219abb0f93cSkardel && WSAEINVAL == err)
2220abb0f93cSkardel return;
2221abb0f93cSkardel
2222abb0f93cSkardel SetLastError(err);
2223abb0f93cSkardel #endif
2224abb0f93cSkardel msyslog(LOG_ERR,
2225abb0f93cSkardel "setsockopt(%d, SO_EXCLUSIVEADDRUSE, on): %m",
2226abb0f93cSkardel (int)fd);
2227abb0f93cSkardel }
2228abb0f93cSkardel #endif /* SO_EXCLUSIVEADDRUSE */
2229abb0f93cSkardel
2230abb0f93cSkardel
2231abb0f93cSkardel /*
2232abb0f93cSkardel * set_reuseaddr() - set/clear REUSEADDR on all sockets
2233abb0f93cSkardel * NB possible hole - should we be doing this on broadcast
2234abb0f93cSkardel * fd's also?
2235abb0f93cSkardel */
2236abb0f93cSkardel static void
set_reuseaddr(int flag)2237abb0f93cSkardel set_reuseaddr(
2238abb0f93cSkardel int flag
2239abb0f93cSkardel )
2240abb0f93cSkardel {
2241abb0f93cSkardel #ifndef SO_EXCLUSIVEADDRUSE
224245530cf1Skardel endpt *ep;
2243abb0f93cSkardel
224445530cf1Skardel for (ep = ep_list; ep != NULL; ep = ep->elink) {
224545530cf1Skardel if (ep->flags & INT_WILDCARD)
2246abb0f93cSkardel continue;
2247abb0f93cSkardel
2248abb0f93cSkardel /*
224945530cf1Skardel * if ep->fd is INVALID_SOCKET, we might have a adapter
2250abb0f93cSkardel * configured but not present
2251abb0f93cSkardel */
2252abb0f93cSkardel DPRINTF(4, ("setting SO_REUSEADDR on %.16s@%s to %s\n",
225345530cf1Skardel ep->name, stoa(&ep->sin),
2254abb0f93cSkardel flag ? "on" : "off"));
2255abb0f93cSkardel
225645530cf1Skardel if (ep->fd != INVALID_SOCKET) {
225745530cf1Skardel if (setsockopt(ep->fd, SOL_SOCKET, SO_REUSEADDR,
2258169394abSchristos (void *)&flag, sizeof(flag))) {
225945530cf1Skardel msyslog(LOG_ERR, "set_reuseaddr: setsockopt(%s, SO_REUSEADDR, %s) failed: %m",
226045530cf1Skardel stoa(&ep->sin), flag ? "on" : "off");
2261abb0f93cSkardel }
2262abb0f93cSkardel }
2263abb0f93cSkardel }
2264abb0f93cSkardel #endif /* ! SO_EXCLUSIVEADDRUSE */
2265abb0f93cSkardel }
2266abb0f93cSkardel
2267abb0f93cSkardel /*
2268abb0f93cSkardel * This is just a wrapper around an internal function so we can
2269abb0f93cSkardel * make other changes as necessary later on
2270abb0f93cSkardel */
2271abb0f93cSkardel void
enable_broadcast(struct interface * iface,sockaddr_u * baddr)2272abb0f93cSkardel enable_broadcast(
2273abb0f93cSkardel struct interface * iface,
2274abb0f93cSkardel sockaddr_u * baddr
2275abb0f93cSkardel )
2276abb0f93cSkardel {
2277abb0f93cSkardel #ifdef OPEN_BCAST_SOCKET
2278abb0f93cSkardel socket_broadcast_enable(iface, iface->fd, baddr);
2279abb0f93cSkardel #endif
2280abb0f93cSkardel }
2281abb0f93cSkardel
2282abb0f93cSkardel #ifdef OPEN_BCAST_SOCKET
2283abb0f93cSkardel /*
2284abb0f93cSkardel * Enable a broadcast address to a given socket
2285b3d6264cSchristos * The socket is in the ep_list all we need to do is enable
2286abb0f93cSkardel * broadcasting. It is not this function's job to select the socket
2287abb0f93cSkardel */
2288abb0f93cSkardel static isc_boolean_t
socket_broadcast_enable(struct interface * iface,SOCKET fd,sockaddr_u * baddr)2289abb0f93cSkardel socket_broadcast_enable(
2290abb0f93cSkardel struct interface * iface,
2291abb0f93cSkardel SOCKET fd,
2292abb0f93cSkardel sockaddr_u * baddr
2293abb0f93cSkardel )
2294abb0f93cSkardel {
2295abb0f93cSkardel #ifdef SO_BROADCAST
2296abb0f93cSkardel int on = 1;
2297abb0f93cSkardel
2298abb0f93cSkardel if (IS_IPV4(baddr)) {
2299abb0f93cSkardel /* if this interface can support broadcast, set SO_BROADCAST */
2300abb0f93cSkardel if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
2301169394abSchristos (void *)&on, sizeof(on)))
2302abb0f93cSkardel msyslog(LOG_ERR,
2303abb0f93cSkardel "setsockopt(SO_BROADCAST) enable failure on address %s: %m",
2304abb0f93cSkardel stoa(baddr));
2305abb0f93cSkardel else
2306abb0f93cSkardel DPRINTF(2, ("Broadcast enabled on socket %d for address %s\n",
2307abb0f93cSkardel fd, stoa(baddr)));
2308abb0f93cSkardel }
2309b3d6264cSchristos iface->flags |= INT_BCASTXMIT;
2310abb0f93cSkardel return ISC_TRUE;
2311abb0f93cSkardel #else
2312abb0f93cSkardel return ISC_FALSE;
2313abb0f93cSkardel #endif /* SO_BROADCAST */
2314abb0f93cSkardel }
2315abb0f93cSkardel
2316ad131110Schristos #ifdef OS_MISSES_SPECIFIC_ROUTE_UPDATES
2317abb0f93cSkardel /*
2318abb0f93cSkardel * Remove a broadcast address from a given socket
2319b3d6264cSchristos * The socket is in the ep_list all we need to do is disable
2320abb0f93cSkardel * broadcasting. It is not this function's job to select the socket
2321abb0f93cSkardel */
2322abb0f93cSkardel static isc_boolean_t
socket_broadcast_disable(struct interface * iface,sockaddr_u * baddr)2323abb0f93cSkardel socket_broadcast_disable(
2324abb0f93cSkardel struct interface * iface,
2325abb0f93cSkardel sockaddr_u * baddr
2326abb0f93cSkardel )
2327abb0f93cSkardel {
2328abb0f93cSkardel #ifdef SO_BROADCAST
2329abb0f93cSkardel int off = 0; /* This seems to be OK as an int */
2330abb0f93cSkardel
2331abb0f93cSkardel if (IS_IPV4(baddr) && setsockopt(iface->fd, SOL_SOCKET,
2332169394abSchristos SO_BROADCAST, (void *)&off, sizeof(off)))
2333abb0f93cSkardel msyslog(LOG_ERR,
2334abb0f93cSkardel "setsockopt(SO_BROADCAST) disable failure on address %s: %m",
2335abb0f93cSkardel stoa(baddr));
2336abb0f93cSkardel
2337b3d6264cSchristos iface->flags &= ~INT_BCASTXMIT;
2338abb0f93cSkardel return ISC_TRUE;
2339abb0f93cSkardel #else
2340abb0f93cSkardel return ISC_FALSE;
2341abb0f93cSkardel #endif /* SO_BROADCAST */
2342abb0f93cSkardel }
2343ad131110Schristos #endif /* OS_MISSES_SPECIFIC_ROUTE_UPDATES */
2344abb0f93cSkardel
2345abb0f93cSkardel #endif /* OPEN_BCAST_SOCKET */
2346abb0f93cSkardel
2347abb0f93cSkardel /*
2348abb0f93cSkardel * return the broadcast client flag value
2349abb0f93cSkardel */
23509034ec65Schristos /*isc_boolean_t
2351abb0f93cSkardel get_broadcastclient_flag(void)
2352abb0f93cSkardel {
2353abb0f93cSkardel return (broadcast_client_enabled);
2354abb0f93cSkardel }
23559034ec65Schristos */
2356335f7552Schristos
2357abb0f93cSkardel /*
2358abb0f93cSkardel * Check to see if the address is a multicast address
2359abb0f93cSkardel */
2360abb0f93cSkardel static isc_boolean_t
addr_ismulticast(sockaddr_u * maddr)2361abb0f93cSkardel addr_ismulticast(
2362abb0f93cSkardel sockaddr_u *maddr
2363abb0f93cSkardel )
2364abb0f93cSkardel {
2365abb0f93cSkardel isc_boolean_t result;
2366abb0f93cSkardel
2367abb0f93cSkardel #ifndef INCLUDE_IPV6_MULTICAST_SUPPORT
2368abb0f93cSkardel /*
2369abb0f93cSkardel * If we don't have IPV6 support any IPV6 addr is not multicast
2370abb0f93cSkardel */
2371abb0f93cSkardel if (IS_IPV6(maddr))
2372abb0f93cSkardel result = ISC_FALSE;
2373abb0f93cSkardel else
2374abb0f93cSkardel #endif
2375abb0f93cSkardel result = IS_MCAST(maddr);
2376abb0f93cSkardel
2377abb0f93cSkardel if (!result)
2378abb0f93cSkardel DPRINTF(4, ("address %s is not multicast\n",
2379abb0f93cSkardel stoa(maddr)));
2380abb0f93cSkardel
2381abb0f93cSkardel return result;
2382abb0f93cSkardel }
2383abb0f93cSkardel
2384abb0f93cSkardel /*
2385abb0f93cSkardel * Multicast servers need to set the appropriate Multicast interface
2386abb0f93cSkardel * socket option in order for it to know which interface to use for
2387abb0f93cSkardel * send the multicast packet.
2388abb0f93cSkardel */
2389abb0f93cSkardel void
enable_multicast_if(struct interface * iface,sockaddr_u * maddr)2390abb0f93cSkardel enable_multicast_if(
2391abb0f93cSkardel struct interface * iface,
2392abb0f93cSkardel sockaddr_u * maddr
2393abb0f93cSkardel )
2394abb0f93cSkardel {
2395abb0f93cSkardel #ifdef MCAST
2396b3d6264cSchristos #ifdef IP_MULTICAST_LOOP
2397abb0f93cSkardel TYPEOF_IP_MULTICAST_LOOP off = 0;
2398b3d6264cSchristos #endif
239970953dd2Sprlw1 #if defined(INCLUDE_IPV6_MULTICAST_SUPPORT) && defined(IPV6_MULTICAST_LOOP)
2400b3d6264cSchristos u_int off6 = 0;
2401b3d6264cSchristos #endif
2402abb0f93cSkardel
240309f14f80Schristos REQUIRE(AF(maddr) == AF(&iface->sin));
2404abb0f93cSkardel
2405abb0f93cSkardel switch (AF(&iface->sin)) {
2406abb0f93cSkardel
2407abb0f93cSkardel case AF_INET:
2408abb0f93cSkardel #ifdef IP_MULTICAST_LOOP
2409abb0f93cSkardel /*
2410abb0f93cSkardel * Don't send back to itself, but allow failure to set
2411abb0f93cSkardel */
2412abb0f93cSkardel if (setsockopt(iface->fd, IPPROTO_IP,
2413abb0f93cSkardel IP_MULTICAST_LOOP,
2414169394abSchristos (void *)&off,
2415abb0f93cSkardel sizeof(off))) {
2416abb0f93cSkardel
2417abb0f93cSkardel msyslog(LOG_ERR,
2418abb0f93cSkardel "setsockopt IP_MULTICAST_LOOP failed: %m on socket %d, addr %s for multicast address %s",
2419abb0f93cSkardel iface->fd, stoa(&iface->sin),
2420abb0f93cSkardel stoa(maddr));
2421abb0f93cSkardel }
2422abb0f93cSkardel #endif
2423abb0f93cSkardel break;
2424abb0f93cSkardel
2425abb0f93cSkardel case AF_INET6:
2426abb0f93cSkardel #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
2427abb0f93cSkardel #ifdef IPV6_MULTICAST_LOOP
2428abb0f93cSkardel /*
2429abb0f93cSkardel * Don't send back to itself, but allow failure to set
2430abb0f93cSkardel */
2431abb0f93cSkardel if (setsockopt(iface->fd, IPPROTO_IPV6,
2432abb0f93cSkardel IPV6_MULTICAST_LOOP,
2433169394abSchristos (void *) &off6, sizeof(off6))) {
2434abb0f93cSkardel
2435abb0f93cSkardel msyslog(LOG_ERR,
2436b3d6264cSchristos "setsockopt IPV6_MULTICAST_LOOP failed: %m on socket %d, addr %s for multicast address %s",
2437abb0f93cSkardel iface->fd, stoa(&iface->sin),
2438abb0f93cSkardel stoa(maddr));
2439abb0f93cSkardel }
2440abb0f93cSkardel #endif
2441abb0f93cSkardel break;
2442abb0f93cSkardel #else
2443abb0f93cSkardel return;
2444abb0f93cSkardel #endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */
2445abb0f93cSkardel }
2446abb0f93cSkardel return;
2447abb0f93cSkardel #endif
2448abb0f93cSkardel }
2449abb0f93cSkardel
2450abb0f93cSkardel /*
2451abb0f93cSkardel * Add a multicast address to a given socket
2452b3d6264cSchristos * The socket is in the ep_list all we need to do is enable
2453abb0f93cSkardel * multicasting. It is not this function's job to select the socket
2454abb0f93cSkardel */
245545530cf1Skardel #if defined(MCAST)
2456abb0f93cSkardel static isc_boolean_t
socket_multicast_enable(endpt * iface,sockaddr_u * maddr)2457abb0f93cSkardel socket_multicast_enable(
245845530cf1Skardel endpt * iface,
2459abb0f93cSkardel sockaddr_u * maddr
2460abb0f93cSkardel )
2461abb0f93cSkardel {
2462abb0f93cSkardel struct ip_mreq mreq;
2463abb0f93cSkardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
2464abb0f93cSkardel struct ipv6_mreq mreq6;
2465abb0f93cSkardel # endif
2466abb0f93cSkardel switch (AF(maddr)) {
2467abb0f93cSkardel
2468abb0f93cSkardel case AF_INET:
2469b3d6264cSchristos ZERO(mreq);
2470abb0f93cSkardel mreq.imr_multiaddr = SOCK_ADDR4(maddr);
2471abb0f93cSkardel mreq.imr_interface.s_addr = htonl(INADDR_ANY);
2472abb0f93cSkardel if (setsockopt(iface->fd,
2473abb0f93cSkardel IPPROTO_IP,
2474abb0f93cSkardel IP_ADD_MEMBERSHIP,
2475169394abSchristos (void *)&mreq,
2476abb0f93cSkardel sizeof(mreq))) {
24774e3b3909Schristos DPRINTF(2, (
2478abb0f93cSkardel "setsockopt IP_ADD_MEMBERSHIP failed: %m on socket %d, addr %s for %x / %x (%s)",
2479abb0f93cSkardel iface->fd, stoa(&iface->sin),
2480abb0f93cSkardel mreq.imr_multiaddr.s_addr,
2481abb0f93cSkardel mreq.imr_interface.s_addr,
24824e3b3909Schristos stoa(maddr)));
2483abb0f93cSkardel return ISC_FALSE;
2484abb0f93cSkardel }
2485abb0f93cSkardel DPRINTF(4, ("Added IPv4 multicast membership on socket %d, addr %s for %x / %x (%s)\n",
2486abb0f93cSkardel iface->fd, stoa(&iface->sin),
2487abb0f93cSkardel mreq.imr_multiaddr.s_addr,
2488abb0f93cSkardel mreq.imr_interface.s_addr, stoa(maddr)));
2489abb0f93cSkardel break;
2490abb0f93cSkardel
2491abb0f93cSkardel case AF_INET6:
2492abb0f93cSkardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
2493abb0f93cSkardel /*
2494abb0f93cSkardel * Enable reception of multicast packets.
2495abb0f93cSkardel * If the address is link-local we can get the
2496abb0f93cSkardel * interface index from the scope id. Don't do this
2497abb0f93cSkardel * for other types of multicast addresses. For now let
2498abb0f93cSkardel * the kernel figure it out.
2499abb0f93cSkardel */
2500b3d6264cSchristos ZERO(mreq6);
2501abb0f93cSkardel mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr);
250245530cf1Skardel mreq6.ipv6mr_interface = iface->ifindex;
2503abb0f93cSkardel
2504abb0f93cSkardel if (setsockopt(iface->fd, IPPROTO_IPV6,
2505169394abSchristos IPV6_JOIN_GROUP, (void *)&mreq6,
2506abb0f93cSkardel sizeof(mreq6))) {
25074e3b3909Schristos DPRINTF(2, (
250845530cf1Skardel "setsockopt IPV6_JOIN_GROUP failed: %m on socket %d, addr %s for interface %u (%s)",
2509abb0f93cSkardel iface->fd, stoa(&iface->sin),
25104e3b3909Schristos mreq6.ipv6mr_interface, stoa(maddr)));
2511abb0f93cSkardel return ISC_FALSE;
2512abb0f93cSkardel }
251345530cf1Skardel DPRINTF(4, ("Added IPv6 multicast group on socket %d, addr %s for interface %u (%s)\n",
2514abb0f93cSkardel iface->fd, stoa(&iface->sin),
2515abb0f93cSkardel mreq6.ipv6mr_interface, stoa(maddr)));
2516abb0f93cSkardel # else
2517abb0f93cSkardel return ISC_FALSE;
2518abb0f93cSkardel # endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */
2519abb0f93cSkardel }
2520abb0f93cSkardel iface->flags |= INT_MCASTOPEN;
2521abb0f93cSkardel iface->num_mcast++;
252245530cf1Skardel
2523abb0f93cSkardel return ISC_TRUE;
2524abb0f93cSkardel }
252545530cf1Skardel #endif /* MCAST */
252645530cf1Skardel
2527abb0f93cSkardel
2528abb0f93cSkardel /*
2529abb0f93cSkardel * Remove a multicast address from a given socket
2530b3d6264cSchristos * The socket is in the ep_list all we need to do is disable
2531abb0f93cSkardel * multicasting. It is not this function's job to select the socket
2532abb0f93cSkardel */
253345530cf1Skardel #ifdef MCAST
2534abb0f93cSkardel static isc_boolean_t
socket_multicast_disable(struct interface * iface,sockaddr_u * maddr)2535abb0f93cSkardel socket_multicast_disable(
2536abb0f93cSkardel struct interface * iface,
2537abb0f93cSkardel sockaddr_u * maddr
2538abb0f93cSkardel )
2539abb0f93cSkardel {
2540abb0f93cSkardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
2541abb0f93cSkardel struct ipv6_mreq mreq6;
2542abb0f93cSkardel # endif
2543abb0f93cSkardel struct ip_mreq mreq;
2544abb0f93cSkardel
2545b3d6264cSchristos ZERO(mreq);
2546abb0f93cSkardel
2547abb0f93cSkardel if (find_addr_in_list(maddr) == NULL) {
2548abb0f93cSkardel DPRINTF(4, ("socket_multicast_disable(%s): not found\n",
2549abb0f93cSkardel stoa(maddr)));
2550abb0f93cSkardel return ISC_TRUE;
2551abb0f93cSkardel }
2552abb0f93cSkardel
2553abb0f93cSkardel switch (AF(maddr)) {
2554abb0f93cSkardel
2555abb0f93cSkardel case AF_INET:
2556abb0f93cSkardel mreq.imr_multiaddr = SOCK_ADDR4(maddr);
2557abb0f93cSkardel mreq.imr_interface = SOCK_ADDR4(&iface->sin);
2558abb0f93cSkardel if (setsockopt(iface->fd, IPPROTO_IP,
2559169394abSchristos IP_DROP_MEMBERSHIP, (void *)&mreq,
2560abb0f93cSkardel sizeof(mreq))) {
2561abb0f93cSkardel
2562abb0f93cSkardel msyslog(LOG_ERR,
2563abb0f93cSkardel "setsockopt IP_DROP_MEMBERSHIP failed: %m on socket %d, addr %s for %x / %x (%s)",
2564abb0f93cSkardel iface->fd, stoa(&iface->sin),
2565abb0f93cSkardel SRCADR(maddr), SRCADR(&iface->sin),
2566abb0f93cSkardel stoa(maddr));
2567abb0f93cSkardel return ISC_FALSE;
2568abb0f93cSkardel }
2569abb0f93cSkardel break;
2570abb0f93cSkardel case AF_INET6:
2571abb0f93cSkardel # ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
2572abb0f93cSkardel /*
2573abb0f93cSkardel * Disable reception of multicast packets
2574abb0f93cSkardel * If the address is link-local we can get the
2575abb0f93cSkardel * interface index from the scope id. Don't do this
2576abb0f93cSkardel * for other types of multicast addresses. For now let
2577abb0f93cSkardel * the kernel figure it out.
2578abb0f93cSkardel */
2579abb0f93cSkardel mreq6.ipv6mr_multiaddr = SOCK_ADDR6(maddr);
258045530cf1Skardel mreq6.ipv6mr_interface = iface->ifindex;
2581abb0f93cSkardel
2582abb0f93cSkardel if (setsockopt(iface->fd, IPPROTO_IPV6,
2583169394abSchristos IPV6_LEAVE_GROUP, (void *)&mreq6,
2584abb0f93cSkardel sizeof(mreq6))) {
2585abb0f93cSkardel
2586abb0f93cSkardel msyslog(LOG_ERR,
2587abb0f93cSkardel "setsockopt IPV6_LEAVE_GROUP failure: %m on socket %d, addr %s for %d (%s)",
2588abb0f93cSkardel iface->fd, stoa(&iface->sin),
258945530cf1Skardel iface->ifindex, stoa(maddr));
2590abb0f93cSkardel return ISC_FALSE;
2591abb0f93cSkardel }
2592abb0f93cSkardel break;
2593abb0f93cSkardel # else
2594abb0f93cSkardel return ISC_FALSE;
2595abb0f93cSkardel # endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */
2596abb0f93cSkardel }
2597abb0f93cSkardel
2598abb0f93cSkardel iface->num_mcast--;
2599abb0f93cSkardel if (!iface->num_mcast)
2600abb0f93cSkardel iface->flags &= ~INT_MCASTOPEN;
2601abb0f93cSkardel
2602abb0f93cSkardel return ISC_TRUE;
2603abb0f93cSkardel }
2604abb0f93cSkardel #endif /* MCAST */
2605abb0f93cSkardel
2606abb0f93cSkardel /*
2607abb0f93cSkardel * io_setbclient - open the broadcast client sockets
2608abb0f93cSkardel */
2609abb0f93cSkardel void
io_setbclient(void)2610abb0f93cSkardel io_setbclient(void)
2611abb0f93cSkardel {
2612abb0f93cSkardel #ifdef OPEN_BCAST_SOCKET
26139034ec65Schristos endpt * ep;
26149034ec65Schristos unsigned int nif, ni4, ni6;
2615abb0f93cSkardel
26169034ec65Schristos nif = ni4 = ni6 = 0;
2617abb0f93cSkardel set_reuseaddr(1);
2618abb0f93cSkardel
26199034ec65Schristos for (ep = ep_list; ep != NULL; ep = ep->elink) {
26209034ec65Schristos /* count IPv6 vs IPv4 interfaces. Needed later to decide
26219034ec65Schristos * if we should log an error or not.
26229034ec65Schristos */
26239034ec65Schristos switch (ep->family) {
26249034ec65Schristos case AF_INET : ++ni4; break;
26259034ec65Schristos case AF_INET6: ++ni6; break;
26269034ec65Schristos default : break;
26279034ec65Schristos }
2628abb0f93cSkardel
26299034ec65Schristos if (ep->flags & (INT_WILDCARD | INT_LOOPBACK))
2630abb0f93cSkardel continue;
2631abb0f93cSkardel
2632abb0f93cSkardel /* use only allowed addresses */
26339034ec65Schristos if (ep->ignore_packets)
2634abb0f93cSkardel continue;
2635abb0f93cSkardel
2636abb0f93cSkardel /* Need a broadcast-capable interface */
26379034ec65Schristos if (!(ep->flags & INT_BROADCAST))
2638abb0f93cSkardel continue;
2639abb0f93cSkardel
2640abb0f93cSkardel /* Only IPv4 addresses are valid for broadcast */
26419034ec65Schristos REQUIRE(IS_IPV4(&ep->bcast));
2642abb0f93cSkardel
2643abb0f93cSkardel /* Do we already have the broadcast address open? */
26449034ec65Schristos if (ep->flags & INT_BCASTOPEN) {
2645abb0f93cSkardel /*
2646abb0f93cSkardel * account for already open interfaces to avoid
2647abb0f93cSkardel * misleading warning below
2648abb0f93cSkardel */
2649abb0f93cSkardel nif++;
2650abb0f93cSkardel continue;
2651abb0f93cSkardel }
2652abb0f93cSkardel
2653abb0f93cSkardel /*
2654abb0f93cSkardel * Try to open the broadcast address
2655abb0f93cSkardel */
26569034ec65Schristos ep->family = AF_INET;
26579034ec65Schristos ep->bfd = open_socket(&ep->bcast, 1, 0, ep);
2658abb0f93cSkardel
2659abb0f93cSkardel /*
2660abb0f93cSkardel * If we succeeded then we use it otherwise enable
2661abb0f93cSkardel * broadcast on the interface address
2662abb0f93cSkardel */
26639034ec65Schristos if (ep->bfd != INVALID_SOCKET) {
2664abb0f93cSkardel nif++;
26659034ec65Schristos ep->flags |= INT_BCASTOPEN;
2666abb0f93cSkardel msyslog(LOG_INFO,
2667b3d6264cSchristos "Listen for broadcasts to %s on interface #%d %s",
26689034ec65Schristos stoa(&ep->bcast), ep->ifnum, ep->name);
2669335f7552Schristos } else switch (errno) {
2670335f7552Schristos /* Silently ignore EADDRINUSE as we probably
2671335f7552Schristos * opened the socket already for an address in
2672335f7552Schristos * the same network */
2673335f7552Schristos case EADDRINUSE:
2674335f7552Schristos /* Some systems cannot bind a socket to a broadcast
2675335f7552Schristos * address, as that is not a valid host address. */
2676335f7552Schristos case EADDRNOTAVAIL:
2677335f7552Schristos # ifdef SYS_WINNT /*TODO: use for other systems, too? */
2678335f7552Schristos /* avoid recurrence here -- if we already have a
2679335f7552Schristos * regular socket, it's quite useless to try this
2680335f7552Schristos * again.
2681335f7552Schristos */
26829034ec65Schristos if (ep->fd != INVALID_SOCKET) {
26839034ec65Schristos ep->flags |= INT_BCASTOPEN;
2684335f7552Schristos nif++;
2685335f7552Schristos }
2686335f7552Schristos # endif
2687335f7552Schristos break;
2688335f7552Schristos
2689335f7552Schristos default:
2690b3d6264cSchristos msyslog(LOG_INFO,
2691b3d6264cSchristos "failed to listen for broadcasts to %s on interface #%d %s",
26929034ec65Schristos stoa(&ep->bcast), ep->ifnum, ep->name);
2693335f7552Schristos break;
2694abb0f93cSkardel }
2695abb0f93cSkardel }
2696abb0f93cSkardel set_reuseaddr(0);
26971c24ec91Schristos if (nif != 0) {
2698b3d6264cSchristos broadcast_client_enabled = ISC_TRUE;
2699b3d6264cSchristos DPRINTF(1, ("io_setbclient: listening to %d broadcast addresses\n", nif));
27001c24ec91Schristos } else {
2701b3d6264cSchristos broadcast_client_enabled = ISC_FALSE;
27029034ec65Schristos /* This is expected when having only IPv6 interfaces
27039034ec65Schristos * and no IPv4 interfaces at all. We suppress the error
27049034ec65Schristos * log in that case... everything else should work!
27059034ec65Schristos */
27069034ec65Schristos if (ni4 && !ni6) {
2707abb0f93cSkardel msyslog(LOG_ERR,
2708abb0f93cSkardel "Unable to listen for broadcasts, no broadcast interfaces available");
2709b3d6264cSchristos }
27109034ec65Schristos }
2711abb0f93cSkardel #else
2712abb0f93cSkardel msyslog(LOG_ERR,
2713abb0f93cSkardel "io_setbclient: Broadcast Client disabled by build");
2714abb0f93cSkardel #endif /* OPEN_BCAST_SOCKET */
2715abb0f93cSkardel }
2716abb0f93cSkardel
2717abb0f93cSkardel /*
2718abb0f93cSkardel * io_unsetbclient - close the broadcast client sockets
2719abb0f93cSkardel */
2720abb0f93cSkardel void
io_unsetbclient(void)2721abb0f93cSkardel io_unsetbclient(void)
2722abb0f93cSkardel {
272345530cf1Skardel endpt *ep;
2724abb0f93cSkardel
272545530cf1Skardel for (ep = ep_list; ep != NULL; ep = ep->elink) {
272645530cf1Skardel if (INT_WILDCARD & ep->flags)
2727abb0f93cSkardel continue;
272845530cf1Skardel if (!(INT_BCASTOPEN & ep->flags))
2729abb0f93cSkardel continue;
2730b3d6264cSchristos
2731b3d6264cSchristos if (ep->bfd != INVALID_SOCKET) {
2732b3d6264cSchristos /* destroy broadcast listening socket */
2733b3d6264cSchristos msyslog(LOG_INFO,
2734b3d6264cSchristos "stop listening for broadcasts to %s on interface #%d %s",
2735b3d6264cSchristos stoa(&ep->bcast), ep->ifnum, ep->name);
2736335f7552Schristos # ifdef HAVE_IO_COMPLETION_PORT
2737335f7552Schristos io_completion_port_remove_socket(ep->bfd, ep);
2738335f7552Schristos # endif
2739b3d6264cSchristos close_and_delete_fd_from_list(ep->bfd);
2740b3d6264cSchristos ep->bfd = INVALID_SOCKET;
2741abb0f93cSkardel }
2742335f7552Schristos ep->flags &= ~INT_BCASTOPEN;
2743abb0f93cSkardel }
2744b3d6264cSchristos broadcast_client_enabled = ISC_FALSE;
2745b3d6264cSchristos }
2746abb0f93cSkardel
2747abb0f93cSkardel /*
2748abb0f93cSkardel * io_multicast_add() - add multicast group address
2749abb0f93cSkardel */
2750abb0f93cSkardel void
io_multicast_add(sockaddr_u * addr)2751abb0f93cSkardel io_multicast_add(
2752abb0f93cSkardel sockaddr_u *addr
2753abb0f93cSkardel )
2754abb0f93cSkardel {
2755abb0f93cSkardel #ifdef MCAST
275645530cf1Skardel endpt * ep;
275745530cf1Skardel endpt * one_ep;
2758abb0f93cSkardel
2759abb0f93cSkardel /*
2760abb0f93cSkardel * Check to see if this is a multicast address
2761abb0f93cSkardel */
2762abb0f93cSkardel if (!addr_ismulticast(addr))
2763abb0f93cSkardel return;
2764abb0f93cSkardel
2765abb0f93cSkardel /* If we already have it we can just return */
2766abb0f93cSkardel if (NULL != find_flagged_addr_in_list(addr, INT_MCASTOPEN)) {
2767abb0f93cSkardel msyslog(LOG_INFO,
2768abb0f93cSkardel "Duplicate request found for multicast address %s",
2769abb0f93cSkardel stoa(addr));
2770abb0f93cSkardel return;
2771abb0f93cSkardel }
2772abb0f93cSkardel
2773abb0f93cSkardel # ifndef MULTICAST_NONEWSOCKET
277445530cf1Skardel ep = new_interface(NULL);
2775abb0f93cSkardel
2776abb0f93cSkardel /*
2777abb0f93cSkardel * Open a new socket for the multicast address
2778abb0f93cSkardel */
277945530cf1Skardel ep->sin = *addr;
278045530cf1Skardel SET_PORT(&ep->sin, NTP_PORT);
278145530cf1Skardel ep->family = AF(&ep->sin);
278245530cf1Skardel AF(&ep->mask) = ep->family;
278345530cf1Skardel SET_ONESMASK(&ep->mask);
2784abb0f93cSkardel
2785abb0f93cSkardel set_reuseaddr(1);
278645530cf1Skardel ep->bfd = INVALID_SOCKET;
278745530cf1Skardel ep->fd = open_socket(&ep->sin, 0, 0, ep);
278845530cf1Skardel if (ep->fd != INVALID_SOCKET) {
278945530cf1Skardel ep->ignore_packets = ISC_FALSE;
279045530cf1Skardel ep->flags |= INT_MCASTIF;
2791169394abSchristos ep->ifindex = SCOPE(addr);
2792abb0f93cSkardel
2793b3d6264cSchristos strlcpy(ep->name, "multicast", sizeof(ep->name));
279445530cf1Skardel DPRINT_INTERFACE(2, (ep, "multicast add ", "\n"));
279545530cf1Skardel add_interface(ep);
279645530cf1Skardel log_listen_address(ep);
2797abb0f93cSkardel } else {
2798abb0f93cSkardel /* bind failed, re-use wildcard interface */
279945530cf1Skardel delete_interface(ep);
2800abb0f93cSkardel
2801abb0f93cSkardel if (IS_IPV4(addr))
280245530cf1Skardel ep = wildipv4;
2803abb0f93cSkardel else if (IS_IPV6(addr))
280445530cf1Skardel ep = wildipv6;
2805abb0f93cSkardel else
280645530cf1Skardel ep = NULL;
2807abb0f93cSkardel
280845530cf1Skardel if (ep != NULL) {
2809abb0f93cSkardel /* HACK ! -- stuff in an address */
2810abb0f93cSkardel /* because we don't bind addr? DH */
281145530cf1Skardel ep->bcast = *addr;
2812abb0f93cSkardel msyslog(LOG_ERR,
2813abb0f93cSkardel "multicast address %s using wildcard interface #%d %s",
281445530cf1Skardel stoa(addr), ep->ifnum, ep->name);
2815abb0f93cSkardel } else {
2816abb0f93cSkardel msyslog(LOG_ERR,
2817abb0f93cSkardel "No multicast socket available to use for address %s",
2818abb0f93cSkardel stoa(addr));
2819abb0f93cSkardel return;
2820abb0f93cSkardel }
2821abb0f93cSkardel }
282245530cf1Skardel { /* in place of the { following for in #else clause */
282345530cf1Skardel one_ep = ep;
282445530cf1Skardel # else /* MULTICAST_NONEWSOCKET follows */
2825abb0f93cSkardel /*
282645530cf1Skardel * For the case where we can't use a separate socket (Windows)
282745530cf1Skardel * join each applicable endpoint socket to the group address.
2828abb0f93cSkardel */
282945530cf1Skardel if (IS_IPV4(addr))
283045530cf1Skardel one_ep = wildipv4;
283145530cf1Skardel else
283245530cf1Skardel one_ep = wildipv6;
283345530cf1Skardel for (ep = ep_list; ep != NULL; ep = ep->elink) {
283445530cf1Skardel if (ep->ignore_packets || AF(&ep->sin) != AF(addr) ||
283545530cf1Skardel !(INT_MULTICAST & ep->flags) ||
283645530cf1Skardel (INT_LOOPBACK | INT_WILDCARD) & ep->flags)
283745530cf1Skardel continue;
283845530cf1Skardel one_ep = ep;
283945530cf1Skardel # endif /* MULTICAST_NONEWSOCKET */
284045530cf1Skardel if (socket_multicast_enable(ep, addr))
284145530cf1Skardel msyslog(LOG_INFO,
284245530cf1Skardel "Joined %s socket to multicast group %s",
284345530cf1Skardel stoa(&ep->sin),
2844abb0f93cSkardel stoa(addr));
2845abb0f93cSkardel }
2846abb0f93cSkardel
284745530cf1Skardel add_addr_to_list(addr, one_ep);
284845530cf1Skardel #else /* !MCAST follows*/
2849abb0f93cSkardel msyslog(LOG_ERR,
2850abb0f93cSkardel "Can not add multicast address %s: no multicast support",
2851abb0f93cSkardel stoa(addr));
285245530cf1Skardel #endif
2853abb0f93cSkardel return;
2854abb0f93cSkardel }
2855abb0f93cSkardel
2856abb0f93cSkardel
2857abb0f93cSkardel /*
2858abb0f93cSkardel * io_multicast_del() - delete multicast group address
2859abb0f93cSkardel */
2860abb0f93cSkardel void
2861abb0f93cSkardel io_multicast_del(
2862abb0f93cSkardel sockaddr_u * addr
2863abb0f93cSkardel )
2864abb0f93cSkardel {
2865abb0f93cSkardel #ifdef MCAST
286645530cf1Skardel endpt *iface;
2867abb0f93cSkardel
2868abb0f93cSkardel /*
2869abb0f93cSkardel * Check to see if this is a multicast address
2870abb0f93cSkardel */
2871abb0f93cSkardel if (!addr_ismulticast(addr)) {
2872abb0f93cSkardel msyslog(LOG_ERR, "invalid multicast address %s",
2873abb0f93cSkardel stoa(addr));
2874abb0f93cSkardel return;
2875abb0f93cSkardel }
2876abb0f93cSkardel
2877abb0f93cSkardel /*
2878abb0f93cSkardel * Disable reception of multicast packets
2879abb0f93cSkardel */
2880abb0f93cSkardel while ((iface = find_flagged_addr_in_list(addr, INT_MCASTOPEN))
2881abb0f93cSkardel != NULL)
2882abb0f93cSkardel socket_multicast_disable(iface, addr);
2883abb0f93cSkardel
2884abb0f93cSkardel delete_addr_from_list(addr);
2885abb0f93cSkardel
2886abb0f93cSkardel #else /* not MCAST */
2887abb0f93cSkardel msyslog(LOG_ERR,
2888abb0f93cSkardel "Can not delete multicast address %s: no multicast support",
2889abb0f93cSkardel stoa(addr));
2890abb0f93cSkardel #endif /* not MCAST */
2891abb0f93cSkardel }
2892abb0f93cSkardel
2893abb0f93cSkardel
2894abb0f93cSkardel /*
2895abb0f93cSkardel * open_socket - open a socket, returning the file descriptor
2896abb0f93cSkardel */
2897abb0f93cSkardel
2898abb0f93cSkardel static SOCKET
2899abb0f93cSkardel open_socket(
2900abb0f93cSkardel sockaddr_u * addr,
2901abb0f93cSkardel int bcast,
2902abb0f93cSkardel int turn_off_reuse,
290345530cf1Skardel endpt * interf
2904abb0f93cSkardel )
2905abb0f93cSkardel {
2906abb0f93cSkardel SOCKET fd;
2907abb0f93cSkardel int errval;
2908abb0f93cSkardel /*
2909abb0f93cSkardel * int is OK for REUSEADR per
2910abb0f93cSkardel * http://www.kohala.com/start/mcast.api.txt
2911abb0f93cSkardel */
2912abb0f93cSkardel int on = 1;
2913abb0f93cSkardel int off = 0;
2914abb0f93cSkardel
2915abb0f93cSkardel if (IS_IPV6(addr) && !ipv6_works)
2916abb0f93cSkardel return INVALID_SOCKET;
2917abb0f93cSkardel
2918abb0f93cSkardel /* create a datagram (UDP) socket */
2919abb0f93cSkardel fd = socket(AF(addr), SOCK_DGRAM, 0);
2920abb0f93cSkardel if (INVALID_SOCKET == fd) {
292145530cf1Skardel errval = socket_errno();
2922abb0f93cSkardel msyslog(LOG_ERR,
2923abb0f93cSkardel "socket(AF_INET%s, SOCK_DGRAM, 0) failed on address %s: %m",
2924abb0f93cSkardel IS_IPV6(addr) ? "6" : "", stoa(addr));
2925abb0f93cSkardel
2926abb0f93cSkardel if (errval == EPROTONOSUPPORT ||
2927abb0f93cSkardel errval == EAFNOSUPPORT ||
2928abb0f93cSkardel errval == EPFNOSUPPORT)
2929abb0f93cSkardel return (INVALID_SOCKET);
2930abb0f93cSkardel
2931abb0f93cSkardel errno = errval;
2932abb0f93cSkardel msyslog(LOG_ERR,
2933abb0f93cSkardel "unexpected socket() error %m code %d (not EPROTONOSUPPORT nor EAFNOSUPPORT nor EPFNOSUPPORT) - exiting",
2934abb0f93cSkardel errno);
2935abb0f93cSkardel exit(1);
2936abb0f93cSkardel }
2937abb0f93cSkardel
2938abb0f93cSkardel #ifdef SYS_WINNT
2939abb0f93cSkardel connection_reset_fix(fd, addr);
2940abb0f93cSkardel #endif
2941abb0f93cSkardel /*
2942abb0f93cSkardel * Fixup the file descriptor for some systems
2943abb0f93cSkardel * See bug #530 for details of the issue.
2944abb0f93cSkardel */
2945abb0f93cSkardel fd = move_fd(fd);
2946abb0f93cSkardel
2947abb0f93cSkardel /*
2948abb0f93cSkardel * set SO_REUSEADDR since we will be binding the same port
2949abb0f93cSkardel * number on each interface according to turn_off_reuse.
2950abb0f93cSkardel * This is undesirable on Windows versions starting with
2951abb0f93cSkardel * Windows XP (numeric version 5.1).
2952abb0f93cSkardel */
2953abb0f93cSkardel #ifdef SYS_WINNT
2954abb0f93cSkardel if (isc_win32os_versioncheck(5, 1, 0, 0) < 0) /* before 5.1 */
2955abb0f93cSkardel #endif
2956abb0f93cSkardel if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
2957169394abSchristos (void *)((turn_off_reuse)
2958abb0f93cSkardel ? &off
2959abb0f93cSkardel : &on),
2960abb0f93cSkardel sizeof(on))) {
2961abb0f93cSkardel
2962abb0f93cSkardel msyslog(LOG_ERR,
2963abb0f93cSkardel "setsockopt SO_REUSEADDR %s fails for address %s: %m",
2964abb0f93cSkardel (turn_off_reuse)
2965abb0f93cSkardel ? "off"
2966abb0f93cSkardel : "on",
2967abb0f93cSkardel stoa(addr));
2968abb0f93cSkardel closesocket(fd);
2969abb0f93cSkardel return INVALID_SOCKET;
2970abb0f93cSkardel }
2971abb0f93cSkardel #ifdef SO_EXCLUSIVEADDRUSE
2972abb0f93cSkardel /*
2973abb0f93cSkardel * setting SO_EXCLUSIVEADDRUSE on the wildcard we open
2974abb0f93cSkardel * first will cause more specific binds to fail.
2975abb0f93cSkardel */
2976abb0f93cSkardel if (!(interf->flags & INT_WILDCARD))
2977abb0f93cSkardel set_excladdruse(fd);
2978abb0f93cSkardel #endif
2979abb0f93cSkardel
2980abb0f93cSkardel /*
2981abb0f93cSkardel * IPv4 specific options go here
2982abb0f93cSkardel */
2983abb0f93cSkardel if (IS_IPV4(addr)) {
2984b3d6264cSchristos #if defined(IPPROTO_IP) && defined(IP_TOS)
2985169394abSchristos if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void *)&qos,
2986abb0f93cSkardel sizeof(qos)))
2987abb0f93cSkardel msyslog(LOG_ERR,
2988abb0f93cSkardel "setsockopt IP_TOS (%02x) fails on address %s: %m",
2989abb0f93cSkardel qos, stoa(addr));
2990b3d6264cSchristos #endif /* IPPROTO_IP && IP_TOS */
2991abb0f93cSkardel if (bcast)
2992abb0f93cSkardel socket_broadcast_enable(interf, fd, addr);
2993abb0f93cSkardel }
2994abb0f93cSkardel
2995abb0f93cSkardel /*
2996abb0f93cSkardel * IPv6 specific options go here
2997abb0f93cSkardel */
2998abb0f93cSkardel if (IS_IPV6(addr)) {
2999b3d6264cSchristos #if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
3000169394abSchristos if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, (void *)&qos,
3001b3d6264cSchristos sizeof(qos)))
3002b3d6264cSchristos msyslog(LOG_ERR,
3003b3d6264cSchristos "setsockopt IPV6_TCLASS (%02x) fails on address %s: %m",
3004b3d6264cSchristos qos, stoa(addr));
3005b3d6264cSchristos #endif /* IPPROTO_IPV6 && IPV6_TCLASS */
300645530cf1Skardel #ifdef IPV6_V6ONLY
3007abb0f93cSkardel if (isc_net_probe_ipv6only() == ISC_R_SUCCESS
3008abb0f93cSkardel && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
3009169394abSchristos (void *)&on, sizeof(on)))
3010abb0f93cSkardel msyslog(LOG_ERR,
3011abb0f93cSkardel "setsockopt IPV6_V6ONLY on fails on address %s: %m",
3012abb0f93cSkardel stoa(addr));
301345530cf1Skardel #endif
301445530cf1Skardel #ifdef IPV6_BINDV6ONLY
3015abb0f93cSkardel if (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDV6ONLY,
3016169394abSchristos (void *)&on, sizeof(on)))
3017abb0f93cSkardel msyslog(LOG_ERR,
3018abb0f93cSkardel "setsockopt IPV6_BINDV6ONLY on fails on address %s: %m",
3019abb0f93cSkardel stoa(addr));
302045530cf1Skardel #endif
3021abb0f93cSkardel }
3022abb0f93cSkardel
3023abb0f93cSkardel #ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND
3024abb0f93cSkardel /*
3025abb0f93cSkardel * some OSes don't allow binding to more specific
3026abb0f93cSkardel * addresses if a wildcard address already bound
3027abb0f93cSkardel * to the port and SO_REUSEADDR is not set
3028abb0f93cSkardel */
3029abb0f93cSkardel if (!is_wildcard_addr(addr))
3030abb0f93cSkardel set_wildcard_reuse(AF(addr), 1);
3031abb0f93cSkardel #endif
3032abb0f93cSkardel
3033abb0f93cSkardel /*
3034abb0f93cSkardel * bind the local address.
3035abb0f93cSkardel */
3036abb0f93cSkardel errval = bind(fd, &addr->sa, SOCKLEN(addr));
3037abb0f93cSkardel
3038abb0f93cSkardel #ifdef OS_NEEDS_REUSEADDR_FOR_IFADDRBIND
3039abb0f93cSkardel if (!is_wildcard_addr(addr))
3040abb0f93cSkardel set_wildcard_reuse(AF(addr), 0);
3041abb0f93cSkardel #endif
3042abb0f93cSkardel
3043abb0f93cSkardel if (errval < 0) {
3044abb0f93cSkardel /*
3045abb0f93cSkardel * Don't log this under all conditions
3046abb0f93cSkardel */
3047abb0f93cSkardel if (turn_off_reuse == 0
3048abb0f93cSkardel #ifdef DEBUG
3049abb0f93cSkardel || debug > 1
3050abb0f93cSkardel #endif
3051abb0f93cSkardel ) {
3052abb0f93cSkardel msyslog(LOG_ERR,
305324d029faSmlelstv "bind(%d) AF_INET%s %s#%d%s flags 0x%x failed: %m",
3054abb0f93cSkardel fd, IS_IPV6(addr) ? "6" : "",
305524d029faSmlelstv stoa(addr), SRCPORT(addr),
3056abb0f93cSkardel IS_MCAST(addr) ? " (multicast)" : "",
3057abb0f93cSkardel interf->flags);
3058abb0f93cSkardel }
3059abb0f93cSkardel
3060abb0f93cSkardel closesocket(fd);
3061abb0f93cSkardel
3062abb0f93cSkardel return INVALID_SOCKET;
3063abb0f93cSkardel }
3064abb0f93cSkardel
3065abb0f93cSkardel #ifdef HAVE_TIMESTAMP
3066abb0f93cSkardel {
3067abb0f93cSkardel if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP,
3068169394abSchristos (void *)&on, sizeof(on)))
3069abb0f93cSkardel msyslog(LOG_DEBUG,
3070abb0f93cSkardel "setsockopt SO_TIMESTAMP on fails on address %s: %m",
3071abb0f93cSkardel stoa(addr));
3072abb0f93cSkardel else
3073abb0f93cSkardel DPRINTF(4, ("setsockopt SO_TIMESTAMP enabled on fd %d address %s\n",
3074abb0f93cSkardel fd, stoa(addr)));
3075abb0f93cSkardel }
3076abb0f93cSkardel #endif
3077b3d6264cSchristos #ifdef HAVE_TIMESTAMPNS
3078b3d6264cSchristos {
3079b3d6264cSchristos if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS,
3080169394abSchristos (void *)&on, sizeof(on)))
3081b3d6264cSchristos msyslog(LOG_DEBUG,
3082b3d6264cSchristos "setsockopt SO_TIMESTAMPNS on fails on address %s: %m",
3083b3d6264cSchristos stoa(addr));
3084b3d6264cSchristos else
3085b3d6264cSchristos DPRINTF(4, ("setsockopt SO_TIMESTAMPNS enabled on fd %d address %s\n",
3086b3d6264cSchristos fd, stoa(addr)));
3087b3d6264cSchristos }
3088b3d6264cSchristos #endif
3089b3d6264cSchristos #ifdef HAVE_BINTIME
3090b3d6264cSchristos {
3091b3d6264cSchristos if (setsockopt(fd, SOL_SOCKET, SO_BINTIME,
3092169394abSchristos (void *)&on, sizeof(on)))
3093b3d6264cSchristos msyslog(LOG_DEBUG,
3094b3d6264cSchristos "setsockopt SO_BINTIME on fails on address %s: %m",
3095b3d6264cSchristos stoa(addr));
3096b3d6264cSchristos else
3097b3d6264cSchristos DPRINTF(4, ("setsockopt SO_BINTIME enabled on fd %d address %s\n",
3098b3d6264cSchristos fd, stoa(addr)));
3099b3d6264cSchristos }
3100b3d6264cSchristos #endif
3101b3d6264cSchristos
3102abb0f93cSkardel DPRINTF(4, ("bind(%d) AF_INET%s, addr %s%%%d#%d, flags 0x%x\n",
3103abb0f93cSkardel fd, IS_IPV6(addr) ? "6" : "", stoa(addr),
3104abb0f93cSkardel SCOPE(addr), SRCPORT(addr), interf->flags));
3105abb0f93cSkardel
3106b3d6264cSchristos make_socket_nonblocking(fd);
3107abb0f93cSkardel
3108abb0f93cSkardel #ifdef HAVE_SIGNALED_IO
3109abb0f93cSkardel init_socket_sig(fd);
3110abb0f93cSkardel #endif /* not HAVE_SIGNALED_IO */
3111abb0f93cSkardel
3112abb0f93cSkardel add_fd_to_list(fd, FD_TYPE_SOCKET);
3113abb0f93cSkardel
3114abb0f93cSkardel #if !defined(SYS_WINNT) && !defined(VMS)
3115abb0f93cSkardel DPRINTF(4, ("flags for fd %d: 0x%x\n", fd,
3116abb0f93cSkardel fcntl(fd, F_GETFL, 0)));
3117abb0f93cSkardel #endif /* SYS_WINNT || VMS */
3118abb0f93cSkardel
3119abb0f93cSkardel #if defined(HAVE_IO_COMPLETION_PORT)
3120abb0f93cSkardel /*
3121abb0f93cSkardel * Add the socket to the completion port
3122abb0f93cSkardel */
3123335f7552Schristos if (!io_completion_port_add_socket(fd, interf, bcast)) {
3124abb0f93cSkardel msyslog(LOG_ERR, "unable to set up io completion port - EXITING");
3125abb0f93cSkardel exit(1);
3126abb0f93cSkardel }
3127abb0f93cSkardel #endif
3128abb0f93cSkardel return fd;
3129abb0f93cSkardel }
3130abb0f93cSkardel
313145530cf1Skardel
313245530cf1Skardel
3133abb0f93cSkardel /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
3134abb0f93cSkardel /*
3135abb0f93cSkardel * sendpkt - send a packet to the specified destination. Maintain a
3136abb0f93cSkardel * send error cache so that only the first consecutive error for a
3137abb0f93cSkardel * destination is logged.
3138abb0f93cSkardel */
3139abb0f93cSkardel void
3140abb0f93cSkardel sendpkt(
3141abb0f93cSkardel sockaddr_u * dest,
314245530cf1Skardel struct interface * ep,
3143abb0f93cSkardel int ttl,
3144abb0f93cSkardel struct pkt * pkt,
3145abb0f93cSkardel int len
3146abb0f93cSkardel )
3147abb0f93cSkardel {
314845530cf1Skardel endpt * src;
314945530cf1Skardel int ismcast;
3150abb0f93cSkardel int cc;
315145530cf1Skardel int rc;
315245530cf1Skardel u_char cttl;
31539034ec65Schristos l_fp fp_zero = { { 0 }, 0 };
31549034ec65Schristos l_fp org, rec, xmt;
3155abb0f93cSkardel
315645530cf1Skardel ismcast = IS_MCAST(dest);
315745530cf1Skardel if (!ismcast)
315845530cf1Skardel src = ep;
315945530cf1Skardel else
316045530cf1Skardel src = (IS_IPV4(dest))
316145530cf1Skardel ? mc4_list
316245530cf1Skardel : mc6_list;
316345530cf1Skardel
316445530cf1Skardel if (NULL == src) {
3165abb0f93cSkardel /*
3166abb0f93cSkardel * unbound peer - drop request and wait for better
3167abb0f93cSkardel * network conditions
3168abb0f93cSkardel */
3169abb0f93cSkardel DPRINTF(2, ("%ssendpkt(dst=%s, ttl=%d, len=%d): no interface - IGNORED\n",
317045530cf1Skardel ismcast ? "\tMCAST\t***** " : "",
3171abb0f93cSkardel stoa(dest), ttl, len));
3172abb0f93cSkardel return;
3173abb0f93cSkardel }
3174abb0f93cSkardel
317545530cf1Skardel do {
3176abb0f93cSkardel DPRINTF(2, ("%ssendpkt(%d, dst=%s, src=%s, ttl=%d, len=%d)\n",
317745530cf1Skardel ismcast ? "\tMCAST\t***** " : "", src->fd,
317845530cf1Skardel stoa(dest), stoa(&src->sin), ttl, len));
3179abb0f93cSkardel #ifdef MCAST
3180abb0f93cSkardel /*
3181abb0f93cSkardel * for the moment we use the bcast option to set multicast ttl
3182abb0f93cSkardel */
318345530cf1Skardel if (ismcast && ttl > 0 && ttl != src->last_ttl) {
3184abb0f93cSkardel /*
3185abb0f93cSkardel * set the multicast ttl for outgoing packets
3186abb0f93cSkardel */
318745530cf1Skardel switch (AF(&src->sin)) {
3188abb0f93cSkardel
3189abb0f93cSkardel case AF_INET :
3190abb0f93cSkardel cttl = (u_char)ttl;
319145530cf1Skardel rc = setsockopt(src->fd, IPPROTO_IP,
3192abb0f93cSkardel IP_MULTICAST_TTL,
319345530cf1Skardel (void *)&cttl,
319445530cf1Skardel sizeof(cttl));
3195abb0f93cSkardel break;
3196abb0f93cSkardel
3197abb0f93cSkardel # ifdef INCLUDE_IPV6_SUPPORT
3198abb0f93cSkardel case AF_INET6 :
319945530cf1Skardel rc = setsockopt(src->fd, IPPROTO_IPV6,
3200abb0f93cSkardel IPV6_MULTICAST_HOPS,
320145530cf1Skardel (void *)&ttl,
320245530cf1Skardel sizeof(ttl));
3203abb0f93cSkardel break;
3204abb0f93cSkardel # endif /* INCLUDE_IPV6_SUPPORT */
3205abb0f93cSkardel
320645530cf1Skardel default:
320745530cf1Skardel rc = 0;
3208abb0f93cSkardel }
3209abb0f93cSkardel
321045530cf1Skardel if (!rc)
321145530cf1Skardel src->last_ttl = ttl;
3212abb0f93cSkardel else
3213abb0f93cSkardel msyslog(LOG_ERR,
3214abb0f93cSkardel "setsockopt IP_MULTICAST_TTL/IPV6_MULTICAST_HOPS fails on address %s: %m",
321545530cf1Skardel stoa(&src->sin));
3216abb0f93cSkardel }
3217abb0f93cSkardel #endif /* MCAST */
3218abb0f93cSkardel
3219abb0f93cSkardel #ifdef SIM
322045530cf1Skardel cc = simulate_server(dest, src, pkt);
3221335f7552Schristos #elif defined(HAVE_IO_COMPLETION_PORT)
3222335f7552Schristos cc = io_completion_port_sendto(src, src->fd, pkt,
3223335f7552Schristos (size_t)len, (sockaddr_u *)&dest->sa);
322445530cf1Skardel #else
322545530cf1Skardel cc = sendto(src->fd, (char *)pkt, (u_int)len, 0,
322645530cf1Skardel &dest->sa, SOCKLEN(dest));
3227abb0f93cSkardel #endif
322845530cf1Skardel if (cc == -1) {
322945530cf1Skardel src->notsent++;
3230abb0f93cSkardel packets_notsent++;
3231abb0f93cSkardel } else {
323245530cf1Skardel src->sent++;
3233abb0f93cSkardel packets_sent++;
3234abb0f93cSkardel }
323545530cf1Skardel if (ismcast)
323645530cf1Skardel src = src->mclink;
323745530cf1Skardel } while (ismcast && src != NULL);
3238169394abSchristos
3239169394abSchristos /* HMS: pkt->rootdisp is usually random here */
32409034ec65Schristos NTOHL_FP(&pkt->org, &org);
32419034ec65Schristos NTOHL_FP(&pkt->rec, &rec);
32429034ec65Schristos NTOHL_FP(&pkt->xmt, &xmt);
3243169394abSchristos record_raw_stats(src ? &src->sin : NULL, dest,
32449034ec65Schristos &org, &rec, &xmt, &fp_zero,
3245169394abSchristos PKT_LEAP(pkt->li_vn_mode),
32469034ec65Schristos PKT_VERSION(pkt->li_vn_mode),
32479034ec65Schristos PKT_MODE(pkt->li_vn_mode),
3248169394abSchristos pkt->stratum,
3249169394abSchristos pkt->ppoll, pkt->precision,
3250169394abSchristos pkt->rootdelay, pkt->rootdisp, pkt->refid,
3251169394abSchristos len - MIN_V4_PKT_LEN, (u_char *)&pkt->exten);
3252169394abSchristos
3253169394abSchristos return;
3254abb0f93cSkardel }
3255abb0f93cSkardel
3256abb0f93cSkardel
3257abb0f93cSkardel #if !defined(HAVE_IO_COMPLETION_PORT)
3258335f7552Schristos #if !defined(HAVE_SIGNALED_IO)
3259abb0f93cSkardel /*
3260abb0f93cSkardel * fdbits - generate ascii representation of fd_set (FAU debug support)
3261abb0f93cSkardel * HFDF format - highest fd first.
3262abb0f93cSkardel */
3263abb0f93cSkardel static char *
3264abb0f93cSkardel fdbits(
3265abb0f93cSkardel int count,
3266335f7552Schristos const fd_set* set
3267abb0f93cSkardel )
3268abb0f93cSkardel {
3269abb0f93cSkardel static char buffer[256];
3270abb0f93cSkardel char * buf = buffer;
3271abb0f93cSkardel
3272abb0f93cSkardel count = min(count, 255);
3273abb0f93cSkardel
3274abb0f93cSkardel while (count >= 0) {
3275abb0f93cSkardel *buf++ = FD_ISSET(count, set) ? '#' : '-';
3276abb0f93cSkardel count--;
3277abb0f93cSkardel }
3278abb0f93cSkardel *buf = '\0';
3279abb0f93cSkardel
3280abb0f93cSkardel return buffer;
3281abb0f93cSkardel }
3282335f7552Schristos #endif
3283b3d6264cSchristos
3284b3d6264cSchristos #ifdef REFCLOCK
3285abb0f93cSkardel /*
3286abb0f93cSkardel * Routine to read the refclock packets for a specific interface
3287abb0f93cSkardel * Return the number of bytes read. That way we know if we should
3288abb0f93cSkardel * read it again or go on to the next one if no bytes returned
3289abb0f93cSkardel */
3290abb0f93cSkardel static inline int
3291b3d6264cSchristos read_refclock_packet(
3292b3d6264cSchristos SOCKET fd,
3293b3d6264cSchristos struct refclockio * rp,
3294b3d6264cSchristos l_fp ts
3295b3d6264cSchristos )
3296abb0f93cSkardel {
329709f14f80Schristos u_int read_count;
3298abb0f93cSkardel int buflen;
3299b3d6264cSchristos int saved_errno;
3300b3d6264cSchristos int consumed;
3301b3d6264cSchristos struct recvbuf * rb;
3302abb0f93cSkardel
3303*e03b00c8Schristos rb = get_free_recv_buffer(TRUE);
3304abb0f93cSkardel
3305abb0f93cSkardel if (NULL == rb) {
3306abb0f93cSkardel /*
3307*e03b00c8Schristos * No buffer space available - just drop the 'packet'.
3308*e03b00c8Schristos * Since this is a non-blocking character stream we read
3309*e03b00c8Schristos * all data that we can.
3310*e03b00c8Schristos *
3311*e03b00c8Schristos * ...hmmmm... what about "tcflush(fd,TCIFLUSH)" here?!?
3312abb0f93cSkardel */
3313*e03b00c8Schristos char buf[128];
3314*e03b00c8Schristos do
3315*e03b00c8Schristos buflen = read(fd, buf, sizeof(buf));
3316*e03b00c8Schristos while (buflen > 0);
3317abb0f93cSkardel packets_dropped++;
3318abb0f93cSkardel return (buflen);
3319abb0f93cSkardel }
3320abb0f93cSkardel
332109f14f80Schristos /* TALOS-CAN-0064: avoid signed/unsigned clashes that can lead
332209f14f80Schristos * to buffer overrun and memory corruption
332309f14f80Schristos */
332409f14f80Schristos if (rp->datalen <= 0 || (size_t)rp->datalen > sizeof(rb->recv_space))
332509f14f80Schristos read_count = sizeof(rb->recv_space);
332609f14f80Schristos else
332709f14f80Schristos read_count = (u_int)rp->datalen;
3328b3d6264cSchristos do {
332909f14f80Schristos buflen = read(fd, (char *)&rb->recv_space, read_count);
3330b3d6264cSchristos } while (buflen < 0 && EINTR == errno);
3331abb0f93cSkardel
3332b3d6264cSchristos if (buflen <= 0) {
3333b3d6264cSchristos saved_errno = errno;
3334abb0f93cSkardel freerecvbuf(rb);
3335b3d6264cSchristos errno = saved_errno;
3336b3d6264cSchristos return buflen;
3337abb0f93cSkardel }
3338abb0f93cSkardel
3339abb0f93cSkardel /*
3340abb0f93cSkardel * Got one. Mark how and when it got here,
3341abb0f93cSkardel * put it on the full list and do bookkeeping.
3342abb0f93cSkardel */
3343abb0f93cSkardel rb->recv_length = buflen;
3344b3d6264cSchristos rb->recv_peer = rp->srcclock;
3345abb0f93cSkardel rb->dstadr = 0;
3346abb0f93cSkardel rb->fd = fd;
3347abb0f93cSkardel rb->recv_time = ts;
3348abb0f93cSkardel rb->receiver = rp->clock_recv;
3349abb0f93cSkardel
3350b3d6264cSchristos consumed = indicate_refclock_packet(rp, rb);
3351b3d6264cSchristos if (!consumed) {
3352abb0f93cSkardel rp->recvcount++;
3353abb0f93cSkardel packets_received++;
3354abb0f93cSkardel }
3355abb0f93cSkardel
3356b3d6264cSchristos return buflen;
3357b3d6264cSchristos }
3358b3d6264cSchristos #endif /* REFCLOCK */
3359abb0f93cSkardel
3360b3d6264cSchristos
3361b3d6264cSchristos #ifdef HAVE_PACKET_TIMESTAMP
3362abb0f93cSkardel /*
3363abb0f93cSkardel * extract timestamps from control message buffer
3364abb0f93cSkardel */
3365abb0f93cSkardel static l_fp
3366abb0f93cSkardel fetch_timestamp(
3367abb0f93cSkardel struct recvbuf * rb,
3368abb0f93cSkardel struct msghdr * msghdr,
3369abb0f93cSkardel l_fp ts
3370abb0f93cSkardel )
3371abb0f93cSkardel {
3372abb0f93cSkardel struct cmsghdr * cmsghdr;
3373b3d6264cSchristos unsigned long ticks;
3374b3d6264cSchristos double fuzz;
3375b3d6264cSchristos l_fp lfpfuzz;
3376b3d6264cSchristos l_fp nts;
3377b3d6264cSchristos #ifdef DEBUG_TIMING
3378b3d6264cSchristos l_fp dts;
3379b3d6264cSchristos #endif
3380abb0f93cSkardel
3381abb0f93cSkardel cmsghdr = CMSG_FIRSTHDR(msghdr);
3382abb0f93cSkardel while (cmsghdr != NULL) {
3383abb0f93cSkardel switch (cmsghdr->cmsg_type)
3384abb0f93cSkardel {
3385b3d6264cSchristos #ifdef HAVE_BINTIME
3386b3d6264cSchristos case SCM_BINTIME:
3387b3d6264cSchristos #endif /* HAVE_BINTIME */
3388b3d6264cSchristos #ifdef HAVE_TIMESTAMPNS
3389b3d6264cSchristos case SCM_TIMESTAMPNS:
3390b3d6264cSchristos #endif /* HAVE_TIMESTAMPNS */
3391b3d6264cSchristos #ifdef HAVE_TIMESTAMP
3392abb0f93cSkardel case SCM_TIMESTAMP:
3393b3d6264cSchristos #endif /* HAVE_TIMESTAMP */
3394b3d6264cSchristos #if defined(HAVE_BINTIME) || defined (HAVE_TIMESTAMPNS) || defined(HAVE_TIMESTAMP)
3395b3d6264cSchristos switch (cmsghdr->cmsg_type)
3396abb0f93cSkardel {
3397b3d6264cSchristos #ifdef HAVE_BINTIME
3398b3d6264cSchristos case SCM_BINTIME:
339966fcc386Schristos {
340066fcc386Schristos struct bintime pbt;
340166fcc386Schristos memcpy(&pbt, CMSG_DATA(cmsghdr), sizeof(pbt));
3402b3d6264cSchristos /*
3403b3d6264cSchristos * bintime documentation is at http://phk.freebsd.dk/pubs/timecounter.pdf
3404b3d6264cSchristos */
340566fcc386Schristos nts.l_i = pbt.sec + JAN_1970;
340666fcc386Schristos nts.l_uf = (u_int32)(pbt.frac >> 32);
3407b3d6264cSchristos if (sys_tick > measured_tick &&
3408b3d6264cSchristos sys_tick > 1e-9) {
3409b3d6264cSchristos ticks = (unsigned long)(nts.l_uf / (unsigned long)(sys_tick * FRAC));
3410b3d6264cSchristos nts.l_uf = (unsigned long)(ticks * (unsigned long)(sys_tick * FRAC));
3411b3d6264cSchristos }
3412b3d6264cSchristos DPRINTF(4, ("fetch_timestamp: system bintime network time stamp: %ld.%09lu\n",
341366fcc386Schristos pbt.sec, (unsigned long)((nts.l_uf / FRAC) * 1e9)));
341466fcc386Schristos }
3415b3d6264cSchristos break;
3416b3d6264cSchristos #endif /* HAVE_BINTIME */
3417b3d6264cSchristos #ifdef HAVE_TIMESTAMPNS
3418b3d6264cSchristos case SCM_TIMESTAMPNS:
341966fcc386Schristos {
342066fcc386Schristos struct timespec pts;
342166fcc386Schristos memcpy(&pts, CMSG_DATA(cmsghdr), sizeof(pts));
3422b3d6264cSchristos if (sys_tick > measured_tick &&
3423b3d6264cSchristos sys_tick > 1e-9) {
342466fcc386Schristos ticks = (unsigned long)((pts.tv_nsec * 1e-9) /
3425b3d6264cSchristos sys_tick);
342666fcc386Schristos pts.tv_nsec = (long)(ticks * 1e9 *
3427b3d6264cSchristos sys_tick);
3428b3d6264cSchristos }
3429b3d6264cSchristos DPRINTF(4, ("fetch_timestamp: system nsec network time stamp: %ld.%09ld\n",
343066fcc386Schristos pts.tv_sec, pts.tv_nsec));
343166fcc386Schristos nts = tspec_stamp_to_lfp(pts);
343266fcc386Schristos }
3433b3d6264cSchristos break;
3434b3d6264cSchristos #endif /* HAVE_TIMESTAMPNS */
3435b3d6264cSchristos #ifdef HAVE_TIMESTAMP
3436b3d6264cSchristos case SCM_TIMESTAMP:
343766fcc386Schristos {
343866fcc386Schristos struct timeval ptv;
343966fcc386Schristos memcpy(&ptv, CMSG_DATA(cmsghdr), sizeof(ptv));
3440b3d6264cSchristos if (sys_tick > measured_tick &&
3441b3d6264cSchristos sys_tick > 1e-6) {
344266fcc386Schristos ticks = (unsigned long)((ptv.tv_usec * 1e-6) /
3443b3d6264cSchristos sys_tick);
344466fcc386Schristos ptv.tv_usec = (long)(ticks * 1e6 *
3445b3d6264cSchristos sys_tick);
3446b3d6264cSchristos }
344774fd00ffSchristos DPRINTF(4, ("fetch_timestamp: system usec network time stamp: %jd.%06ld\n",
344866fcc386Schristos (intmax_t)ptv.tv_sec, (long)ptv.tv_usec));
344966fcc386Schristos nts = tval_stamp_to_lfp(ptv);
345066fcc386Schristos }
3451b3d6264cSchristos break;
3452b3d6264cSchristos #endif /* HAVE_TIMESTAMP */
3453b3d6264cSchristos }
3454b3d6264cSchristos fuzz = ntp_random() * 2. / FRAC * sys_fuzz;
3455b3d6264cSchristos DTOLFP(fuzz, &lfpfuzz);
3456b3d6264cSchristos L_ADD(&nts, &lfpfuzz);
3457abb0f93cSkardel #ifdef DEBUG_TIMING
3458abb0f93cSkardel dts = ts;
3459abb0f93cSkardel L_SUB(&dts, &nts);
3460b3d6264cSchristos collect_timing(rb, "input processing delay", 1,
3461b3d6264cSchristos &dts);
3462b3d6264cSchristos DPRINTF(4, ("fetch_timestamp: timestamp delta: %s (incl. fuzz)\n",
3463abb0f93cSkardel lfptoa(&dts, 9)));
3464b3d6264cSchristos #endif /* DEBUG_TIMING */
3465abb0f93cSkardel ts = nts; /* network time stamp */
3466abb0f93cSkardel break;
3467b3d6264cSchristos #endif /* HAVE_BINTIME || HAVE_TIMESTAMPNS || HAVE_TIMESTAMP */
3468b3d6264cSchristos
3469abb0f93cSkardel default:
3470abb0f93cSkardel DPRINTF(4, ("fetch_timestamp: skipping control message 0x%x\n",
3471abb0f93cSkardel cmsghdr->cmsg_type));
3472abb0f93cSkardel }
3473abb0f93cSkardel cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr);
3474abb0f93cSkardel }
3475abb0f93cSkardel return ts;
3476abb0f93cSkardel }
3477b3d6264cSchristos #endif /* HAVE_PACKET_TIMESTAMP */
3478abb0f93cSkardel
3479abb0f93cSkardel
3480abb0f93cSkardel /*
3481abb0f93cSkardel * Routine to read the network NTP packets for a specific interface
3482abb0f93cSkardel * Return the number of bytes read. That way we know if we should
3483abb0f93cSkardel * read it again or go on to the next one if no bytes returned
3484abb0f93cSkardel */
3485abb0f93cSkardel static inline int
3486abb0f93cSkardel read_network_packet(
3487abb0f93cSkardel SOCKET fd,
3488abb0f93cSkardel struct interface * itf,
3489abb0f93cSkardel l_fp ts
3490abb0f93cSkardel )
3491abb0f93cSkardel {
3492abb0f93cSkardel GETSOCKNAME_SOCKLEN_TYPE fromlen;
3493abb0f93cSkardel int buflen;
3494abb0f93cSkardel register struct recvbuf *rb;
3495b3d6264cSchristos #ifdef HAVE_PACKET_TIMESTAMP
3496abb0f93cSkardel struct msghdr msghdr;
3497abb0f93cSkardel struct iovec iovec;
3498b3d6264cSchristos char control[CMSG_BUFSIZE];
3499abb0f93cSkardel #endif
3500abb0f93cSkardel
3501abb0f93cSkardel /*
3502*e03b00c8Schristos * Get a buffer and read the frame. If we haven't got a buffer,
3503*e03b00c8Schristos * or this is received on a disallowed socket, just dump the
3504abb0f93cSkardel * packet.
3505abb0f93cSkardel */
3506abb0f93cSkardel
3507*e03b00c8Schristos rb = itf->ignore_packets ? NULL : get_free_recv_buffer(FALSE);
3508*e03b00c8Schristos if (NULL == rb) {
3509*e03b00c8Schristos /* A partial read on a UDP socket truncates the data and
3510*e03b00c8Schristos * removes the message from the queue. So there's no
3511*e03b00c8Schristos * need to have a full buffer here on the stack.
3512*e03b00c8Schristos */
3513*e03b00c8Schristos char buf[16];
3514abb0f93cSkardel sockaddr_u from;
3515abb0f93cSkardel
3516abb0f93cSkardel if (rb != NULL)
3517abb0f93cSkardel freerecvbuf(rb);
3518abb0f93cSkardel
3519abb0f93cSkardel fromlen = sizeof(from);
3520abb0f93cSkardel buflen = recvfrom(fd, buf, sizeof(buf), 0,
3521abb0f93cSkardel &from.sa, &fromlen);
3522abb0f93cSkardel DPRINTF(4, ("%s on (%lu) fd=%d from %s\n",
3523abb0f93cSkardel (itf->ignore_packets)
3524abb0f93cSkardel ? "ignore"
3525abb0f93cSkardel : "drop",
3526abb0f93cSkardel free_recvbuffs(), fd, stoa(&from)));
3527abb0f93cSkardel if (itf->ignore_packets)
3528abb0f93cSkardel packets_ignored++;
3529abb0f93cSkardel else
3530abb0f93cSkardel packets_dropped++;
3531abb0f93cSkardel return (buflen);
3532abb0f93cSkardel }
3533abb0f93cSkardel
3534abb0f93cSkardel fromlen = sizeof(rb->recv_srcadr);
3535abb0f93cSkardel
3536b3d6264cSchristos #ifndef HAVE_PACKET_TIMESTAMP
3537abb0f93cSkardel rb->recv_length = recvfrom(fd, (char *)&rb->recv_space,
3538abb0f93cSkardel sizeof(rb->recv_space), 0,
3539abb0f93cSkardel &rb->recv_srcadr.sa, &fromlen);
3540abb0f93cSkardel #else
3541abb0f93cSkardel iovec.iov_base = &rb->recv_space;
3542abb0f93cSkardel iovec.iov_len = sizeof(rb->recv_space);
3543abb0f93cSkardel msghdr.msg_name = &rb->recv_srcadr;
3544abb0f93cSkardel msghdr.msg_namelen = fromlen;
3545abb0f93cSkardel msghdr.msg_iov = &iovec;
3546abb0f93cSkardel msghdr.msg_iovlen = 1;
3547abb0f93cSkardel msghdr.msg_control = (void *)&control;
3548abb0f93cSkardel msghdr.msg_controllen = sizeof(control);
3549abb0f93cSkardel msghdr.msg_flags = 0;
3550abb0f93cSkardel rb->recv_length = recvmsg(fd, &msghdr, 0);
3551abb0f93cSkardel #endif
3552abb0f93cSkardel
3553abb0f93cSkardel buflen = rb->recv_length;
3554abb0f93cSkardel
3555abb0f93cSkardel if (buflen == 0 || (buflen == -1 &&
3556abb0f93cSkardel (EWOULDBLOCK == errno
3557abb0f93cSkardel #ifdef EAGAIN
3558abb0f93cSkardel || EAGAIN == errno
3559abb0f93cSkardel #endif
3560abb0f93cSkardel ))) {
3561abb0f93cSkardel freerecvbuf(rb);
3562abb0f93cSkardel return (buflen);
3563abb0f93cSkardel } else if (buflen < 0) {
3564abb0f93cSkardel msyslog(LOG_ERR, "recvfrom(%s) fd=%d: %m",
3565abb0f93cSkardel stoa(&rb->recv_srcadr), fd);
3566abb0f93cSkardel DPRINTF(5, ("read_network_packet: fd=%d dropped (bad recvfrom)\n",
3567abb0f93cSkardel fd));
3568abb0f93cSkardel freerecvbuf(rb);
3569abb0f93cSkardel return (buflen);
3570abb0f93cSkardel }
3571abb0f93cSkardel
3572abb0f93cSkardel DPRINTF(3, ("read_network_packet: fd=%d length %d from %s\n",
3573abb0f93cSkardel fd, buflen, stoa(&rb->recv_srcadr)));
3574abb0f93cSkardel
3575335f7552Schristos #ifdef ENABLE_BUG3020_FIX
3576335f7552Schristos if (ISREFCLOCKADR(&rb->recv_srcadr)) {
3577335f7552Schristos msyslog(LOG_ERR, "recvfrom(%s) fd=%d: refclock srcadr on a network interface!",
3578335f7552Schristos stoa(&rb->recv_srcadr), fd);
3579335f7552Schristos DPRINTF(1, ("read_network_packet: fd=%d dropped (refclock srcadr))\n",
3580335f7552Schristos fd));
3581335f7552Schristos packets_dropped++;
3582335f7552Schristos freerecvbuf(rb);
3583335f7552Schristos return (buflen);
3584335f7552Schristos }
3585335f7552Schristos #endif
3586335f7552Schristos
3587abb0f93cSkardel /*
3588ad131110Schristos ** Bug 2672: Some OSes (MacOSX and Linux) don't block spoofed ::1
3589ad131110Schristos */
3590ad131110Schristos
3591ad131110Schristos if (AF_INET6 == itf->family) {
359250cc4415Schristos DPRINTF(2, ("Got an IPv6 packet, from <%s> (%d) to <%s> (%d)\n",
3593ad131110Schristos stoa(&rb->recv_srcadr),
359450cc4415Schristos IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&rb->recv_srcadr)),
3595ad131110Schristos stoa(&itf->sin),
359650cc4415Schristos !IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&itf->sin))
3597ad131110Schristos ));
3598ad131110Schristos
359950cc4415Schristos if ( IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&rb->recv_srcadr))
360050cc4415Schristos && !IN6_IS_ADDR_LOOPBACK(PSOCK_ADDR6(&itf->sin))
3601ad131110Schristos ) {
3602ad131110Schristos packets_dropped++;
360350cc4415Schristos DPRINTF(2, ("DROPPING that packet\n"));
3604ad131110Schristos freerecvbuf(rb);
3605ad131110Schristos return buflen;
3606ad131110Schristos }
360750cc4415Schristos DPRINTF(2, ("processing that packet\n"));
360850cc4415Schristos }
3609ad131110Schristos
3610ad131110Schristos /*
3611abb0f93cSkardel * Got one. Mark how and when it got here,
3612abb0f93cSkardel * put it on the full list and do bookkeeping.
3613abb0f93cSkardel */
3614abb0f93cSkardel rb->dstadr = itf;
3615abb0f93cSkardel rb->fd = fd;
3616b3d6264cSchristos #ifdef HAVE_PACKET_TIMESTAMP
3617abb0f93cSkardel /* pick up a network time stamp if possible */
3618abb0f93cSkardel ts = fetch_timestamp(rb, &msghdr, ts);
3619abb0f93cSkardel #endif
3620abb0f93cSkardel rb->recv_time = ts;
3621abb0f93cSkardel rb->receiver = receive;
3622abb0f93cSkardel
3623abb0f93cSkardel add_full_recv_buffer(rb);
3624abb0f93cSkardel
3625abb0f93cSkardel itf->received++;
3626abb0f93cSkardel packets_received++;
3627abb0f93cSkardel return (buflen);
3628abb0f93cSkardel }
3629abb0f93cSkardel
3630b3d6264cSchristos /*
3631b3d6264cSchristos * attempt to handle io (select()/signaled IO)
3632b3d6264cSchristos */
3633b3d6264cSchristos void
3634b3d6264cSchristos io_handler(void)
3635b3d6264cSchristos {
3636b3d6264cSchristos # ifndef HAVE_SIGNALED_IO
3637b3d6264cSchristos fd_set rdfdes;
3638b3d6264cSchristos int nfound;
3639b3d6264cSchristos
3640b3d6264cSchristos /*
3641b3d6264cSchristos * Use select() on all on all input fd's for unlimited
3642b3d6264cSchristos * time. select() will terminate on SIGALARM or on the
3643b3d6264cSchristos * reception of input. Using select() means we can't do
3644b3d6264cSchristos * robust signal handling and we get a potential race
3645b3d6264cSchristos * between checking for alarms and doing the select().
3646b3d6264cSchristos * Mostly harmless, I think.
3647b3d6264cSchristos */
3648b3d6264cSchristos /*
3649b3d6264cSchristos * On VMS, I suspect that select() can't be interrupted
3650b3d6264cSchristos * by a "signal" either, so I take the easy way out and
3651b3d6264cSchristos * have select() time out after one second.
3652b3d6264cSchristos * System clock updates really aren't time-critical,
3653b3d6264cSchristos * and - lacking a hardware reference clock - I have
3654b3d6264cSchristos * yet to learn about anything else that is.
3655b3d6264cSchristos */
3656335f7552Schristos ++handler_calls;
3657b3d6264cSchristos rdfdes = activefds;
3658b3d6264cSchristos # if !defined(VMS) && !defined(SYS_VXWORKS)
3659b3d6264cSchristos nfound = select(maxactivefd + 1, &rdfdes, NULL,
3660b3d6264cSchristos NULL, NULL);
3661b3d6264cSchristos # else /* VMS, VxWorks */
3662b3d6264cSchristos /* make select() wake up after one second */
3663b3d6264cSchristos {
3664b3d6264cSchristos struct timeval t1;
3665b3d6264cSchristos t1.tv_sec = 1;
3666b3d6264cSchristos t1.tv_usec = 0;
3667b3d6264cSchristos nfound = select(maxactivefd + 1,
3668b3d6264cSchristos &rdfdes, NULL, NULL,
3669b3d6264cSchristos &t1);
3670b3d6264cSchristos }
3671b3d6264cSchristos # endif /* VMS, VxWorks */
3672335f7552Schristos if (nfound < 0 && sanitize_fdset(errno)) {
3673335f7552Schristos struct timeval t1;
3674335f7552Schristos t1.tv_sec = 0;
3675335f7552Schristos t1.tv_usec = 0;
3676335f7552Schristos rdfdes = activefds;
3677335f7552Schristos nfound = select(maxactivefd + 1,
3678335f7552Schristos &rdfdes, NULL, NULL,
3679335f7552Schristos &t1);
3680335f7552Schristos }
3681335f7552Schristos
3682b3d6264cSchristos if (nfound > 0) {
3683b3d6264cSchristos l_fp ts;
3684b3d6264cSchristos
3685b3d6264cSchristos get_systime(&ts);
3686b3d6264cSchristos
3687335f7552Schristos input_handler_scan(&ts, &rdfdes);
3688b3d6264cSchristos } else if (nfound == -1 && errno != EINTR) {
3689b3d6264cSchristos msyslog(LOG_ERR, "select() error: %m");
3690b3d6264cSchristos }
3691b3d6264cSchristos # ifdef DEBUG
3692b3d6264cSchristos else if (debug > 4) {
3693b3d6264cSchristos msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
3694b3d6264cSchristos } else {
36954e3b3909Schristos DPRINTF(3, ("select() returned %d: %m\n", nfound));
3696b3d6264cSchristos }
3697b3d6264cSchristos # endif /* DEBUG */
3698b3d6264cSchristos # else /* HAVE_SIGNALED_IO */
3699b3d6264cSchristos wait_for_signal();
3700b3d6264cSchristos # endif /* HAVE_SIGNALED_IO */
3701b3d6264cSchristos }
3702abb0f93cSkardel
3703335f7552Schristos #ifdef HAVE_SIGNALED_IO
3704abb0f93cSkardel /*
3705abb0f93cSkardel * input_handler - receive packets asynchronously
3706335f7552Schristos *
3707335f7552Schristos * ALWAYS IN SIGNAL HANDLER CONTEXT -- only async-safe functions allowed!
3708abb0f93cSkardel */
3709335f7552Schristos static RETSIGTYPE
3710abb0f93cSkardel input_handler(
3711abb0f93cSkardel l_fp * cts
3712abb0f93cSkardel )
3713abb0f93cSkardel {
3714abb0f93cSkardel int n;
3715335f7552Schristos struct timeval tvzero;
3716335f7552Schristos fd_set fds;
3717335f7552Schristos
3718335f7552Schristos ++handler_calls;
3719335f7552Schristos
3720335f7552Schristos /*
3721335f7552Schristos * Do a poll to see who has data
3722335f7552Schristos */
3723335f7552Schristos
3724335f7552Schristos fds = activefds;
3725335f7552Schristos tvzero.tv_sec = tvzero.tv_usec = 0;
3726335f7552Schristos
3727335f7552Schristos n = select(maxactivefd + 1, &fds, NULL, NULL, &tvzero);
3728335f7552Schristos if (n < 0 && sanitize_fdset(errno)) {
3729335f7552Schristos fds = activefds;
3730335f7552Schristos tvzero.tv_sec = tvzero.tv_usec = 0;
3731335f7552Schristos n = select(maxactivefd + 1, &fds, NULL, NULL, &tvzero);
3732335f7552Schristos }
3733335f7552Schristos if (n > 0)
3734335f7552Schristos input_handler_scan(cts, &fds);
3735335f7552Schristos }
3736335f7552Schristos #endif /* HAVE_SIGNALED_IO */
3737335f7552Schristos
3738335f7552Schristos
3739335f7552Schristos /*
3740335f7552Schristos * Try to sanitize the global FD set
3741335f7552Schristos *
3742335f7552Schristos * SIGNAL HANDLER CONTEXT if HAVE_SIGNALED_IO, ordinary userspace otherwise
3743335f7552Schristos */
3744335f7552Schristos static int/*BOOL*/
3745335f7552Schristos sanitize_fdset(
3746335f7552Schristos int errc
3747335f7552Schristos )
3748335f7552Schristos {
3749335f7552Schristos int j, b, maxscan;
3750335f7552Schristos
3751335f7552Schristos # ifndef HAVE_SIGNALED_IO
3752335f7552Schristos /*
3753335f7552Schristos * extended FAU debugging output
3754335f7552Schristos */
3755335f7552Schristos if (errc != EINTR) {
3756335f7552Schristos msyslog(LOG_ERR,
3757335f7552Schristos "select(%d, %s, 0L, 0L, &0.0) error: %m",
3758335f7552Schristos maxactivefd + 1,
3759335f7552Schristos fdbits(maxactivefd, &activefds));
3760335f7552Schristos }
3761335f7552Schristos # endif
3762335f7552Schristos
3763335f7552Schristos if (errc != EBADF)
3764335f7552Schristos return FALSE;
3765335f7552Schristos
3766335f7552Schristos /* if we have oviously bad FDs, try to sanitize the FD set. */
3767335f7552Schristos for (j = 0, maxscan = 0; j <= maxactivefd; j++) {
3768335f7552Schristos if (FD_ISSET(j, &activefds)) {
3769335f7552Schristos if (-1 != read(j, &b, 0)) {
3770335f7552Schristos maxscan = j;
3771335f7552Schristos continue;
3772335f7552Schristos }
3773335f7552Schristos # ifndef HAVE_SIGNALED_IO
3774335f7552Schristos msyslog(LOG_ERR,
3775335f7552Schristos "Removing bad file descriptor %d from select set",
3776335f7552Schristos j);
3777335f7552Schristos # endif
3778335f7552Schristos FD_CLR(j, &activefds);
3779335f7552Schristos }
3780335f7552Schristos }
3781335f7552Schristos if (maxactivefd != maxscan)
3782335f7552Schristos maxactivefd = maxscan;
3783335f7552Schristos return TRUE;
3784335f7552Schristos }
3785335f7552Schristos
3786335f7552Schristos /*
3787335f7552Schristos * scan the known FDs (clocks, servers, ...) for presence in a 'fd_set'.
3788335f7552Schristos *
3789335f7552Schristos * SIGNAL HANDLER CONTEXT if HAVE_SIGNALED_IO, ordinary userspace otherwise
3790335f7552Schristos */
3791335f7552Schristos static void
3792335f7552Schristos input_handler_scan(
3793335f7552Schristos const l_fp * cts,
3794335f7552Schristos const fd_set * pfds
3795335f7552Schristos )
3796335f7552Schristos {
3797335f7552Schristos int buflen;
3798b3d6264cSchristos u_int idx;
3799abb0f93cSkardel int doing;
3800abb0f93cSkardel SOCKET fd;
3801b3d6264cSchristos blocking_child *c;
3802abb0f93cSkardel l_fp ts; /* Timestamp at BOselect() gob */
3803335f7552Schristos
3804335f7552Schristos #if defined(DEBUG_TIMING)
3805abb0f93cSkardel l_fp ts_e; /* Timestamp at EOselect() gob */
3806abb0f93cSkardel #endif
380745530cf1Skardel endpt * ep;
3808b3d6264cSchristos #ifdef REFCLOCK
3809b3d6264cSchristos struct refclockio *rp;
3810b3d6264cSchristos int saved_errno;
3811b3d6264cSchristos const char * clk;
3812b3d6264cSchristos #endif
3813b3d6264cSchristos #ifdef HAS_ROUTING_SOCKET
3814abb0f93cSkardel struct asyncio_reader * asyncio_reader;
3815b3d6264cSchristos struct asyncio_reader * next_asyncio_reader;
3816abb0f93cSkardel #endif
3817abb0f93cSkardel
3818abb0f93cSkardel ++handler_pkts;
3819335f7552Schristos ts = *cts;
3820abb0f93cSkardel
3821abb0f93cSkardel #ifdef REFCLOCK
3822abb0f93cSkardel /*
3823abb0f93cSkardel * Check out the reference clocks first, if any
3824abb0f93cSkardel */
3825abb0f93cSkardel
3826abb0f93cSkardel for (rp = refio; rp != NULL; rp = rp->next) {
3827abb0f93cSkardel fd = rp->fd;
3828abb0f93cSkardel
3829335f7552Schristos if (!FD_ISSET(fd, pfds))
3830b3d6264cSchristos continue;
3831b3d6264cSchristos buflen = read_refclock_packet(fd, rp, ts);
3832b3d6264cSchristos /*
3833335f7552Schristos * The first read must succeed after select() indicates
3834335f7552Schristos * readability, or we've reached a permanent EOF.
3835335f7552Schristos * http://bugs.ntp.org/1732 reported ntpd munching CPU
3836335f7552Schristos * after a USB GPS was unplugged because select was
3837335f7552Schristos * indicating EOF but ntpd didn't remove the descriptor
3838b3d6264cSchristos * from the activefds set.
3839b3d6264cSchristos */
3840b3d6264cSchristos if (buflen < 0 && EAGAIN != errno) {
3841b3d6264cSchristos saved_errno = errno;
3842b3d6264cSchristos clk = refnumtoa(&rp->srcclock->srcadr);
3843b3d6264cSchristos errno = saved_errno;
3844b3d6264cSchristos msyslog(LOG_ERR, "%s read: %m", clk);
3845b3d6264cSchristos maintain_activefds(fd, TRUE);
3846b3d6264cSchristos } else if (0 == buflen) {
3847b3d6264cSchristos clk = refnumtoa(&rp->srcclock->srcadr);
3848b3d6264cSchristos msyslog(LOG_ERR, "%s read EOF", clk);
3849b3d6264cSchristos maintain_activefds(fd, TRUE);
3850b3d6264cSchristos } else {
3851b3d6264cSchristos /* drain any remaining refclock input */
3852b3d6264cSchristos do {
3853b3d6264cSchristos buflen = read_refclock_packet(fd, rp, ts);
3854abb0f93cSkardel } while (buflen > 0);
3855abb0f93cSkardel }
3856abb0f93cSkardel }
3857abb0f93cSkardel #endif /* REFCLOCK */
3858abb0f93cSkardel
3859abb0f93cSkardel /*
3860abb0f93cSkardel * Loop through the interfaces looking for data to read.
3861abb0f93cSkardel */
386245530cf1Skardel for (ep = ep_list; ep != NULL; ep = ep->elink) {
386345530cf1Skardel for (doing = 0; doing < 2; doing++) {
386445530cf1Skardel if (!doing) {
386545530cf1Skardel fd = ep->fd;
386645530cf1Skardel } else {
386745530cf1Skardel if (!(ep->flags & INT_BCASTOPEN))
3868abb0f93cSkardel break;
386945530cf1Skardel fd = ep->bfd;
3870abb0f93cSkardel }
3871abb0f93cSkardel if (fd < 0)
3872abb0f93cSkardel continue;
3873335f7552Schristos if (FD_ISSET(fd, pfds))
3874abb0f93cSkardel do {
3875abb0f93cSkardel buflen = read_network_packet(
387645530cf1Skardel fd, ep, ts);
3877abb0f93cSkardel } while (buflen > 0);
3878abb0f93cSkardel /* Check more interfaces */
3879abb0f93cSkardel }
3880abb0f93cSkardel }
3881abb0f93cSkardel
3882abb0f93cSkardel #ifdef HAS_ROUTING_SOCKET
3883abb0f93cSkardel /*
3884abb0f93cSkardel * scan list of asyncio readers - currently only used for routing sockets
3885abb0f93cSkardel */
3886abb0f93cSkardel asyncio_reader = asyncio_reader_list;
3887abb0f93cSkardel
3888abb0f93cSkardel while (asyncio_reader != NULL) {
3889b3d6264cSchristos /* callback may unlink and free asyncio_reader */
3890b3d6264cSchristos next_asyncio_reader = asyncio_reader->link;
3891335f7552Schristos if (FD_ISSET(asyncio_reader->fd, pfds))
3892b3d6264cSchristos (*asyncio_reader->receiver)(asyncio_reader);
3893b3d6264cSchristos asyncio_reader = next_asyncio_reader;
3894abb0f93cSkardel }
3895abb0f93cSkardel #endif /* HAS_ROUTING_SOCKET */
3896abb0f93cSkardel
3897abb0f93cSkardel /*
3898b3d6264cSchristos * Check for a response from a blocking child
3899abb0f93cSkardel */
3900b3d6264cSchristos for (idx = 0; idx < blocking_children_alloc; idx++) {
3901b3d6264cSchristos c = blocking_children[idx];
3902b3d6264cSchristos if (NULL == c || -1 == c->resp_read_pipe)
3903b3d6264cSchristos continue;
3904335f7552Schristos if (FD_ISSET(c->resp_read_pipe, pfds)) {
3905335f7552Schristos ++c->resp_ready_seen;
3906335f7552Schristos ++blocking_child_ready_seen;
3907b3d6264cSchristos }
3908b3d6264cSchristos }
3909abb0f93cSkardel
3910abb0f93cSkardel /* We've done our work */
3911335f7552Schristos #if defined(DEBUG_TIMING)
3912abb0f93cSkardel get_systime(&ts_e);
3913abb0f93cSkardel /*
3914abb0f93cSkardel * (ts_e - ts) is the amount of time we spent
3915abb0f93cSkardel * processing this gob of file descriptors. Log
3916abb0f93cSkardel * it.
3917abb0f93cSkardel */
3918abb0f93cSkardel L_SUB(&ts_e, &ts);
3919abb0f93cSkardel collect_timing(NULL, "input handler", 1, &ts_e);
3920abb0f93cSkardel if (debug > 3)
3921abb0f93cSkardel msyslog(LOG_DEBUG,
3922abb0f93cSkardel "input_handler: Processed a gob of fd's in %s msec",
3923abb0f93cSkardel lfptoms(&ts_e, 6));
3924b3d6264cSchristos #endif /* DEBUG_TIMING */
3925abb0f93cSkardel }
3926b3d6264cSchristos #endif /* !HAVE_IO_COMPLETION_PORT */
3927b3d6264cSchristos
3928b3d6264cSchristos /*
3929b3d6264cSchristos * find an interface suitable for the src address
3930b3d6264cSchristos */
3931b3d6264cSchristos endpt *
3932b3d6264cSchristos select_peerinterface(
3933b3d6264cSchristos struct peer * peer,
3934b3d6264cSchristos sockaddr_u * srcadr,
3935b3d6264cSchristos endpt * dstadr
3936b3d6264cSchristos )
3937b3d6264cSchristos {
3938b3d6264cSchristos endpt *ep;
3939b3d6264cSchristos #ifndef SIM
3940b3d6264cSchristos endpt *wild;
3941b3d6264cSchristos
3942b3d6264cSchristos wild = ANY_INTERFACE_CHOOSE(srcadr);
3943b3d6264cSchristos
3944b3d6264cSchristos /*
3945b3d6264cSchristos * Initialize the peer structure and dance the interface jig.
3946b3d6264cSchristos * Reference clocks step the loopback waltz, the others
3947b3d6264cSchristos * squaredance around the interface list looking for a buddy. If
3948b3d6264cSchristos * the dance peters out, there is always the wildcard interface.
3949b3d6264cSchristos * This might happen in some systems and would preclude proper
3950b3d6264cSchristos * operation with public key cryptography.
3951b3d6264cSchristos */
3952b3d6264cSchristos if (ISREFCLOCKADR(srcadr)) {
3953b3d6264cSchristos ep = loopback_interface;
3954b3d6264cSchristos } else if (peer->cast_flags &
3955b3d6264cSchristos (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) {
3956b3d6264cSchristos ep = findbcastinter(srcadr);
3957b3d6264cSchristos if (ep != NULL)
3958b3d6264cSchristos DPRINTF(4, ("Found *-cast interface %s for address %s\n",
3959b3d6264cSchristos stoa(&ep->sin), stoa(srcadr)));
3960b3d6264cSchristos else
3961b3d6264cSchristos DPRINTF(4, ("No *-cast local address found for address %s\n",
3962b3d6264cSchristos stoa(srcadr)));
3963b3d6264cSchristos } else {
3964b3d6264cSchristos ep = dstadr;
3965b3d6264cSchristos if (NULL == ep)
3966b3d6264cSchristos ep = wild;
3967b3d6264cSchristos }
3968b3d6264cSchristos /*
3969b3d6264cSchristos * If it is a multicast address, findbcastinter() may not find
3970b3d6264cSchristos * it. For unicast, we get to find the interface when dstadr is
3971b3d6264cSchristos * given to us as the wildcard (ANY_INTERFACE_CHOOSE). Either
3972b3d6264cSchristos * way, try a little harder.
3973b3d6264cSchristos */
3974b3d6264cSchristos if (wild == ep)
3975b3d6264cSchristos ep = findinterface(srcadr);
3976b3d6264cSchristos /*
3977b3d6264cSchristos * we do not bind to the wildcard interfaces for output
3978b3d6264cSchristos * as our (network) source address would be undefined and
3979b3d6264cSchristos * crypto will not work without knowing the own transmit address
3980b3d6264cSchristos */
3981b3d6264cSchristos if (ep != NULL && INT_WILDCARD & ep->flags)
3982b3d6264cSchristos if (!accept_wildcard_if_for_winnt)
3983b3d6264cSchristos ep = NULL;
3984b3d6264cSchristos #else /* SIM follows */
3985b3d6264cSchristos ep = loopback_interface;
3986abb0f93cSkardel #endif
3987abb0f93cSkardel
3988b3d6264cSchristos return ep;
3989b3d6264cSchristos }
3990b3d6264cSchristos
3991b3d6264cSchristos
3992abb0f93cSkardel /*
3993abb0f93cSkardel * findinterface - find local interface corresponding to address
3994abb0f93cSkardel */
399545530cf1Skardel endpt *
3996abb0f93cSkardel findinterface(
3997abb0f93cSkardel sockaddr_u *addr
3998abb0f93cSkardel )
3999abb0f93cSkardel {
400045530cf1Skardel endpt *iface;
4001abb0f93cSkardel
4002abb0f93cSkardel iface = findlocalinterface(addr, INT_WILDCARD, 0);
4003abb0f93cSkardel
4004abb0f93cSkardel if (NULL == iface) {
4005abb0f93cSkardel DPRINTF(4, ("Found no interface for address %s - returning wildcard\n",
4006abb0f93cSkardel stoa(addr)));
4007abb0f93cSkardel
4008abb0f93cSkardel iface = ANY_INTERFACE_CHOOSE(addr);
4009abb0f93cSkardel } else
4010abb0f93cSkardel DPRINTF(4, ("Found interface #%d %s for address %s\n",
4011abb0f93cSkardel iface->ifnum, iface->name, stoa(addr)));
4012abb0f93cSkardel
4013abb0f93cSkardel return iface;
4014abb0f93cSkardel }
4015abb0f93cSkardel
4016abb0f93cSkardel /*
4017abb0f93cSkardel * findlocalinterface - find local interface corresponding to addr,
4018abb0f93cSkardel * which does not have any of flags set. If bast is nonzero, addr is
4019abb0f93cSkardel * a broadcast address.
4020abb0f93cSkardel *
4021abb0f93cSkardel * This code attempts to find the local sending address for an outgoing
4022abb0f93cSkardel * address by connecting a new socket to destinationaddress:NTP_PORT
4023abb0f93cSkardel * and reading the sockname of the resulting connect.
4024abb0f93cSkardel * the complicated sequence simulates the routing table lookup
4025abb0f93cSkardel * for to first hop without duplicating any of the routing logic into
4026abb0f93cSkardel * ntpd. preferably we would have used an API call - but its not there -
4027abb0f93cSkardel * so this is the best we can do here short of duplicating to entire routing
4028abb0f93cSkardel * logic in ntpd which would be a silly and really unportable thing to do.
4029abb0f93cSkardel *
4030abb0f93cSkardel */
403145530cf1Skardel static endpt *
4032abb0f93cSkardel findlocalinterface(
4033abb0f93cSkardel sockaddr_u * addr,
4034abb0f93cSkardel int flags,
4035abb0f93cSkardel int bcast
4036abb0f93cSkardel )
4037abb0f93cSkardel {
4038abb0f93cSkardel GETSOCKNAME_SOCKLEN_TYPE sockaddrlen;
403945530cf1Skardel endpt * iface;
4040abb0f93cSkardel sockaddr_u saddr;
4041abb0f93cSkardel SOCKET s;
4042abb0f93cSkardel int rtn;
4043abb0f93cSkardel int on;
4044abb0f93cSkardel
4045abb0f93cSkardel DPRINTF(4, ("Finding interface for addr %s in list of addresses\n",
4046abb0f93cSkardel stoa(addr)));
4047abb0f93cSkardel
4048169394abSchristos /* [Bug 3437] The dummy POOL peer comes in with an AF of
4049169394abSchristos * zero. This is bound to fail, but on the way to nowhere it
4050169394abSchristos * triggers a security incident on SELinux.
4051169394abSchristos *
4052169394abSchristos * Checking the condition and failing early is probably a good
4053169394abSchristos * advice, and even saves us some syscalls in that case.
4054169394abSchristos * Thanks to Miroslav Lichvar for finding this.
4055169394abSchristos */
4056169394abSchristos if (AF_UNSPEC == AF(addr))
4057169394abSchristos return NULL;
4058169394abSchristos
4059abb0f93cSkardel s = socket(AF(addr), SOCK_DGRAM, 0);
4060abb0f93cSkardel if (INVALID_SOCKET == s)
4061abb0f93cSkardel return NULL;
4062abb0f93cSkardel
4063abb0f93cSkardel /*
4064abb0f93cSkardel * If we are looking for broadcast interface we need to set this
4065abb0f93cSkardel * socket to allow broadcast
4066abb0f93cSkardel */
4067abb0f93cSkardel if (bcast) {
4068abb0f93cSkardel on = 1;
4069b3d6264cSchristos if (SOCKET_ERROR == setsockopt(s, SOL_SOCKET,
4070b3d6264cSchristos SO_BROADCAST,
4071169394abSchristos (void *)&on,
4072b3d6264cSchristos sizeof(on))) {
4073b3d6264cSchristos closesocket(s);
4074b3d6264cSchristos return NULL;
4075b3d6264cSchristos }
4076abb0f93cSkardel }
4077abb0f93cSkardel
4078abb0f93cSkardel rtn = connect(s, &addr->sa, SOCKLEN(addr));
4079abb0f93cSkardel if (SOCKET_ERROR == rtn) {
4080abb0f93cSkardel closesocket(s);
4081abb0f93cSkardel return NULL;
4082abb0f93cSkardel }
4083abb0f93cSkardel
4084abb0f93cSkardel sockaddrlen = sizeof(saddr);
4085abb0f93cSkardel rtn = getsockname(s, &saddr.sa, &sockaddrlen);
4086abb0f93cSkardel closesocket(s);
4087abb0f93cSkardel if (SOCKET_ERROR == rtn)
4088abb0f93cSkardel return NULL;
4089abb0f93cSkardel
4090abb0f93cSkardel DPRINTF(4, ("findlocalinterface: kernel maps %s to %s\n",
4091abb0f93cSkardel stoa(addr), stoa(&saddr)));
4092abb0f93cSkardel
4093abb0f93cSkardel iface = getinterface(&saddr, flags);
4094abb0f93cSkardel
4095abb0f93cSkardel /*
409645530cf1Skardel * if we didn't find an exact match on saddr, find the closest
409745530cf1Skardel * available local address. This handles the case of the
409845530cf1Skardel * address suggested by the kernel being excluded by nic rules
409945530cf1Skardel * or the user's -I and -L options to ntpd.
410045530cf1Skardel * See http://bugs.ntp.org/1184 and http://bugs.ntp.org/1683
410145530cf1Skardel * for more background.
4102abb0f93cSkardel */
4103abb0f93cSkardel if (NULL == iface || iface->ignore_packets)
410445530cf1Skardel iface = findclosestinterface(&saddr,
410545530cf1Skardel flags | INT_LOOPBACK);
4106abb0f93cSkardel
4107abb0f93cSkardel /* Don't use an interface which will ignore replies */
4108abb0f93cSkardel if (iface != NULL && iface->ignore_packets)
4109abb0f93cSkardel iface = NULL;
4110abb0f93cSkardel
4111abb0f93cSkardel return iface;
4112abb0f93cSkardel }
4113abb0f93cSkardel
4114abb0f93cSkardel
4115abb0f93cSkardel /*
411645530cf1Skardel * findclosestinterface
411745530cf1Skardel *
411845530cf1Skardel * If there are -I/--interface or -L/novirtualips command-line options,
411945530cf1Skardel * or "nic" or "interface" rules in ntp.conf, findlocalinterface() may
412045530cf1Skardel * find the kernel's preferred local address for a given peer address is
412145530cf1Skardel * administratively unavailable to ntpd, and punt to this routine's more
412245530cf1Skardel * expensive search.
412345530cf1Skardel *
412445530cf1Skardel * Find the numerically closest local address to the one connect()
412545530cf1Skardel * suggested. This matches an address on the same subnet first, as
412645530cf1Skardel * needed by Bug 1184, and provides a consistent choice if there are
412745530cf1Skardel * multiple feasible local addresses, regardless of the order ntpd
412845530cf1Skardel * enumerated them.
4129abb0f93cSkardel */
4130b3d6264cSchristos endpt *
413145530cf1Skardel findclosestinterface(
4132abb0f93cSkardel sockaddr_u * addr,
4133abb0f93cSkardel int flags
4134abb0f93cSkardel )
4135abb0f93cSkardel {
413645530cf1Skardel endpt * ep;
413745530cf1Skardel endpt * winner;
413845530cf1Skardel sockaddr_u addr_dist;
413945530cf1Skardel sockaddr_u min_dist;
414045530cf1Skardel
4141b3d6264cSchristos ZERO_SOCK(&min_dist);
414245530cf1Skardel winner = NULL;
414345530cf1Skardel
414445530cf1Skardel for (ep = ep_list; ep != NULL; ep = ep->elink) {
414545530cf1Skardel if (ep->ignore_packets ||
414645530cf1Skardel AF(addr) != ep->family ||
414745530cf1Skardel flags & ep->flags)
414845530cf1Skardel continue;
414945530cf1Skardel
415045530cf1Skardel calc_addr_distance(&addr_dist, addr, &ep->sin);
415145530cf1Skardel if (NULL == winner ||
415245530cf1Skardel -1 == cmp_addr_distance(&addr_dist, &min_dist)) {
415345530cf1Skardel min_dist = addr_dist;
415445530cf1Skardel winner = ep;
415545530cf1Skardel }
415645530cf1Skardel }
415745530cf1Skardel if (NULL == winner)
415845530cf1Skardel DPRINTF(4, ("findclosestinterface(%s) failed\n",
415945530cf1Skardel stoa(addr)));
416045530cf1Skardel else
416145530cf1Skardel DPRINTF(4, ("findclosestinterface(%s) -> %s\n",
416245530cf1Skardel stoa(addr), stoa(&winner->sin)));
416345530cf1Skardel
416445530cf1Skardel return winner;
416545530cf1Skardel }
416645530cf1Skardel
416745530cf1Skardel
416845530cf1Skardel /*
416945530cf1Skardel * calc_addr_distance - calculate the distance between two addresses,
417045530cf1Skardel * the absolute value of the difference between
417145530cf1Skardel * the addresses numerically, stored as an address.
417245530cf1Skardel */
417345530cf1Skardel static void
417445530cf1Skardel calc_addr_distance(
417545530cf1Skardel sockaddr_u * dist,
417645530cf1Skardel const sockaddr_u * a1,
417745530cf1Skardel const sockaddr_u * a2
417845530cf1Skardel )
417945530cf1Skardel {
418045530cf1Skardel u_int32 a1val;
418145530cf1Skardel u_int32 a2val;
418245530cf1Skardel u_int32 v4dist;
418345530cf1Skardel int found_greater;
418445530cf1Skardel int a1_greater;
418545530cf1Skardel int i;
418645530cf1Skardel
418709f14f80Schristos REQUIRE(AF(a1) == AF(a2));
418845530cf1Skardel
4189b3d6264cSchristos ZERO_SOCK(dist);
419045530cf1Skardel AF(dist) = AF(a1);
419145530cf1Skardel
419245530cf1Skardel /* v4 can be done a bit simpler */
419345530cf1Skardel if (IS_IPV4(a1)) {
419445530cf1Skardel a1val = SRCADR(a1);
419545530cf1Skardel a2val = SRCADR(a2);
419645530cf1Skardel v4dist = (a1val > a2val)
419745530cf1Skardel ? a1val - a2val
419845530cf1Skardel : a2val - a1val;
419945530cf1Skardel SET_ADDR4(dist, v4dist);
420045530cf1Skardel
420145530cf1Skardel return;
420245530cf1Skardel }
420345530cf1Skardel
420445530cf1Skardel found_greater = FALSE;
420545530cf1Skardel a1_greater = FALSE; /* suppress pot. uninit. warning */
4206f40817b7Skardel for (i = 0; i < (int)sizeof(NSRCADR6(a1)); i++) {
420745530cf1Skardel if (!found_greater &&
420845530cf1Skardel NSRCADR6(a1)[i] != NSRCADR6(a2)[i]) {
420945530cf1Skardel found_greater = TRUE;
421045530cf1Skardel a1_greater = (NSRCADR6(a1)[i] > NSRCADR6(a2)[i]);
421145530cf1Skardel }
421245530cf1Skardel if (!found_greater) {
421345530cf1Skardel NSRCADR6(dist)[i] = 0;
421445530cf1Skardel } else {
421545530cf1Skardel if (a1_greater)
421645530cf1Skardel NSRCADR6(dist)[i] = NSRCADR6(a1)[i] -
421745530cf1Skardel NSRCADR6(a2)[i];
421845530cf1Skardel else
421945530cf1Skardel NSRCADR6(dist)[i] = NSRCADR6(a2)[i] -
422045530cf1Skardel NSRCADR6(a1)[i];
422145530cf1Skardel }
422245530cf1Skardel }
422345530cf1Skardel }
422445530cf1Skardel
422545530cf1Skardel
422645530cf1Skardel /*
422745530cf1Skardel * cmp_addr_distance - compare two address distances, returning -1, 0,
422845530cf1Skardel * 1 to indicate their relationship.
422945530cf1Skardel */
423045530cf1Skardel static int
423145530cf1Skardel cmp_addr_distance(
423245530cf1Skardel const sockaddr_u * d1,
423345530cf1Skardel const sockaddr_u * d2
423445530cf1Skardel )
423545530cf1Skardel {
423645530cf1Skardel int i;
423745530cf1Skardel
423809f14f80Schristos REQUIRE(AF(d1) == AF(d2));
423945530cf1Skardel
424045530cf1Skardel if (IS_IPV4(d1)) {
424145530cf1Skardel if (SRCADR(d1) < SRCADR(d2))
424245530cf1Skardel return -1;
424345530cf1Skardel else if (SRCADR(d1) == SRCADR(d2))
424445530cf1Skardel return 0;
424545530cf1Skardel else
424645530cf1Skardel return 1;
424745530cf1Skardel }
424845530cf1Skardel
4249f40817b7Skardel for (i = 0; i < (int)sizeof(NSRCADR6(d1)); i++) {
425045530cf1Skardel if (NSRCADR6(d1)[i] < NSRCADR6(d2)[i])
425145530cf1Skardel return -1;
425245530cf1Skardel else if (NSRCADR6(d1)[i] > NSRCADR6(d2)[i])
425345530cf1Skardel return 1;
425445530cf1Skardel }
425545530cf1Skardel
425645530cf1Skardel return 0;
425745530cf1Skardel }
425845530cf1Skardel
425945530cf1Skardel
426045530cf1Skardel
426145530cf1Skardel /*
426245530cf1Skardel * fetch an interface structure the matches the
426345530cf1Skardel * address and has the given flags NOT set
426445530cf1Skardel */
4265b3d6264cSchristos endpt *
426645530cf1Skardel getinterface(
426745530cf1Skardel sockaddr_u * addr,
426845530cf1Skardel u_int32 flags
426945530cf1Skardel )
427045530cf1Skardel {
427145530cf1Skardel endpt *iface;
4272abb0f93cSkardel
4273abb0f93cSkardel iface = find_addr_in_list(addr);
4274abb0f93cSkardel
4275abb0f93cSkardel if (iface != NULL && (iface->flags & flags))
4276abb0f93cSkardel iface = NULL;
4277abb0f93cSkardel
4278abb0f93cSkardel return iface;
4279abb0f93cSkardel }
4280abb0f93cSkardel
4281abb0f93cSkardel
4282abb0f93cSkardel /*
4283abb0f93cSkardel * findbcastinter - find broadcast interface corresponding to address
4284abb0f93cSkardel */
428545530cf1Skardel endpt *
4286abb0f93cSkardel findbcastinter(
4287abb0f93cSkardel sockaddr_u *addr
4288abb0f93cSkardel )
4289abb0f93cSkardel {
4290b3d6264cSchristos endpt * iface;
4291b3d6264cSchristos
4292b3d6264cSchristos iface = NULL;
4293abb0f93cSkardel #if !defined(MPE) && (defined(SIOCGIFCONF) || defined(SYS_WINNT))
4294abb0f93cSkardel DPRINTF(4, ("Finding broadcast/multicast interface for addr %s in list of addresses\n",
4295abb0f93cSkardel stoa(addr)));
4296abb0f93cSkardel
4297abb0f93cSkardel iface = findlocalinterface(addr, INT_LOOPBACK | INT_WILDCARD,
4298abb0f93cSkardel 1);
4299abb0f93cSkardel if (iface != NULL) {
4300abb0f93cSkardel DPRINTF(4, ("Easily found bcast-/mcast- interface index #%d %s\n",
4301abb0f93cSkardel iface->ifnum, iface->name));
4302abb0f93cSkardel return iface;
4303abb0f93cSkardel }
4304abb0f93cSkardel
4305abb0f93cSkardel /*
4306abb0f93cSkardel * plan B - try to find something reasonable in our lists in
4307abb0f93cSkardel * case kernel lookup doesn't help
4308abb0f93cSkardel */
430945530cf1Skardel for (iface = ep_list; iface != NULL; iface = iface->elink) {
4310abb0f93cSkardel if (iface->flags & INT_WILDCARD)
4311abb0f93cSkardel continue;
4312abb0f93cSkardel
4313abb0f93cSkardel /* Don't bother with ignored interfaces */
4314abb0f93cSkardel if (iface->ignore_packets)
4315abb0f93cSkardel continue;
4316abb0f93cSkardel
4317abb0f93cSkardel /*
4318abb0f93cSkardel * First look if this is the correct family
4319abb0f93cSkardel */
4320abb0f93cSkardel if(AF(&iface->sin) != AF(addr))
4321abb0f93cSkardel continue;
4322abb0f93cSkardel
4323abb0f93cSkardel /* Skip the loopback addresses */
4324abb0f93cSkardel if (iface->flags & INT_LOOPBACK)
4325abb0f93cSkardel continue;
4326abb0f93cSkardel
4327abb0f93cSkardel /*
4328abb0f93cSkardel * If we are looking to match a multicast address and
4329abb0f93cSkardel * this interface is one...
4330abb0f93cSkardel */
4331abb0f93cSkardel if (addr_ismulticast(addr)
4332abb0f93cSkardel && (iface->flags & INT_MULTICAST)) {
4333abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT
4334abb0f93cSkardel /*
4335abb0f93cSkardel * ...it is the winner unless we're looking for
4336abb0f93cSkardel * an interface to use for link-local multicast
4337abb0f93cSkardel * and its address is not link-local.
4338abb0f93cSkardel */
4339abb0f93cSkardel if (IS_IPV6(addr)
4340abb0f93cSkardel && IN6_IS_ADDR_MC_LINKLOCAL(PSOCK_ADDR6(addr))
4341abb0f93cSkardel && !IN6_IS_ADDR_LINKLOCAL(PSOCK_ADDR6(&iface->sin)))
4342abb0f93cSkardel continue;
4343abb0f93cSkardel #endif
4344abb0f93cSkardel break;
4345abb0f93cSkardel }
4346abb0f93cSkardel
4347abb0f93cSkardel /*
4348abb0f93cSkardel * We match only those interfaces marked as
4349abb0f93cSkardel * broadcastable and either the explicit broadcast
4350abb0f93cSkardel * address or the network portion of the IP address.
4351abb0f93cSkardel * Sloppy.
4352abb0f93cSkardel */
4353abb0f93cSkardel if (IS_IPV4(addr)) {
4354abb0f93cSkardel if (SOCK_EQ(&iface->bcast, addr))
4355abb0f93cSkardel break;
4356abb0f93cSkardel
4357abb0f93cSkardel if ((NSRCADR(&iface->sin) & NSRCADR(&iface->mask))
4358abb0f93cSkardel == (NSRCADR(addr) & NSRCADR(&iface->mask)))
4359abb0f93cSkardel break;
4360abb0f93cSkardel }
4361abb0f93cSkardel #ifdef INCLUDE_IPV6_SUPPORT
4362abb0f93cSkardel else if (IS_IPV6(addr)) {
4363abb0f93cSkardel if (SOCK_EQ(&iface->bcast, addr))
4364abb0f93cSkardel break;
4365abb0f93cSkardel
4366abb0f93cSkardel if (SOCK_EQ(netof(&iface->sin), netof(addr)))
4367abb0f93cSkardel break;
4368abb0f93cSkardel }
4369abb0f93cSkardel #endif
4370abb0f93cSkardel }
4371abb0f93cSkardel #endif /* SIOCGIFCONF */
4372abb0f93cSkardel if (NULL == iface) {
4373abb0f93cSkardel DPRINTF(4, ("No bcast interface found for %s\n",
4374abb0f93cSkardel stoa(addr)));
4375abb0f93cSkardel iface = ANY_INTERFACE_CHOOSE(addr);
4376b3d6264cSchristos } else {
4377abb0f93cSkardel DPRINTF(4, ("Found bcast-/mcast- interface index #%d %s\n",
4378abb0f93cSkardel iface->ifnum, iface->name));
4379b3d6264cSchristos }
4380b3d6264cSchristos
4381abb0f93cSkardel return iface;
4382abb0f93cSkardel }
4383abb0f93cSkardel
4384abb0f93cSkardel
4385abb0f93cSkardel /*
4386abb0f93cSkardel * io_clr_stats - clear I/O module statistics
4387abb0f93cSkardel */
4388abb0f93cSkardel void
4389abb0f93cSkardel io_clr_stats(void)
4390abb0f93cSkardel {
4391abb0f93cSkardel packets_dropped = 0;
4392abb0f93cSkardel packets_ignored = 0;
4393abb0f93cSkardel packets_received = 0;
4394abb0f93cSkardel packets_sent = 0;
4395abb0f93cSkardel packets_notsent = 0;
4396abb0f93cSkardel
4397abb0f93cSkardel handler_calls = 0;
4398abb0f93cSkardel handler_pkts = 0;
4399abb0f93cSkardel io_timereset = current_time;
4400abb0f93cSkardel }
4401abb0f93cSkardel
4402abb0f93cSkardel
4403abb0f93cSkardel #ifdef REFCLOCK
4404abb0f93cSkardel /*
4405abb0f93cSkardel * io_addclock - add a reference clock to the list and arrange that we
4406abb0f93cSkardel * get SIGIO interrupts from it.
4407abb0f93cSkardel */
4408abb0f93cSkardel int
4409abb0f93cSkardel io_addclock(
4410abb0f93cSkardel struct refclockio *rio
4411abb0f93cSkardel )
4412abb0f93cSkardel {
4413abb0f93cSkardel BLOCKIO();
4414abb0f93cSkardel
4415abb0f93cSkardel /*
4416abb0f93cSkardel * Stuff the I/O structure in the list and mark the descriptor
4417abb0f93cSkardel * in use. There is a harmless (I hope) race condition here.
4418abb0f93cSkardel */
4419b3d6264cSchristos rio->active = TRUE;
4420abb0f93cSkardel
4421abb0f93cSkardel # ifdef HAVE_SIGNALED_IO
4422abb0f93cSkardel if (init_clock_sig(rio)) {
4423abb0f93cSkardel UNBLOCKIO();
4424abb0f93cSkardel return 0;
4425abb0f93cSkardel }
4426abb0f93cSkardel # elif defined(HAVE_IO_COMPLETION_PORT)
4427335f7552Schristos if (!io_completion_port_add_clock_io(rio)) {
4428abb0f93cSkardel UNBLOCKIO();
4429abb0f93cSkardel return 0;
4430abb0f93cSkardel }
4431abb0f93cSkardel # endif
4432abb0f93cSkardel
4433abb0f93cSkardel /*
4434abb0f93cSkardel * enqueue
4435abb0f93cSkardel */
4436b3d6264cSchristos LINK_SLIST(refio, rio, next);
4437abb0f93cSkardel
4438abb0f93cSkardel /*
4439abb0f93cSkardel * register fd
4440abb0f93cSkardel */
4441abb0f93cSkardel add_fd_to_list(rio->fd, FD_TYPE_FILE);
4442abb0f93cSkardel
4443abb0f93cSkardel UNBLOCKIO();
4444abb0f93cSkardel return 1;
4445abb0f93cSkardel }
4446abb0f93cSkardel
4447b3d6264cSchristos
4448abb0f93cSkardel /*
4449abb0f93cSkardel * io_closeclock - close the clock in the I/O structure given
4450abb0f93cSkardel */
4451abb0f93cSkardel void
4452abb0f93cSkardel io_closeclock(
4453abb0f93cSkardel struct refclockio *rio
4454abb0f93cSkardel )
4455abb0f93cSkardel {
4456b3d6264cSchristos struct refclockio *unlinked;
4457abb0f93cSkardel
4458abb0f93cSkardel BLOCKIO();
4459abb0f93cSkardel
4460abb0f93cSkardel /*
4461abb0f93cSkardel * Remove structure from the list
4462abb0f93cSkardel */
4463b3d6264cSchristos rio->active = FALSE;
4464b3d6264cSchristos UNLINK_SLIST(unlinked, refio, rio, next, struct refclockio);
4465b3d6264cSchristos if (NULL != unlinked) {
4466335f7552Schristos /* Close the descriptor. The order of operations is
4467335f7552Schristos * important here in case of async / overlapped IO:
4468335f7552Schristos * only after we have removed the clock from the
4469335f7552Schristos * IO completion port we can be sure no further
4470335f7552Schristos * input is queued. So...
4471335f7552Schristos * - we first disable feeding to the queu by removing
4472335f7552Schristos * the clock from the IO engine
4473335f7552Schristos * - close the file (which brings down any IO on it)
4474335f7552Schristos * - clear the buffer from results for this fd
4475abb0f93cSkardel */
4476335f7552Schristos # ifdef HAVE_IO_COMPLETION_PORT
4477335f7552Schristos io_completion_port_remove_clock_io(rio);
4478335f7552Schristos # endif
4479abb0f93cSkardel close_and_delete_fd_from_list(rio->fd);
4480335f7552Schristos purge_recv_buffers_for_fd(rio->fd);
4481b3d6264cSchristos rio->fd = -1;
4482335f7552Schristos }
4483b3d6264cSchristos
4484abb0f93cSkardel UNBLOCKIO();
4485abb0f93cSkardel }
4486abb0f93cSkardel #endif /* REFCLOCK */
4487abb0f93cSkardel
4488b3d6264cSchristos
4489abb0f93cSkardel /*
4490abb0f93cSkardel * On NT a SOCKET is an unsigned int so we cannot possibly keep it in
4491abb0f93cSkardel * an array. So we use one of the ISC_LIST functions to hold the
4492abb0f93cSkardel * socket value and use that when we want to enumerate it.
4493abb0f93cSkardel *
4494abb0f93cSkardel * This routine is called by the forked intres child process to close
4495abb0f93cSkardel * all open sockets. On Windows there's no need as intres runs in
4496abb0f93cSkardel * the same process as a thread.
4497abb0f93cSkardel */
4498abb0f93cSkardel #ifndef SYS_WINNT
4499abb0f93cSkardel void
4500b3d6264cSchristos kill_asyncio(
4501b3d6264cSchristos int startfd
4502b3d6264cSchristos )
4503abb0f93cSkardel {
4504abb0f93cSkardel BLOCKIO();
4505abb0f93cSkardel
4506abb0f93cSkardel /*
4507abb0f93cSkardel * In the child process we do not maintain activefds and
4508abb0f93cSkardel * maxactivefd. Zeroing maxactivefd disables code which
4509abb0f93cSkardel * maintains it in close_and_delete_fd_from_list().
4510abb0f93cSkardel */
4511abb0f93cSkardel maxactivefd = 0;
4512abb0f93cSkardel
4513abb0f93cSkardel while (fd_list != NULL)
4514abb0f93cSkardel close_and_delete_fd_from_list(fd_list->fd);
4515abb0f93cSkardel
4516abb0f93cSkardel UNBLOCKIO();
4517abb0f93cSkardel }
4518abb0f93cSkardel #endif /* !SYS_WINNT */
4519abb0f93cSkardel
4520b3d6264cSchristos
4521abb0f93cSkardel /*
4522abb0f93cSkardel * Add and delete functions for the list of open sockets
4523abb0f93cSkardel */
4524abb0f93cSkardel static void
4525abb0f93cSkardel add_fd_to_list(
4526abb0f93cSkardel SOCKET fd,
4527abb0f93cSkardel enum desc_type type
4528abb0f93cSkardel )
4529abb0f93cSkardel {
4530abb0f93cSkardel vsock_t *lsock = emalloc(sizeof(*lsock));
4531abb0f93cSkardel
4532abb0f93cSkardel lsock->fd = fd;
4533abb0f93cSkardel lsock->type = type;
4534abb0f93cSkardel
4535abb0f93cSkardel LINK_SLIST(fd_list, lsock, link);
4536b3d6264cSchristos maintain_activefds(fd, 0);
4537abb0f93cSkardel }
4538abb0f93cSkardel
4539abb0f93cSkardel
4540abb0f93cSkardel static void
4541abb0f93cSkardel close_and_delete_fd_from_list(
4542abb0f93cSkardel SOCKET fd
4543abb0f93cSkardel )
4544abb0f93cSkardel {
4545abb0f93cSkardel vsock_t *lsock;
4546abb0f93cSkardel
4547abb0f93cSkardel UNLINK_EXPR_SLIST(lsock, fd_list, fd ==
4548abb0f93cSkardel UNLINK_EXPR_SLIST_CURRENT()->fd, link, vsock_t);
4549abb0f93cSkardel
4550b3d6264cSchristos if (NULL == lsock)
4551b3d6264cSchristos return;
4552b3d6264cSchristos
4553abb0f93cSkardel switch (lsock->type) {
4554b3d6264cSchristos
4555abb0f93cSkardel case FD_TYPE_SOCKET:
4556abb0f93cSkardel closesocket(lsock->fd);
4557abb0f93cSkardel break;
4558abb0f93cSkardel
4559abb0f93cSkardel case FD_TYPE_FILE:
4560bd25f4c4Schristos closeserial((int)lsock->fd);
4561abb0f93cSkardel break;
4562abb0f93cSkardel
4563abb0f93cSkardel default:
4564abb0f93cSkardel msyslog(LOG_ERR,
4565abb0f93cSkardel "internal error - illegal descriptor type %d - EXITING",
4566abb0f93cSkardel (int)lsock->type);
4567abb0f93cSkardel exit(1);
4568abb0f93cSkardel }
4569abb0f93cSkardel
4570abb0f93cSkardel free(lsock);
4571abb0f93cSkardel /*
4572abb0f93cSkardel * remove from activefds
4573abb0f93cSkardel */
4574b3d6264cSchristos maintain_activefds(fd, 1);
4575b3d6264cSchristos }
4576abb0f93cSkardel
4577abb0f93cSkardel
4578abb0f93cSkardel static void
4579abb0f93cSkardel add_addr_to_list(
4580abb0f93cSkardel sockaddr_u * addr,
458145530cf1Skardel endpt * ep
4582abb0f93cSkardel )
4583abb0f93cSkardel {
4584abb0f93cSkardel remaddr_t *laddr;
4585abb0f93cSkardel
4586abb0f93cSkardel #ifdef DEBUG
4587abb0f93cSkardel if (find_addr_in_list(addr) == NULL) {
4588abb0f93cSkardel #endif
4589abb0f93cSkardel /* not there yet - add to list */
4590abb0f93cSkardel laddr = emalloc(sizeof(*laddr));
459145530cf1Skardel laddr->addr = *addr;
459245530cf1Skardel laddr->ep = ep;
4593abb0f93cSkardel
4594abb0f93cSkardel LINK_SLIST(remoteaddr_list, laddr, link);
4595abb0f93cSkardel
4596abb0f93cSkardel DPRINTF(4, ("Added addr %s to list of addresses\n",
4597abb0f93cSkardel stoa(addr)));
4598abb0f93cSkardel #ifdef DEBUG
4599abb0f93cSkardel } else
4600abb0f93cSkardel DPRINTF(4, ("WARNING: Attempt to add duplicate addr %s to address list\n",
4601abb0f93cSkardel stoa(addr)));
4602abb0f93cSkardel #endif
4603abb0f93cSkardel }
4604abb0f93cSkardel
4605abb0f93cSkardel
4606abb0f93cSkardel static void
4607abb0f93cSkardel delete_addr_from_list(
4608abb0f93cSkardel sockaddr_u *addr
4609abb0f93cSkardel )
4610abb0f93cSkardel {
4611abb0f93cSkardel remaddr_t *unlinked;
4612abb0f93cSkardel
4613abb0f93cSkardel UNLINK_EXPR_SLIST(unlinked, remoteaddr_list, SOCK_EQ(addr,
4614abb0f93cSkardel &(UNLINK_EXPR_SLIST_CURRENT()->addr)), link, remaddr_t);
4615abb0f93cSkardel
4616abb0f93cSkardel if (unlinked != NULL) {
4617abb0f93cSkardel DPRINTF(4, ("Deleted addr %s from list of addresses\n",
4618abb0f93cSkardel stoa(addr)));
4619abb0f93cSkardel free(unlinked);
4620abb0f93cSkardel }
4621abb0f93cSkardel }
4622abb0f93cSkardel
4623abb0f93cSkardel
4624abb0f93cSkardel static void
4625abb0f93cSkardel delete_interface_from_list(
462645530cf1Skardel endpt *iface
4627abb0f93cSkardel )
4628abb0f93cSkardel {
4629abb0f93cSkardel remaddr_t *unlinked;
4630abb0f93cSkardel
4631ad131110Schristos for (;;) {
4632abb0f93cSkardel UNLINK_EXPR_SLIST(unlinked, remoteaddr_list, iface ==
463345530cf1Skardel UNLINK_EXPR_SLIST_CURRENT()->ep, link,
4634abb0f93cSkardel remaddr_t);
4635abb0f93cSkardel
4636ad131110Schristos if (unlinked == NULL)
4637ad131110Schristos break;
4638abb0f93cSkardel DPRINTF(4, ("Deleted addr %s for interface #%d %s from list of addresses\n",
4639abb0f93cSkardel stoa(&unlinked->addr), iface->ifnum,
4640abb0f93cSkardel iface->name));
4641abb0f93cSkardel free(unlinked);
4642abb0f93cSkardel }
4643abb0f93cSkardel }
4644abb0f93cSkardel
4645abb0f93cSkardel
4646abb0f93cSkardel static struct interface *
4647abb0f93cSkardel find_addr_in_list(
4648abb0f93cSkardel sockaddr_u *addr
4649abb0f93cSkardel )
4650abb0f93cSkardel {
4651abb0f93cSkardel remaddr_t *entry;
4652abb0f93cSkardel
4653abb0f93cSkardel DPRINTF(4, ("Searching for addr %s in list of addresses - ",
4654abb0f93cSkardel stoa(addr)));
4655abb0f93cSkardel
4656abb0f93cSkardel for (entry = remoteaddr_list;
4657abb0f93cSkardel entry != NULL;
4658abb0f93cSkardel entry = entry->link)
4659abb0f93cSkardel if (SOCK_EQ(&entry->addr, addr)) {
4660abb0f93cSkardel DPRINTF(4, ("FOUND\n"));
466145530cf1Skardel return entry->ep;
4662abb0f93cSkardel }
4663abb0f93cSkardel
4664abb0f93cSkardel DPRINTF(4, ("NOT FOUND\n"));
4665abb0f93cSkardel return NULL;
4666abb0f93cSkardel }
4667abb0f93cSkardel
4668abb0f93cSkardel
4669abb0f93cSkardel /*
4670abb0f93cSkardel * Find the given address with the all given flags set in the list
4671abb0f93cSkardel */
467245530cf1Skardel static endpt *
4673abb0f93cSkardel find_flagged_addr_in_list(
4674abb0f93cSkardel sockaddr_u * addr,
467545530cf1Skardel u_int32 flags
4676abb0f93cSkardel )
4677abb0f93cSkardel {
4678abb0f93cSkardel remaddr_t *entry;
4679abb0f93cSkardel
4680abb0f93cSkardel DPRINTF(4, ("Finding addr %s with flags %d in list: ",
4681abb0f93cSkardel stoa(addr), flags));
4682abb0f93cSkardel
4683abb0f93cSkardel for (entry = remoteaddr_list;
4684abb0f93cSkardel entry != NULL;
4685abb0f93cSkardel entry = entry->link)
4686abb0f93cSkardel
4687abb0f93cSkardel if (SOCK_EQ(&entry->addr, addr)
468845530cf1Skardel && (entry->ep->flags & flags) == flags) {
4689abb0f93cSkardel
4690abb0f93cSkardel DPRINTF(4, ("FOUND\n"));
469145530cf1Skardel return entry->ep;
4692abb0f93cSkardel }
4693abb0f93cSkardel
4694abb0f93cSkardel DPRINTF(4, ("NOT FOUND\n"));
4695abb0f93cSkardel return NULL;
4696abb0f93cSkardel }
4697abb0f93cSkardel
4698abb0f93cSkardel
469945530cf1Skardel const char *
470045530cf1Skardel localaddrtoa(
470145530cf1Skardel endpt *la
470245530cf1Skardel )
470345530cf1Skardel {
470445530cf1Skardel return (NULL == la)
470545530cf1Skardel ? "<null>"
470645530cf1Skardel : stoa(&la->sin);
470745530cf1Skardel }
470845530cf1Skardel
470945530cf1Skardel
4710abb0f93cSkardel #ifdef HAS_ROUTING_SOCKET
4711abb0f93cSkardel # ifndef UPDATE_GRACE
4712abb0f93cSkardel # define UPDATE_GRACE 2 /* wait UPDATE_GRACE seconds before scanning */
4713abb0f93cSkardel # endif
4714abb0f93cSkardel
4715abb0f93cSkardel static void
4716abb0f93cSkardel process_routing_msgs(struct asyncio_reader *reader)
4717abb0f93cSkardel {
4718abb0f93cSkardel char buffer[5120];
4719abb0f93cSkardel int cnt, msg_type;
4720abb0f93cSkardel #ifdef HAVE_RTNETLINK
4721abb0f93cSkardel struct nlmsghdr *nh;
4722abb0f93cSkardel #else
4723b3d6264cSchristos struct rt_msghdr rtm;
4724abb0f93cSkardel char *p;
4725abb0f93cSkardel #endif
4726abb0f93cSkardel
4727abb0f93cSkardel if (disable_dynamic_updates) {
4728abb0f93cSkardel /*
4729abb0f93cSkardel * discard ourselves if we are not needed any more
4730abb0f93cSkardel * usually happens when running unprivileged
4731abb0f93cSkardel */
4732abb0f93cSkardel remove_asyncio_reader(reader);
4733abb0f93cSkardel delete_asyncio_reader(reader);
4734abb0f93cSkardel return;
4735abb0f93cSkardel }
4736abb0f93cSkardel
4737abb0f93cSkardel cnt = read(reader->fd, buffer, sizeof(buffer));
4738abb0f93cSkardel
4739abb0f93cSkardel if (cnt < 0) {
474009f14f80Schristos if (errno == ENOBUFS) {
4741436bf552Sroy msyslog(LOG_DEBUG,
4742436bf552Sroy "routing socket overflowed"
4743436bf552Sroy " - will update interfaces");
474427c1ab70Sroy /*
474527c1ab70Sroy * drain the routing socket as we need to update
474627c1ab70Sroy * the interfaces anyway
474727c1ab70Sroy */
474827c1ab70Sroy do {
474927c1ab70Sroy cnt = read(reader->fd, buffer, sizeof(buffer));
475027c1ab70Sroy } while (cnt != -1 || errno == ENOBUFS);
475127c1ab70Sroy timer_interfacetimeout(current_time + UPDATE_GRACE);
4752ee0588e9Sroy } else if (errno != EINTR) {
475309f14f80Schristos msyslog(LOG_ERR,
475409f14f80Schristos "routing socket reports: %m - disabling");
4755abb0f93cSkardel remove_asyncio_reader(reader);
4756abb0f93cSkardel delete_asyncio_reader(reader);
475709f14f80Schristos }
4758abb0f93cSkardel return;
4759abb0f93cSkardel }
4760abb0f93cSkardel
4761abb0f93cSkardel /*
4762abb0f93cSkardel * process routing message
4763abb0f93cSkardel */
4764abb0f93cSkardel #ifdef HAVE_RTNETLINK
4765bd25f4c4Schristos for (nh = UA_PTR(struct nlmsghdr, buffer);
4766abb0f93cSkardel NLMSG_OK(nh, cnt);
4767*e03b00c8Schristos nh = NLMSG_NEXT(nh, cnt))
4768*e03b00c8Schristos {
4769abb0f93cSkardel msg_type = nh->nlmsg_type;
4770abb0f93cSkardel #else
4771abb0f93cSkardel for (p = buffer;
4772abb0f93cSkardel (p + sizeof(struct rt_msghdr)) <= (buffer + cnt);
4773*e03b00c8Schristos p += rtm.rtm_msglen)
4774*e03b00c8Schristos {
4775b3d6264cSchristos memcpy(&rtm, p, sizeof(rtm));
4776b3d6264cSchristos if (rtm.rtm_version != RTM_VERSION) {
4777abb0f93cSkardel msyslog(LOG_ERR,
4778abb0f93cSkardel "version mismatch (got %d - expected %d) on routing socket - disabling",
4779b3d6264cSchristos rtm.rtm_version, RTM_VERSION);
4780abb0f93cSkardel
4781abb0f93cSkardel remove_asyncio_reader(reader);
4782abb0f93cSkardel delete_asyncio_reader(reader);
4783abb0f93cSkardel return;
4784abb0f93cSkardel }
4785b3d6264cSchristos msg_type = rtm.rtm_type;
4786abb0f93cSkardel #endif
4787abb0f93cSkardel switch (msg_type) {
4788abb0f93cSkardel #ifdef RTM_NEWADDR
4789abb0f93cSkardel case RTM_NEWADDR:
4790abb0f93cSkardel #endif
4791abb0f93cSkardel #ifdef RTM_DELADDR
4792abb0f93cSkardel case RTM_DELADDR:
4793abb0f93cSkardel #endif
4794abb0f93cSkardel #ifdef RTM_ADD
4795abb0f93cSkardel case RTM_ADD:
4796abb0f93cSkardel #endif
4797abb0f93cSkardel #ifdef RTM_DELETE
4798abb0f93cSkardel case RTM_DELETE:
4799abb0f93cSkardel #endif
4800abb0f93cSkardel #ifdef RTM_REDIRECT
4801abb0f93cSkardel case RTM_REDIRECT:
4802abb0f93cSkardel #endif
4803abb0f93cSkardel #ifdef RTM_CHANGE
4804abb0f93cSkardel case RTM_CHANGE:
4805abb0f93cSkardel #endif
4806abb0f93cSkardel #ifdef RTM_IFINFO
4807abb0f93cSkardel case RTM_IFINFO:
4808abb0f93cSkardel #endif
4809abb0f93cSkardel #ifdef RTM_NEWLINK
4810abb0f93cSkardel case RTM_NEWLINK:
4811abb0f93cSkardel #endif
4812abb0f93cSkardel #ifdef RTM_DELLINK
4813abb0f93cSkardel case RTM_DELLINK:
4814abb0f93cSkardel #endif
4815abb0f93cSkardel #ifdef RTM_NEWROUTE
4816abb0f93cSkardel case RTM_NEWROUTE:
4817abb0f93cSkardel #endif
4818abb0f93cSkardel #ifdef RTM_DELROUTE
4819abb0f93cSkardel case RTM_DELROUTE:
4820abb0f93cSkardel #endif
4821abb0f93cSkardel /*
4822abb0f93cSkardel * we are keen on new and deleted addresses and
4823abb0f93cSkardel * if an interface goes up and down or routing
4824abb0f93cSkardel * changes
4825abb0f93cSkardel */
4826abb0f93cSkardel DPRINTF(3, ("routing message op = %d: scheduling interface update\n",
4827abb0f93cSkardel msg_type));
4828abb0f93cSkardel timer_interfacetimeout(current_time + UPDATE_GRACE);
4829abb0f93cSkardel break;
4830abb0f93cSkardel #ifdef HAVE_RTNETLINK
4831abb0f93cSkardel case NLMSG_DONE:
4832abb0f93cSkardel /* end of multipart message */
4833abb0f93cSkardel return;
4834abb0f93cSkardel #endif
4835abb0f93cSkardel default:
4836abb0f93cSkardel /*
4837abb0f93cSkardel * the rest doesn't bother us.
4838abb0f93cSkardel */
4839abb0f93cSkardel DPRINTF(4, ("routing message op = %d: ignored\n",
4840abb0f93cSkardel msg_type));
4841abb0f93cSkardel break;
4842abb0f93cSkardel }
4843abb0f93cSkardel }
4844abb0f93cSkardel }
4845abb0f93cSkardel
4846abb0f93cSkardel /*
4847abb0f93cSkardel * set up routing notifications
4848abb0f93cSkardel */
4849abb0f93cSkardel static void
4850abb0f93cSkardel init_async_notifications()
4851abb0f93cSkardel {
4852abb0f93cSkardel struct asyncio_reader *reader;
4853abb0f93cSkardel #ifdef HAVE_RTNETLINK
4854abb0f93cSkardel int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
4855abb0f93cSkardel struct sockaddr_nl sa;
4856abb0f93cSkardel #else
4857abb0f93cSkardel int fd = socket(PF_ROUTE, SOCK_RAW, 0);
485827c1ab70Sroy #ifdef SO_RERROR
485927c1ab70Sroy int on = 1;
486027c1ab70Sroy #endif
4861abb0f93cSkardel #endif
4862867deecaSroy #ifdef RO_MSGFILTER
4863867deecaSroy unsigned char msgfilter[] = {
4864867deecaSroy #ifdef RTM_NEWADDR
4865867deecaSroy RTM_NEWADDR,
4866867deecaSroy #endif
4867867deecaSroy #ifdef RTM_DELADDR
4868867deecaSroy RTM_DELADDR,
4869867deecaSroy #endif
4870867deecaSroy #ifdef RTM_ADD
4871867deecaSroy RTM_ADD,
4872867deecaSroy #endif
4873867deecaSroy #ifdef RTM_DELETE
4874867deecaSroy RTM_DELETE,
4875867deecaSroy #endif
4876867deecaSroy #ifdef RTM_REDIRECT
4877867deecaSroy RTM_REDIRECT,
4878867deecaSroy #endif
4879867deecaSroy #ifdef RTM_CHANGE
4880867deecaSroy RTM_CHANGE,
4881867deecaSroy #endif
4882867deecaSroy #ifdef RTM_IFINFO
4883867deecaSroy RTM_IFINFO,
4884867deecaSroy #endif
4885867deecaSroy #ifdef RTM_NEWLINK
4886867deecaSroy RTM_NEWLINK,
4887867deecaSroy #endif
4888867deecaSroy #ifdef RTM_DELLINK
4889867deecaSroy RTM_DELLINK,
4890867deecaSroy #endif
4891867deecaSroy #ifdef RTM_NEWROUTE
4892867deecaSroy RTM_NEWROUTE,
4893867deecaSroy #endif
4894867deecaSroy #ifdef RTM_DELROUTE
4895867deecaSroy RTM_DELROUTE,
4896867deecaSroy #endif
4897867deecaSroy };
4898867deecaSroy #endif /* !RO_MSGFILTER */
4899867deecaSroy
4900abb0f93cSkardel if (fd < 0) {
4901abb0f93cSkardel msyslog(LOG_ERR,
4902abb0f93cSkardel "unable to open routing socket (%m) - using polled interface update");
4903abb0f93cSkardel return;
4904abb0f93cSkardel }
4905abb0f93cSkardel
4906abb0f93cSkardel fd = move_fd(fd);
4907abb0f93cSkardel #ifdef HAVE_RTNETLINK
4908b3d6264cSchristos ZERO(sa);
4909abb0f93cSkardel sa.nl_family = PF_NETLINK;
4910abb0f93cSkardel sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR
4911abb0f93cSkardel | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_ROUTE
4912abb0f93cSkardel | RTMGRP_IPV4_MROUTE | RTMGRP_IPV6_ROUTE
4913abb0f93cSkardel | RTMGRP_IPV6_MROUTE;
4914abb0f93cSkardel if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
4915abb0f93cSkardel msyslog(LOG_ERR,
4916abb0f93cSkardel "bind failed on routing socket (%m) - using polled interface update");
4917abb0f93cSkardel return;
4918abb0f93cSkardel }
4919abb0f93cSkardel #endif
4920867deecaSroy #ifdef RO_MSGFILTER
4921867deecaSroy if (setsockopt(fd, PF_ROUTE, RO_MSGFILTER,
4922867deecaSroy &msgfilter, sizeof(msgfilter)) == -1)
4923867deecaSroy msyslog(LOG_ERR, "RO_MSGFILTER: %m");
4924867deecaSroy #endif
492527c1ab70Sroy #ifdef SO_RERROR
492627c1ab70Sroy if (setsockopt(fd, SOL_SOCKET, SO_RERROR, &on, sizeof(on)) == -1)
492727c1ab70Sroy msyslog(LOG_ERR, "SO_RERROR: %m");
492827c1ab70Sroy #endif
4929b3d6264cSchristos make_socket_nonblocking(fd);
4930abb0f93cSkardel #if defined(HAVE_SIGNALED_IO)
4931abb0f93cSkardel init_socket_sig(fd);
4932abb0f93cSkardel #endif /* HAVE_SIGNALED_IO */
4933abb0f93cSkardel
4934abb0f93cSkardel reader = new_asyncio_reader();
4935abb0f93cSkardel
4936abb0f93cSkardel reader->fd = fd;
4937abb0f93cSkardel reader->receiver = process_routing_msgs;
4938abb0f93cSkardel
4939abb0f93cSkardel add_asyncio_reader(reader, FD_TYPE_SOCKET);
4940abb0f93cSkardel msyslog(LOG_INFO,
4941abb0f93cSkardel "Listening on routing socket on fd #%d for interface updates",
4942abb0f93cSkardel fd);
4943abb0f93cSkardel }
4944abb0f93cSkardel #else
4945abb0f93cSkardel /* HAS_ROUTING_SOCKET not defined */
4946abb0f93cSkardel static void
4947abb0f93cSkardel init_async_notifications(void)
4948abb0f93cSkardel {
4949abb0f93cSkardel }
4950abb0f93cSkardel #endif
4951b3d6264cSchristos
4952