blob: b0618338478ce689c3af6a483ebb9e137dd2cddd [file] [log] [blame]
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001/* dnsmasq is Copyright (c) 2000-2024 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelley9e4abcb2004-01-22 19:47:41 +000017#include "dnsmasq.h"
18
Simon Kelley7622fc02009-06-04 20:32:05 +010019#ifdef HAVE_LINUX_NETWORK
20
21int indextoname(int fd, int index, char *name)
22{
23 struct ifreq ifr;
24
25 if (index == 0)
26 return 0;
27
28 ifr.ifr_ifindex = index;
29 if (ioctl(fd, SIOCGIFNAME, &ifr) == -1)
30 return 0;
31
Petr Menšík47b45b22018-08-15 18:17:00 +020032 safe_strncpy(name, ifr.ifr_name, IF_NAMESIZE);
Simon Kelley7622fc02009-06-04 20:32:05 +010033
Tarun Kundu12e3b2e2024-08-15 16:16:53 -070034 return 1;
Simon Kelley7622fc02009-06-04 20:32:05 +010035}
36
Simon Kelley28866e92011-02-14 20:19:14 +000037
38#elif defined(HAVE_SOLARIS_NETWORK)
39
40#include <zone.h>
41#include <alloca.h>
42#ifndef LIFC_UNDER_IPMP
43# define LIFC_UNDER_IPMP 0
44#endif
45
46int indextoname(int fd, int index, char *name)
47{
48 int64_t lifc_flags;
49 struct lifnum lifn;
50 int numifs, bufsize, i;
51 struct lifconf lifc;
52 struct lifreq *lifrp;
53
54 if (index == 0)
55 return 0;
56
57 if (getzoneid() == GLOBAL_ZONEID)
58 {
59 if (!if_indextoname(index, name))
60 return 0;
61 return 1;
62 }
63
64 lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES | LIFC_UNDER_IPMP;
65 lifn.lifn_family = AF_UNSPEC;
66 lifn.lifn_flags = lifc_flags;
67 if (ioctl(fd, SIOCGLIFNUM, &lifn) < 0)
68 return 0;
69
70 numifs = lifn.lifn_count;
71 bufsize = numifs * sizeof(struct lifreq);
72
73 lifc.lifc_family = AF_UNSPEC;
74 lifc.lifc_flags = lifc_flags;
75 lifc.lifc_len = bufsize;
76 lifc.lifc_buf = alloca(bufsize);
77
78 if (ioctl(fd, SIOCGLIFCONF, &lifc) < 0)
79 return 0;
80
81 lifrp = lifc.lifc_req;
82 for (i = lifc.lifc_len / sizeof(struct lifreq); i; i--, lifrp++)
83 {
84 struct lifreq lifr;
Petr Menšík47b45b22018-08-15 18:17:00 +020085 safe_strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
Simon Kelley28866e92011-02-14 20:19:14 +000086 if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0)
87 return 0;
88
89 if (lifr.lifr_index == index) {
Petr Menšík47b45b22018-08-15 18:17:00 +020090 safe_strncpy(name, lifr.lifr_name, IF_NAMESIZE);
Simon Kelley28866e92011-02-14 20:19:14 +000091 return 1;
92 }
93 }
94 return 0;
95}
96
97
Simon Kelley7622fc02009-06-04 20:32:05 +010098#else
99
100int indextoname(int fd, int index, char *name)
101{
Simon Kelley115ac3e2013-05-20 11:28:32 +0100102 (void)fd;
103
Simon Kelley7622fc02009-06-04 20:32:05 +0100104 if (index == 0 || !if_indextoname(index, name))
105 return 0;
106
107 return 1;
108}
109
110#endif
111
Simon Kelleycc921df2019-01-02 22:48:59 +0000112int iface_check(int family, union all_addr *addr, char *name, int *auth)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000113{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000114 struct iname *tmp;
Simon Kelleyedf0bde2013-07-29 17:21:48 +0100115 int ret = 1, match_addr = 0;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100116
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700117 /* Note: have to check all and not bail out early, so that we set the "used" flags.
118 May be called with family == AF_LOCAL to check interface by name only. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100119
Simon Kelleyc72daea2012-01-05 21:33:27 +0000120 if (daemon->if_names || daemon->if_addrs)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100121 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100122 ret = 0;
123
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100124 for (tmp = daemon->if_names; tmp; tmp = tmp->next)
Simon Kelley49333cb2013-03-15 20:30:51 +0000125 if (tmp->name && wildcard_match(tmp->name, name))
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700126 {
127 tmp->flags |= INAME_USED;
128 ret = 1;
129 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100130
Simon Kelley429798f2012-12-10 20:45:53 +0000131 if (addr)
132 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
133 if (tmp->addr.sa.sa_family == family)
134 {
135 if (family == AF_INET &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000136 tmp->addr.in.sin_addr.s_addr == addr->addr4.s_addr)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700137 {
138 tmp->flags |= INAME_USED;
139 ret = match_addr = 1;
140 }
Simon Kelley429798f2012-12-10 20:45:53 +0000141 else if (family == AF_INET6 &&
142 IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
Simon Kelleycc921df2019-01-02 22:48:59 +0000143 &addr->addr6))
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700144 {
145 tmp->flags |= INAME_USED;
146 ret = match_addr = 1;
147 }
Simon Kelley429798f2012-12-10 20:45:53 +0000148 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100149 }
150
Simon Kelleyedf0bde2013-07-29 17:21:48 +0100151 if (!match_addr)
152 for (tmp = daemon->if_except; tmp; tmp = tmp->next)
153 if (tmp->name && wildcard_match(tmp->name, name))
154 ret = 0;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000155
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700156 if (auth)
Simon Kelley429798f2012-12-10 20:45:53 +0000157 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700158 *auth = 0;
159
160 for (tmp = daemon->authinterface; tmp; tmp = tmp->next)
161 if (tmp->name)
162 {
163 if (strcmp(tmp->name, name) == 0 &&
164 (tmp->addr.sa.sa_family == 0 || tmp->addr.sa.sa_family == family))
165 break;
166 }
167 else if (addr && tmp->addr.sa.sa_family == AF_INET && family == AF_INET &&
168 tmp->addr.in.sin_addr.s_addr == addr->addr4.s_addr)
169 break;
170 else if (addr && tmp->addr.sa.sa_family == AF_INET6 && family == AF_INET6 &&
171 IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, &addr->addr6))
172 break;
173
174 if (tmp)
175 {
176 *auth = 1;
177 ret = 1;
178 }
Simon Kelley429798f2012-12-10 20:45:53 +0000179 }
180
Simon Kelley309331f2006-04-22 15:05:01 +0100181 return ret;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100182}
Simon Kelleye25db1f2013-01-29 22:10:26 +0000183
184
Josh Soref730c6742017-02-06 16:14:04 +0000185/* Fix for problem that the kernel sometimes reports the loopback interface as the
Simon Kelleye25db1f2013-01-29 22:10:26 +0000186 arrival interface when a packet originates locally, even when sent to address of
187 an interface other than the loopback. Accept packet if it arrived via a loopback
188 interface, even when we're not accepting packets that way, as long as the destination
189 address is one we're believing. Interface list must be up-to-date before calling. */
Simon Kelleycc921df2019-01-02 22:48:59 +0000190int loopback_exception(int fd, int family, union all_addr *addr, char *name)
Simon Kelleye25db1f2013-01-29 22:10:26 +0000191{
192 struct ifreq ifr;
193 struct irec *iface;
194
Petr Menšík47b45b22018-08-15 18:17:00 +0200195 safe_strncpy(ifr.ifr_name, name, IF_NAMESIZE);
Simon Kelleye25db1f2013-01-29 22:10:26 +0000196 if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&
197 ifr.ifr_flags & IFF_LOOPBACK)
198 {
199 for (iface = daemon->interfaces; iface; iface = iface->next)
200 if (iface->addr.sa.sa_family == family)
201 {
202 if (family == AF_INET)
203 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000204 if (iface->addr.in.sin_addr.s_addr == addr->addr4.s_addr)
Simon Kelleye25db1f2013-01-29 22:10:26 +0000205 return 1;
206 }
Simon Kelleycc921df2019-01-02 22:48:59 +0000207 else if (IN6_ARE_ADDR_EQUAL(&iface->addr.in6.sin6_addr, &addr->addr6))
Simon Kelleye25db1f2013-01-29 22:10:26 +0000208 return 1;
Simon Kelleye25db1f2013-01-29 22:10:26 +0000209 }
210 }
211 return 0;
212}
213
Simon Kelley3f2873d2013-05-14 11:28:47 +0100214/* If we're configured with something like --interface=eth0:0 then we'll listen correctly
215 on the relevant address, but the name of the arrival interface, derived from the
216 index won't match the config. Check that we found an interface address for the arrival
217 interface: daemon->interfaces must be up-to-date. */
Simon Kelleycc921df2019-01-02 22:48:59 +0000218int label_exception(int index, int family, union all_addr *addr)
Simon Kelley3f2873d2013-05-14 11:28:47 +0100219{
220 struct irec *iface;
221
222 /* labels only supported on IPv4 addresses. */
223 if (family != AF_INET)
224 return 0;
225
226 for (iface = daemon->interfaces; iface; iface = iface->next)
227 if (iface->index == index && iface->addr.sa.sa_family == AF_INET &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000228 iface->addr.in.sin_addr.s_addr == addr->addr4.s_addr)
Simon Kelley3f2873d2013-05-14 11:28:47 +0100229 return 1;
230
231 return 0;
232}
233
Simon Kelley115ac3e2013-05-20 11:28:32 +0100234struct iface_param {
235 struct addrlist *spare;
236 int fd;
237};
238
239static int iface_allowed(struct iface_param *param, int if_index, char *label,
Simon Kelley47669362014-12-17 12:41:56 +0000240 union mysockaddr *addr, struct in_addr netmask, int prefixlen, int iface_flags)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100241{
242 struct irec *iface;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700243 struct cond_domain *cond;
Petr Menšíka8c14742021-03-02 21:38:02 +0000244 int loopback;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100245 struct ifreq ifr;
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100246 int tftp_ok = !!option_bool(OPT_TFTP);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700247 int dhcp4_ok = 1;
248 int dhcp6_ok = 1;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000249 int auth_dns = 0;
Petr Menšíkad59f272017-03-17 17:22:19 +0000250 int is_label = 0;
Simon Kelley91543f42013-09-23 12:41:20 +0100251#if defined(HAVE_DHCP) || defined(HAVE_TFTP)
Simon Kelley832af0b2007-01-21 20:01:28 +0000252 struct iname *tmp;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100253#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100254
Vladislav Grishenko3b195962013-11-26 11:08:21 +0000255 (void)prefixlen;
256
Simon Kelley115ac3e2013-05-20 11:28:32 +0100257 if (!indextoname(param->fd, if_index, ifr.ifr_name) ||
258 ioctl(param->fd, SIOCGIFFLAGS, &ifr) == -1)
259 return 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100260
261 loopback = ifr.ifr_flags & IFF_LOOPBACK;
Simon Kelley9380ba72012-04-16 14:41:56 +0100262
263 if (loopback)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700264 dhcp4_ok = dhcp6_ok = 0;
Simon Kelley3f2873d2013-05-14 11:28:47 +0100265
Simon Kelley115ac3e2013-05-20 11:28:32 +0100266 if (!label)
267 label = ifr.ifr_name;
Petr Menšíkad59f272017-03-17 17:22:19 +0000268 else
269 is_label = strcmp(label, ifr.ifr_name);
Simon Kelleyc8a80482014-03-05 14:29:54 +0000270
271 /* maintain a list of all addresses on all interfaces for --local-service option */
272 if (option_bool(OPT_LOCAL_SERVICE))
273 {
274 struct addrlist *al;
Simon Kelley115ac3e2013-05-20 11:28:32 +0100275
Simon Kelleyc8a80482014-03-05 14:29:54 +0000276 if (param->spare)
277 {
278 al = param->spare;
279 param->spare = al->next;
280 }
281 else
282 al = whine_malloc(sizeof(struct addrlist));
283
284 if (al)
285 {
286 al->next = daemon->interface_addrs;
287 daemon->interface_addrs = al;
288 al->prefixlen = prefixlen;
289
290 if (addr->sa.sa_family == AF_INET)
291 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000292 al->addr.addr4 = addr->in.sin_addr;
Simon Kelleyc8a80482014-03-05 14:29:54 +0000293 al->flags = 0;
294 }
Simon Kelleyc8a80482014-03-05 14:29:54 +0000295 else
296 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000297 al->addr.addr6 = addr->in6.sin6_addr;
Simon Kelleyc8a80482014-03-05 14:29:54 +0000298 al->flags = ADDRLIST_IPV6;
299 }
Simon Kelleyc8a80482014-03-05 14:29:54 +0000300 }
301 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000302
Simon Kelley115ac3e2013-05-20 11:28:32 +0100303 if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
Simon Kelley115ac3e2013-05-20 11:28:32 +0100304 {
305 struct interface_name *int_name;
306 struct addrlist *al;
Simon Kelley376d48c2013-11-13 13:04:30 +0000307#ifdef HAVE_AUTH
308 struct auth_zone *zone;
309 struct auth_name_list *name;
Simon Kelley115ac3e2013-05-20 11:28:32 +0100310
Simon Kelley376d48c2013-11-13 13:04:30 +0000311 /* Find subnets in auth_zones */
312 for (zone = daemon->auth_zones; zone; zone = zone->next)
313 for (name = zone->interface_names; name; name = name->next)
314 if (wildcard_match(name->name, label))
315 {
316 if (addr->sa.sa_family == AF_INET && (name->flags & AUTH4))
317 {
318 if (param->spare)
319 {
320 al = param->spare;
321 param->spare = al->next;
322 }
323 else
324 al = whine_malloc(sizeof(struct addrlist));
325
326 if (al)
327 {
328 al->next = zone->subnet;
329 zone->subnet = al;
330 al->prefixlen = prefixlen;
Simon Kelleycc921df2019-01-02 22:48:59 +0000331 al->addr.addr4 = addr->in.sin_addr;
Simon Kelley376d48c2013-11-13 13:04:30 +0000332 al->flags = 0;
333 }
334 }
335
Simon Kelley376d48c2013-11-13 13:04:30 +0000336 if (addr->sa.sa_family == AF_INET6 && (name->flags & AUTH6))
337 {
338 if (param->spare)
339 {
340 al = param->spare;
341 param->spare = al->next;
342 }
343 else
344 al = whine_malloc(sizeof(struct addrlist));
345
346 if (al)
347 {
348 al->next = zone->subnet;
349 zone->subnet = al;
Vladislav Grishenko3b195962013-11-26 11:08:21 +0000350 al->prefixlen = prefixlen;
Simon Kelleycc921df2019-01-02 22:48:59 +0000351 al->addr.addr6 = addr->in6.sin6_addr;
Simon Kelley376d48c2013-11-13 13:04:30 +0000352 al->flags = ADDRLIST_IPV6;
353 }
354 }
Simon Kelley376d48c2013-11-13 13:04:30 +0000355 }
356#endif
357
358 /* Update addresses from interface_names. These are a set independent
359 of the set we're listening on. */
Simon Kelley115ac3e2013-05-20 11:28:32 +0100360 for (int_name = daemon->int_names; int_name; int_name = int_name->next)
Simon Kelleyb7cf7542021-03-04 16:54:14 +0000361 if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0)
Simon Kelley115ac3e2013-05-20 11:28:32 +0100362 {
Simon Kelleyb7cf7542021-03-04 16:54:14 +0000363 struct addrlist *lp;
364
365 al = NULL;
366
367 if (addr->sa.sa_family == AF_INET && (int_name->flags & (IN4 | INP4)))
Simon Kelley115ac3e2013-05-20 11:28:32 +0100368 {
Simon Kelleyb7cf7542021-03-04 16:54:14 +0000369 struct in_addr newaddr = addr->in.sin_addr;
370
371 if (int_name->flags & INP4)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700372 newaddr.s_addr = (addr->in.sin_addr.s_addr & netmask.s_addr) |
373 (int_name->proto4.s_addr & ~netmask.s_addr);
Simon Kelleyb7cf7542021-03-04 16:54:14 +0000374
375 /* check for duplicates. */
376 for (lp = int_name->addr; lp; lp = lp->next)
377 if (lp->flags == 0 && lp->addr.addr4.s_addr == newaddr.s_addr)
378 break;
379
380 if (!lp)
381 {
382 if (param->spare)
383 {
384 al = param->spare;
385 param->spare = al->next;
386 }
387 else
388 al = whine_malloc(sizeof(struct addrlist));
389
390 if (al)
391 {
392 al->flags = 0;
393 al->addr.addr4 = newaddr;
394 }
395 }
Simon Kelley115ac3e2013-05-20 11:28:32 +0100396 }
Simon Kelleyb7cf7542021-03-04 16:54:14 +0000397
398 if (addr->sa.sa_family == AF_INET6 && (int_name->flags & (IN6 | INP6)))
399 {
400 struct in6_addr newaddr = addr->in6.sin6_addr;
401
402 if (int_name->flags & INP6)
403 {
404 int i;
405
Simon Kelleyb7cf7542021-03-04 16:54:14 +0000406 for (i = 0; i < 16; i++)
407 {
408 int bits = ((i+1)*8) - prefixlen;
409
410 if (bits >= 8)
411 newaddr.s6_addr[i] = int_name->proto6.s6_addr[i];
412 else if (bits >= 0)
413 {
414 unsigned char mask = 0xff << bits;
415 newaddr.s6_addr[i] =
416 (addr->in6.sin6_addr.s6_addr[i] & mask) |
417 (int_name->proto6.s6_addr[i] & ~mask);
418 }
419 }
420 }
421
422 /* check for duplicates. */
423 for (lp = int_name->addr; lp; lp = lp->next)
424 if ((lp->flags & ADDRLIST_IPV6) &&
425 IN6_ARE_ADDR_EQUAL(&lp->addr.addr6, &newaddr))
426 break;
427
428 if (!lp)
429 {
430 if (param->spare)
431 {
432 al = param->spare;
433 param->spare = al->next;
434 }
435 else
436 al = whine_malloc(sizeof(struct addrlist));
437
438 if (al)
439 {
440 al->flags = ADDRLIST_IPV6;
441 al->addr.addr6 = newaddr;
442
443 /* Privacy addresses and addresses still undergoing DAD and deprecated addresses
444 don't appear in forward queries, but will in reverse ones. */
445 if (!(iface_flags & IFACE_PERMANENT) || (iface_flags & (IFACE_DEPRECATED | IFACE_TENTATIVE)))
446 al->flags |= ADDRLIST_REVONLY;
447 }
448 }
449 }
Simon Kelley115ac3e2013-05-20 11:28:32 +0100450
451 if (al)
452 {
Simon Kelley376d48c2013-11-13 13:04:30 +0000453 al->next = int_name->addr;
454 int_name->addr = al;
Simon Kelley115ac3e2013-05-20 11:28:32 +0100455 }
456 }
457 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700458
459 /* Update addresses for domain=<domain>,<interface> */
460 for (cond = daemon->cond_domain; cond; cond = cond->next)
461 if (cond->interface && strncmp(label, cond->interface, IF_NAMESIZE) == 0)
462 {
463 struct addrlist *al;
464
465 if (param->spare)
466 {
467 al = param->spare;
468 param->spare = al->next;
469 }
470 else
471 al = whine_malloc(sizeof(struct addrlist));
472
473 if (addr->sa.sa_family == AF_INET)
474 {
475 al->addr.addr4 = addr->in.sin_addr;
476 al->flags = 0;
477 }
478 else
479 {
480 al->addr.addr6 = addr->in6.sin6_addr;
481 al->flags = ADDRLIST_IPV6;
482 }
483
484 al->prefixlen = prefixlen;
485 al->next = cond->al;
486 cond->al = al;
487 }
488
Simon Kelley115ac3e2013-05-20 11:28:32 +0100489 /* check whether the interface IP has been added already
490 we call this routine multiple times. */
491 for (iface = daemon->interfaces; iface; iface = iface->next)
Petr Mensik951a2212019-07-03 17:02:16 +0200492 if (sockaddr_isequal(&iface->addr, addr) && iface->index == if_index)
Simon Kelley115ac3e2013-05-20 11:28:32 +0100493 {
Simon Kelley47669362014-12-17 12:41:56 +0000494 iface->dad = !!(iface_flags & IFACE_TENTATIVE);
Simon Kelley08619212013-12-02 14:43:48 +0000495 iface->found = 1; /* for garbage collection */
Petr Mensik951a2212019-07-03 17:02:16 +0200496 iface->netmask = netmask;
Simon Kelley115ac3e2013-05-20 11:28:32 +0100497 return 1;
498 }
499
500 /* If we are restricting the set of interfaces to use, make
Simon Kelley59353a62004-11-21 19:34:28 +0000501 sure that loopback interfaces are in that set. */
Simon Kelley1f15b812009-10-13 17:49:32 +0100502 if (daemon->if_names && loopback)
Simon Kelley59353a62004-11-21 19:34:28 +0000503 {
504 struct iname *lo;
505 for (lo = daemon->if_names; lo; lo = lo->next)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100506 if (lo->name && strcmp(lo->name, ifr.ifr_name) == 0)
Simon Kelley4ce4f372012-06-14 11:50:45 +0100507 break;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100508
Simon Kelley38365ff2013-02-05 14:35:54 +0000509 if (!lo && (lo = whine_malloc(sizeof(struct iname))))
Simon Kelley59353a62004-11-21 19:34:28 +0000510 {
Simon Kelley38365ff2013-02-05 14:35:54 +0000511 if ((lo->name = whine_malloc(strlen(ifr.ifr_name)+1)))
512 {
513 strcpy(lo->name, ifr.ifr_name);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700514 lo->flags |= INAME_USED;
Simon Kelley38365ff2013-02-05 14:35:54 +0000515 lo->next = daemon->if_names;
516 daemon->if_names = lo;
517 }
518 else
519 free(lo);
Simon Kelley59353a62004-11-21 19:34:28 +0000520 }
521 }
522
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100523 if (addr->sa.sa_family == AF_INET &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000524 !iface_check(AF_INET, (union all_addr *)&addr->in.sin_addr, label, &auth_dns))
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100525 return 1;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000526
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100527 if (addr->sa.sa_family == AF_INET6 &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000528 !iface_check(AF_INET6, (union all_addr *)&addr->in6.sin6_addr, label, &auth_dns))
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100529 return 1;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000530
531#ifdef HAVE_DHCP
532 /* No DHCP where we're doing auth DNS. */
533 if (auth_dns)
534 {
535 tftp_ok = 0;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700536 dhcp4_ok = dhcp6_ok = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000537 }
538 else
539 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
Simon Kelley49333cb2013-03-15 20:30:51 +0000540 if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
Simon Kelley4f7b3042012-11-28 21:27:02 +0000541 {
542 tftp_ok = 0;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700543 if (tmp->flags & INAME_4)
544 dhcp4_ok = 0;
545 if (tmp->flags & INAME_6)
546 dhcp6_ok = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000547 }
548#endif
549
Simon Kelley2937f8a2013-07-29 19:49:07 +0100550
Simon Kelley91543f42013-09-23 12:41:20 +0100551#ifdef HAVE_TFTP
Simon Kelley2937f8a2013-07-29 19:49:07 +0100552 if (daemon->tftp_interfaces)
553 {
554 /* dedicated tftp interface list */
555 tftp_ok = 0;
556 for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
557 if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
558 tftp_ok = 1;
559 }
Simon Kelley91543f42013-09-23 12:41:20 +0100560#endif
Simon Kelley2937f8a2013-07-29 19:49:07 +0100561
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100562 /* add to list */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100563 if ((iface = whine_malloc(sizeof(struct irec))))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100564 {
Petr Menšíka8c14742021-03-02 21:38:02 +0000565 int mtu = 0;
566
567 if (ioctl(param->fd, SIOCGIFMTU, &ifr) != -1)
568 mtu = ifr.ifr_mtu;
569
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100570 iface->addr = *addr;
571 iface->netmask = netmask;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100572 iface->tftp_ok = tftp_ok;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700573 iface->dhcp4_ok = dhcp4_ok;
574 iface->dhcp6_ok = dhcp6_ok;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000575 iface->dns_auth = auth_dns;
Simon Kelley1f15b812009-10-13 17:49:32 +0100576 iface->mtu = mtu;
Simon Kelley47669362014-12-17 12:41:56 +0000577 iface->dad = !!(iface_flags & IFACE_TENTATIVE);
Simon Kelley08619212013-12-02 14:43:48 +0000578 iface->found = 1;
Simon Kelleydc27e142013-10-16 13:09:53 +0100579 iface->done = iface->multicast_done = iface->warned = 0;
Simon Kelley5d162f22012-12-20 14:55:46 +0000580 iface->index = if_index;
Petr Menšíkad59f272017-03-17 17:22:19 +0000581 iface->label = is_label;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100582 if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
Simon Kelley6f13e532012-04-17 14:25:06 +0100583 {
584 strcpy(iface->name, ifr.ifr_name);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100585 iface->next = daemon->interfaces;
586 daemon->interfaces = iface;
Simon Kelley6f13e532012-04-17 14:25:06 +0100587 return 1;
588 }
589 free(iface);
Simon Kelley5d162f22012-12-20 14:55:46 +0000590
Simon Kelley44a2a312004-03-10 20:04:35 +0000591 }
592
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100593 errno = ENOMEM;
594 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000595}
596
Simon Kelleyc72daea2012-01-05 21:33:27 +0000597static int iface_allowed_v6(struct in6_addr *local, int prefix,
Simon Kelleybad7b872012-12-20 22:00:39 +0000598 int scope, int if_index, int flags,
Simon Kelley1f776932012-12-16 19:46:08 +0000599 int preferred, int valid, void *vparam)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000600{
Simon Kelley59353a62004-11-21 19:34:28 +0000601 union mysockaddr addr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100602 struct in_addr netmask; /* dummy */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100603 netmask.s_addr = 0;
Simon Kelley52b92f42012-01-22 16:05:15 +0000604
Simon Kelley52b92f42012-01-22 16:05:15 +0000605 (void)scope; /* warning */
Simon Kelley1f776932012-12-16 19:46:08 +0000606 (void)preferred;
607 (void)valid;
Simon Kelley44a2a312004-03-10 20:04:35 +0000608
Simon Kelley849a8352006-06-09 21:02:31 +0100609 memset(&addr, 0, sizeof(addr));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000610#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100611 addr.in6.sin6_len = sizeof(addr.in6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000612#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100613 addr.in6.sin6_family = AF_INET6;
614 addr.in6.sin6_addr = *local;
615 addr.in6.sin6_port = htons(daemon->port);
Simon Kelley62ab3cc2013-12-03 11:53:53 +0000616 /* FreeBSD insists this is zero for non-linklocal addresses */
617 if (IN6_IS_ADDR_LINKLOCAL(local))
618 addr.in6.sin6_scope_id = if_index;
619 else
620 addr.in6.sin6_scope_id = 0;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000621
Simon Kelley47669362014-12-17 12:41:56 +0000622 return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, flags);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100623}
Simon Kelley59353a62004-11-21 19:34:28 +0000624
Simon Kelley3f2873d2013-05-14 11:28:47 +0100625static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100626 struct in_addr netmask, struct in_addr broadcast, void *vparam)
627{
628 union mysockaddr addr;
Simon Kelley376d48c2013-11-13 13:04:30 +0000629 int prefix, bit;
Simon Kelleyb8ac4662016-03-10 18:40:53 +0000630
631 (void)broadcast; /* warning */
Simon Kelley849a8352006-06-09 21:02:31 +0100632
633 memset(&addr, 0, sizeof(addr));
Simon Kelley1ab84e22004-01-29 16:48:35 +0000634#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100635 addr.in.sin_len = sizeof(addr.in);
Simon Kelley1ab84e22004-01-29 16:48:35 +0000636#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100637 addr.in.sin_family = AF_INET;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100638 addr.in.sin_addr = local;
639 addr.in.sin_port = htons(daemon->port);
Simon Kelley44a2a312004-03-10 20:04:35 +0000640
Simon Kelley376d48c2013-11-13 13:04:30 +0000641 /* determine prefix length from netmask */
642 for (prefix = 32, bit = 1; (bit & ntohl(netmask.s_addr)) == 0 && prefix != 0; bit = bit << 1, prefix--);
643
644 return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, prefix, 0);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100645}
Petr Mensik60a3ae12019-07-09 14:05:59 +0200646
647/*
648 * Clean old interfaces no longer found.
649 */
650static void clean_interfaces()
651{
652 struct irec *iface;
653 struct irec **up = &daemon->interfaces;
654
655 for (iface = *up; iface; iface = *up)
656 {
657 if (!iface->found && !iface->done)
658 {
659 *up = iface->next;
660 free(iface->name);
661 free(iface);
662 }
663 else
664 {
665 up = &iface->next;
666 }
667 }
668}
669
Petr Menšík49bdf1e2019-07-15 17:13:12 +0200670/** Release listener if no other interface needs it.
671 *
672 * @return 1 if released, 0 if still required
673 */
674static int release_listener(struct listener *l)
675{
676 if (l->used > 1)
677 {
678 struct irec *iface;
679 for (iface = daemon->interfaces; iface; iface = iface->next)
680 if (iface->done && sockaddr_isequal(&l->addr, &iface->addr))
681 {
682 if (iface->found)
683 {
684 /* update listener to point to active interface instead */
685 if (!l->iface->found)
686 l->iface = iface;
687 }
688 else
689 {
690 l->used--;
691 iface->done = 0;
692 }
693 }
694
695 /* Someone is still using this listener, skip its deletion */
696 if (l->used > 0)
697 return 0;
698 }
699
700 if (l->iface->done)
701 {
702 int port;
703
704 port = prettyprint_addr(&l->iface->addr, daemon->addrbuff);
Simon Kelley4c30e962021-03-12 22:09:14 +0000705 my_syslog(LOG_DEBUG|MS_DEBUG, _("stopped listening on %s(#%d): %s port %d"),
Petr Menšík49bdf1e2019-07-15 17:13:12 +0200706 l->iface->name, l->iface->index, daemon->addrbuff, port);
707 /* In case it ever returns */
708 l->iface->done = 0;
709 }
710
711 if (l->fd != -1)
712 close(l->fd);
713 if (l->tcpfd != -1)
714 close(l->tcpfd);
715 if (l->tftpfd != -1)
716 close(l->tftpfd);
717
718 free(l);
719 return 1;
720}
721
Simon Kelley115ac3e2013-05-20 11:28:32 +0100722int enumerate_interfaces(int reset)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100723{
Simon Kelley115ac3e2013-05-20 11:28:32 +0100724 static struct addrlist *spare = NULL;
Simon Kelleya0358e52014-06-07 13:38:48 +0100725 static int done = 0;
Simon Kelley115ac3e2013-05-20 11:28:32 +0100726 struct iface_param param;
727 int errsave, ret = 1;
728 struct addrlist *addr, *tmp;
729 struct interface_name *intname;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700730 struct cond_domain *cond;
Simon Kelley08619212013-12-02 14:43:48 +0000731 struct irec *iface;
Simon Kelley376d48c2013-11-13 13:04:30 +0000732#ifdef HAVE_AUTH
733 struct auth_zone *zone;
734#endif
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000735 struct server *serv;
736
Simon Kelley76dd75d2013-05-23 10:04:25 +0100737 /* Do this max once per select cycle - also inhibits netlink socket use
738 in TCP child processes. */
Simon Kelley397542b2013-09-05 11:27:34 +0100739
Simon Kelley115ac3e2013-05-20 11:28:32 +0100740 if (reset)
741 {
742 done = 0;
743 return 1;
744 }
745
Simon Kelleya0358e52014-06-07 13:38:48 +0100746 if (done)
Simon Kelley115ac3e2013-05-20 11:28:32 +0100747 return 1;
748
749 done = 1;
750
751 if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
752 return 0;
Petr Menšík4c0aecc2021-03-02 18:21:32 +0000753
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000754 /* iface indexes can change when interfaces are created/destroyed.
755 We use them in the main forwarding control path, when the path
756 to a server is specified by an interface, so cache them.
757 Update the cache here. */
758 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley1de6bbc2021-03-19 22:24:08 +0000759 if (serv->interface[0] != 0)
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000760 {
Simon Kelley1de6bbc2021-03-19 22:24:08 +0000761#ifdef HAVE_LINUX_NETWORK
762 struct ifreq ifr;
763
764 safe_strncpy(ifr.ifr_name, serv->interface, IF_NAMESIZE);
765 if (ioctl(param.fd, SIOCGIFINDEX, &ifr) != -1)
766 serv->ifindex = ifr.ifr_ifindex;
767#else
768 serv->ifindex = if_nametoindex(serv->interface);
769#endif
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000770 }
771
Petr Menšík4c0aecc2021-03-02 18:21:32 +0000772again:
Simon Kelley08619212013-12-02 14:43:48 +0000773 /* Mark interfaces for garbage collection */
774 for (iface = daemon->interfaces; iface; iface = iface->next)
775 iface->found = 0;
776
Simon Kelley115ac3e2013-05-20 11:28:32 +0100777 /* remove addresses stored against interface_names */
778 for (intname = daemon->int_names; intname; intname = intname->next)
779 {
Simon Kelley376d48c2013-11-13 13:04:30 +0000780 for (addr = intname->addr; addr; addr = tmp)
Simon Kelley115ac3e2013-05-20 11:28:32 +0100781 {
782 tmp = addr->next;
783 addr->next = spare;
784 spare = addr;
785 }
786
Simon Kelley376d48c2013-11-13 13:04:30 +0000787 intname->addr = NULL;
Simon Kelley115ac3e2013-05-20 11:28:32 +0100788 }
Simon Kelley376d48c2013-11-13 13:04:30 +0000789
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700790 /* remove addresses stored against cond-domains. */
791 for (cond = daemon->cond_domain; cond; cond = cond->next)
792 {
793 for (addr = cond->al; addr; addr = tmp)
794 {
795 tmp = addr->next;
796 addr->next = spare;
797 spare = addr;
798 }
799
800 cond->al = NULL;
801 }
802
Simon Kelleyc8a80482014-03-05 14:29:54 +0000803 /* Remove list of addresses of local interfaces */
804 for (addr = daemon->interface_addrs; addr; addr = tmp)
805 {
806 tmp = addr->next;
807 addr->next = spare;
808 spare = addr;
809 }
810 daemon->interface_addrs = NULL;
811
Simon Kelley376d48c2013-11-13 13:04:30 +0000812#ifdef HAVE_AUTH
813 /* remove addresses stored against auth_zone subnets, but not
814 ones configured as address literals */
815 for (zone = daemon->auth_zones; zone; zone = zone->next)
816 if (zone->interface_names)
817 {
818 struct addrlist **up;
819 for (up = &zone->subnet, addr = zone->subnet; addr; addr = tmp)
820 {
821 tmp = addr->next;
822 if (addr->flags & ADDRLIST_LITERAL)
823 up = &addr->next;
824 else
825 {
826 *up = addr->next;
827 addr->next = spare;
828 spare = addr;
829 }
830 }
831 }
832#endif
833
Simon Kelley115ac3e2013-05-20 11:28:32 +0100834 param.spare = spare;
835
Simon Kelley115ac3e2013-05-20 11:28:32 +0100836 ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
Petr Menšík4c0aecc2021-03-02 18:21:32 +0000837 if (ret < 0)
838 goto again;
839 else if (ret)
840 {
841 ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
842 if (ret < 0)
843 goto again;
844 }
Simon Kelley115ac3e2013-05-20 11:28:32 +0100845
846 errsave = errno;
847 close(param.fd);
Simon Kelley08619212013-12-02 14:43:48 +0000848
849 if (option_bool(OPT_CLEVERBIND))
850 {
851 /* Garbage-collect listeners listening on addresses that no longer exist.
852 Does nothing when not binding interfaces or for listeners on localhost,
853 since the ->iface field is NULL. Note that this needs the protections
Josh Soref730c6742017-02-06 16:14:04 +0000854 against reentrancy, hence it's here. It also means there's a possibility,
Simon Kelley08619212013-12-02 14:43:48 +0000855 in OPT_CLEVERBIND mode, that at listener will just disappear after
856 a call to enumerate_interfaces, this is checked OK on all calls. */
857 struct listener *l, *tmp, **up;
Petr Mensik60a3ae12019-07-09 14:05:59 +0200858 int freed = 0;
Simon Kelley08619212013-12-02 14:43:48 +0000859
860 for (up = &daemon->listeners, l = daemon->listeners; l; l = tmp)
861 {
862 tmp = l->next;
863
864 if (!l->iface || l->iface->found)
865 up = &l->next;
Petr Menšík49bdf1e2019-07-15 17:13:12 +0200866 else if (release_listener(l))
Simon Kelley08619212013-12-02 14:43:48 +0000867 {
Petr Menšík49bdf1e2019-07-15 17:13:12 +0200868 *up = tmp;
Simon Kelley619000a2020-04-29 00:09:58 +0100869 freed = 1;
Simon Kelley08619212013-12-02 14:43:48 +0000870 }
871 }
Petr Mensik60a3ae12019-07-09 14:05:59 +0200872
873 if (freed)
874 clean_interfaces();
Simon Kelley08619212013-12-02 14:43:48 +0000875 }
Petr Mensik60a3ae12019-07-09 14:05:59 +0200876
Simon Kelley115ac3e2013-05-20 11:28:32 +0100877 errno = errsave;
Simon Kelley115ac3e2013-05-20 11:28:32 +0100878 spare = param.spare;
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000879
Simon Kelley115ac3e2013-05-20 11:28:32 +0100880 return ret;
Simon Kelley44a2a312004-03-10 20:04:35 +0000881}
882
Simon Kelley5aabfc72007-08-29 11:24:47 +0100883/* set NONBLOCK bit on fd: See Stevens 16.6 */
Simon Kelley7cebd202006-05-06 14:13:33 +0100884int fix_fd(int fd)
885{
886 int flags;
887
888 if ((flags = fcntl(fd, F_GETFL)) == -1 ||
Simon Kelley5aabfc72007-08-29 11:24:47 +0100889 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
Simon Kelley7cebd202006-05-06 14:13:33 +0100890 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100891
Simon Kelley7cebd202006-05-06 14:13:33 +0100892 return 1;
893}
894
Simon Kelley74c95c22011-10-19 09:33:39 +0100895static int make_sock(union mysockaddr *addr, int type, int dienow)
Simon Kelley44a2a312004-03-10 20:04:35 +0000896{
Simon Kelley28866e92011-02-14 20:19:14 +0000897 int family = addr->sa.sa_family;
898 int fd, rc, opt = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100899
Simon Kelley28866e92011-02-14 20:19:14 +0000900 if ((fd = socket(family, type, 0)) == -1)
Simon Kelley316e2732010-01-22 20:16:09 +0000901 {
Josh Soref730c6742017-02-06 16:14:04 +0000902 int port, errsave;
Simon Kelley39f1b8e2012-06-20 20:04:27 +0100903 char *s;
Simon Kelley28866e92011-02-14 20:19:14 +0000904
905 /* No error if the kernel just doesn't support this IP flavour */
906 if (errno == EPROTONOSUPPORT ||
907 errno == EAFNOSUPPORT ||
908 errno == EINVAL)
909 return -1;
910
911 err:
Josh Soref730c6742017-02-06 16:14:04 +0000912 errsave = errno;
Simon Kelley39f1b8e2012-06-20 20:04:27 +0100913 port = prettyprint_addr(addr, daemon->addrbuff);
914 if (!option_bool(OPT_NOWILD) && !option_bool(OPT_CLEVERBIND))
915 sprintf(daemon->addrbuff, "port %d", port);
916 s = _("failed to create listening socket for %s: %s");
917
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100918 if (fd != -1)
Matthias Andree71aaa5a2013-12-03 11:20:45 +0000919 close (fd);
920
Josh Soref730c6742017-02-06 16:14:04 +0000921 errno = errsave;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000922
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700923 /* Failure to bind addresses given by --listen-address at this point
924 because there's no interface with the address is OK if we're doing bind-dynamic.
925 If/when an interface is created with the relevant address we'll notice
926 and attempt to bind it then. This is in the generic error path so we close the socket,
927 but EADDRNOTAVAIL is only a possible error from bind()
928
929 When a new address is created and we call this code again (dienow == 0) there
930 may still be configured addresses when don't exist, (consider >1 --listen-address,
931 when the first is created, the second will still be missing) so we suppress
932 EADDRNOTAVAIL even in that case to avoid confusing log entries.
933 */
934 if (!option_bool(OPT_CLEVERBIND) || errno != EADDRNOTAVAIL)
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100935 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700936 if (dienow)
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100937 die(s, daemon->addrbuff, EC_BADNET);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700938 else
939 my_syslog(LOG_WARNING, s, daemon->addrbuff, strerror(errno));
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100940 }
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100941
Simon Kelley74c95c22011-10-19 09:33:39 +0100942 return -1;
Simon Kelley28866e92011-02-14 20:19:14 +0000943 }
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100944
Simon Kelley28866e92011-02-14 20:19:14 +0000945 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
946 goto err;
947
Simon Kelleyc72daea2012-01-05 21:33:27 +0000948 if (family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000949 goto err;
Simon Kelley28866e92011-02-14 20:19:14 +0000950
Simon Kelley74c95c22011-10-19 09:33:39 +0100951 if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000952 goto err;
953
954 if (type == SOCK_STREAM)
955 {
Simon Kelley608aa9f2019-03-10 22:44:15 +0000956#ifdef TCP_FASTOPEN
957 int qlen = 5;
Matthias Andreee39c4842020-03-05 15:58:31 +0000958 setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen));
Simon Kelley608aa9f2019-03-10 22:44:15 +0000959#endif
960
Simon Kelley09b768e2016-12-22 22:16:58 +0000961 if (listen(fd, TCP_BACKLOG) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000962 goto err;
963 }
Simon Kelley2329bef2013-12-03 13:41:16 +0000964 else if (family == AF_INET)
Simon Kelley28866e92011-02-14 20:19:14 +0000965 {
Simon Kelley2329bef2013-12-03 13:41:16 +0000966 if (!option_bool(OPT_NOWILD))
Simon Kelley28866e92011-02-14 20:19:14 +0000967 {
968#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000969 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000970 goto err;
971#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
972 if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
973 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1)
974 goto err;
975#endif
976 }
Simon Kelley28866e92011-02-14 20:19:14 +0000977 }
Simon Kelley2329bef2013-12-03 13:41:16 +0000978 else if (!set_ipv6pktinfo(fd))
979 goto err;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000980
Simon Kelley28866e92011-02-14 20:19:14 +0000981 return fd;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100982}
Simon Kelleyc72daea2012-01-05 21:33:27 +0000983
Simon Kelleyc72daea2012-01-05 21:33:27 +0000984int set_ipv6pktinfo(int fd)
985{
986 int opt = 1;
987
988 /* The API changed around Linux 2.6.14 but the old ABI is still supported:
989 handle all combinations of headers and kernel.
990 OpenWrt note that this fixes the problem addressed by your very broken patch. */
991 daemon->v6pktinfo = IPV6_PKTINFO;
992
993#ifdef IPV6_RECVPKTINFO
994 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)) != -1)
995 return 1;
996# ifdef IPV6_2292PKTINFO
997 else if (errno == ENOPROTOOPT && setsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
998 {
999 daemon->v6pktinfo = IPV6_2292PKTINFO;
1000 return 1;
1001 }
1002# endif
1003#else
1004 if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &opt, sizeof(opt)) != -1)
1005 return 1;
1006#endif
1007
1008 return 0;
1009}
Simon Kelley22ce5502013-01-22 13:53:04 +00001010
1011
1012/* Find the interface on which a TCP connection arrived, if possible, or zero otherwise. */
1013int tcp_interface(int fd, int af)
1014{
Kevin Darbyshire-Bryant70c50ef2020-03-06 10:31:15 +00001015 (void)fd; /* suppress potential unused warning */
1016 (void)af; /* suppress potential unused warning */
Simon Kelley22ce5502013-01-22 13:53:04 +00001017 int if_index = 0;
1018
1019#ifdef HAVE_LINUX_NETWORK
1020 int opt = 1;
1021 struct cmsghdr *cmptr;
1022 struct msghdr msg;
Simon Kelley529b0302016-03-16 19:00:45 +00001023 socklen_t len;
Simon Kelley22ce5502013-01-22 13:53:04 +00001024
Simon Kelley529b0302016-03-16 19:00:45 +00001025 /* use mshdr so that the CMSDG_* macros are available */
Simon Kelley22ce5502013-01-22 13:53:04 +00001026 msg.msg_control = daemon->packet;
Simon Kelley529b0302016-03-16 19:00:45 +00001027 msg.msg_controllen = len = daemon->packet_buff_sz;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001028
Simon Kelley22ce5502013-01-22 13:53:04 +00001029 /* we overwrote the buffer... */
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001030 daemon->srv_save = NULL;
1031
Simon Kelley22ce5502013-01-22 13:53:04 +00001032 if (af == AF_INET)
1033 {
1034 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&
Simon Kelley529b0302016-03-16 19:00:45 +00001035 getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, &len) != -1)
1036 {
1037 msg.msg_controllen = len;
1038 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
1039 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
1040 {
1041 union {
1042 unsigned char *c;
1043 struct in_pktinfo *p;
1044 } p;
1045
1046 p.c = CMSG_DATA(cmptr);
1047 if_index = p.p->ipi_ifindex;
1048 }
1049 }
Simon Kelley22ce5502013-01-22 13:53:04 +00001050 }
Simon Kelley22ce5502013-01-22 13:53:04 +00001051 else
1052 {
1053 /* Only the RFC-2292 API has the ability to find the interface for TCP connections,
1054 it was removed in RFC-3542 !!!!
1055
1056 Fortunately, Linux kept the 2292 ABI when it moved to 3542. The following code always
1057 uses the old ABI, and should work with pre- and post-3542 kernel headers */
1058
1059#ifdef IPV6_2292PKTOPTIONS
1060# define PKTOPTIONS IPV6_2292PKTOPTIONS
1061#else
1062# define PKTOPTIONS IPV6_PKTOPTIONS
1063#endif
1064
1065 if (set_ipv6pktinfo(fd) &&
Simon Kelley529b0302016-03-16 19:00:45 +00001066 getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, &len) != -1)
Simon Kelley22ce5502013-01-22 13:53:04 +00001067 {
Simon Kelley529b0302016-03-16 19:00:45 +00001068 msg.msg_controllen = len;
1069 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley22ce5502013-01-22 13:53:04 +00001070 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
1071 {
1072 union {
1073 unsigned char *c;
1074 struct in6_pktinfo *p;
1075 } p;
1076 p.c = CMSG_DATA(cmptr);
1077
1078 if_index = p.p->ipi6_ifindex;
1079 }
1080 }
1081 }
Simon Kelley22ce5502013-01-22 13:53:04 +00001082#endif /* Linux */
1083
1084 return if_index;
1085}
Simon Kelley28866e92011-02-14 20:19:14 +00001086
Simon Kelley74c95c22011-10-19 09:33:39 +01001087static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
Simon Kelley28866e92011-02-14 20:19:14 +00001088{
1089 struct listener *l = NULL;
1090 int fd = -1, tcpfd = -1, tftpfd = -1;
1091
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001092 (void)do_tftp;
1093
Simon Kelley28866e92011-02-14 20:19:14 +00001094 if (daemon->port != 0)
1095 {
Simon Kelley74c95c22011-10-19 09:33:39 +01001096 fd = make_sock(addr, SOCK_DGRAM, dienow);
1097 tcpfd = make_sock(addr, SOCK_STREAM, dienow);
Simon Kelley28866e92011-02-14 20:19:14 +00001098 }
1099
1100#ifdef HAVE_TFTP
1101 if (do_tftp)
1102 {
1103 if (addr->sa.sa_family == AF_INET)
1104 {
1105 /* port must be restored to DNS port for TCP code */
1106 short save = addr->in.sin_port;
1107 addr->in.sin_port = htons(TFTP_PORT);
Simon Kelley74c95c22011-10-19 09:33:39 +01001108 tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
Simon Kelley28866e92011-02-14 20:19:14 +00001109 addr->in.sin_port = save;
1110 }
Simon Kelley28866e92011-02-14 20:19:14 +00001111 else
1112 {
1113 short save = addr->in6.sin6_port;
1114 addr->in6.sin6_port = htons(TFTP_PORT);
Simon Kelley74c95c22011-10-19 09:33:39 +01001115 tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
Simon Kelley28866e92011-02-14 20:19:14 +00001116 addr->in6.sin6_port = save;
1117 }
Simon Kelley28866e92011-02-14 20:19:14 +00001118 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001119#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001120
Simon Kelley28866e92011-02-14 20:19:14 +00001121 if (fd != -1 || tcpfd != -1 || tftpfd != -1)
1122 {
1123 l = safe_malloc(sizeof(struct listener));
1124 l->next = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00001125 l->fd = fd;
1126 l->tcpfd = tcpfd;
Petr Menšík49bdf1e2019-07-15 17:13:12 +02001127 l->tftpfd = tftpfd;
1128 l->addr = *addr;
1129 l->used = 1;
Simon Kelley08619212013-12-02 14:43:48 +00001130 l->iface = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00001131 }
1132
1133 return l;
1134}
1135
Simon Kelley74c95c22011-10-19 09:33:39 +01001136void create_wildcard_listeners(void)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001137{
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001138 union mysockaddr addr;
Simon Kelley8bc4cec2012-07-03 21:04:11 +01001139 struct listener *l, *l6;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001140
Simon Kelley849a8352006-06-09 21:02:31 +01001141 memset(&addr, 0, sizeof(addr));
Simon Kelley28866e92011-02-14 20:19:14 +00001142#ifdef HAVE_SOCKADDR_SA_LEN
1143 addr.in.sin_len = sizeof(addr.in);
1144#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001145 addr.in.sin_family = AF_INET;
1146 addr.in.sin_addr.s_addr = INADDR_ANY;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001147 addr.in.sin_port = htons(daemon->port);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001148
Simon Kelley8bc4cec2012-07-03 21:04:11 +01001149 l = create_listeners(&addr, !!option_bool(OPT_TFTP), 1);
Simon Kelley28866e92011-02-14 20:19:14 +00001150
Simon Kelley28866e92011-02-14 20:19:14 +00001151 memset(&addr, 0, sizeof(addr));
Simon Kelleyee875042018-10-23 22:10:17 +01001152#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley28866e92011-02-14 20:19:14 +00001153 addr.in6.sin6_len = sizeof(addr.in6);
Simon Kelleyee875042018-10-23 22:10:17 +01001154#endif
Simon Kelley28866e92011-02-14 20:19:14 +00001155 addr.in6.sin6_family = AF_INET6;
1156 addr.in6.sin6_addr = in6addr_any;
1157 addr.in6.sin6_port = htons(daemon->port);
Simon Kelley8bc4cec2012-07-03 21:04:11 +01001158
1159 l6 = create_listeners(&addr, !!option_bool(OPT_TFTP), 1);
Simon Kelley28866e92011-02-14 20:19:14 +00001160 if (l)
Simon Kelley8bc4cec2012-07-03 21:04:11 +01001161 l->next = l6;
Simon Kelley28866e92011-02-14 20:19:14 +00001162 else
Simon Kelley8bc4cec2012-07-03 21:04:11 +01001163 l = l6;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001164
Simon Kelley74c95c22011-10-19 09:33:39 +01001165 daemon->listeners = l;
Simon Kelley44a2a312004-03-10 20:04:35 +00001166}
1167
Petr Menšík49bdf1e2019-07-15 17:13:12 +02001168static struct listener *find_listener(union mysockaddr *addr)
1169{
1170 struct listener *l;
1171 for (l = daemon->listeners; l; l = l->next)
1172 if (sockaddr_isequal(&l->addr, addr))
1173 return l;
1174 return NULL;
1175}
1176
Simon Kelley74c95c22011-10-19 09:33:39 +01001177void create_bound_listeners(int dienow)
Simon Kelley44a2a312004-03-10 20:04:35 +00001178{
Simon Kelley74c95c22011-10-19 09:33:39 +01001179 struct listener *new;
Simon Kelley44a2a312004-03-10 20:04:35 +00001180 struct irec *iface;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001181 struct iname *if_tmp;
Petr Menšík49bdf1e2019-07-15 17:13:12 +02001182 struct listener *existing;
Simon Kelley73a08a22009-02-05 20:28:08 +00001183
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001184 for (iface = daemon->interfaces; iface; iface = iface->next)
Petr Menšík49bdf1e2019-07-15 17:13:12 +02001185 if (!iface->done && !iface->dad && iface->found)
Simon Kelley28866e92011-02-14 20:19:14 +00001186 {
Petr Menšík49bdf1e2019-07-15 17:13:12 +02001187 existing = find_listener(&iface->addr);
1188 if (existing)
1189 {
1190 iface->done = 1;
1191 existing->used++; /* increase usage counter */
1192 }
1193 else if ((new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
1194 {
Petr Menšík49bdf1e2019-07-15 17:13:12 +02001195 new->iface = iface;
1196 new->next = daemon->listeners;
1197 daemon->listeners = new;
1198 iface->done = 1;
Simon Kelley619000a2020-04-29 00:09:58 +01001199
1200 /* Don't log the initial set of listen addresses created
1201 at startup, since this is happening before the logging
1202 system is initialised and the sign-on printed. */
1203 if (!dienow)
1204 {
1205 int port = prettyprint_addr(&iface->addr, daemon->addrbuff);
Simon Kelley4c30e962021-03-12 22:09:14 +00001206 my_syslog(LOG_DEBUG|MS_DEBUG, _("listening on %s(#%d): %s port %d"),
Simon Kelley619000a2020-04-29 00:09:58 +01001207 iface->name, iface->index, daemon->addrbuff, port);
1208 }
Petr Menšík49bdf1e2019-07-15 17:13:12 +02001209 }
Simon Kelley28866e92011-02-14 20:19:14 +00001210 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001211
1212 /* Check for --listen-address options that haven't been used because there's
1213 no interface with a matching address. These may be valid: eg it's possible
1214 to listen on 127.0.1.1 even if the loopback interface is 127.0.0.1
1215
Simon Kelley5f11b3e2012-08-16 14:04:05 +01001216 If the address isn't valid the bind() will fail and we'll die()
1217 (except in bind-dynamic mode, when we'll complain but keep trying.)
Simon Kelley52d4abf2012-03-21 21:39:48 +00001218
1219 The resulting listeners have the ->iface field NULL, and this has to be
1220 handled by the DNS and TFTP code. It disables --localise-queries processing
1221 (no netmask) and some MTU login the tftp code. */
1222
1223 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001224 if (!(if_tmp->flags & INAME_USED) &&
Simon Kelley8bc4cec2012-07-03 21:04:11 +01001225 (new = create_listeners(&if_tmp->addr, !!option_bool(OPT_TFTP), dienow)))
Simon Kelley52d4abf2012-03-21 21:39:48 +00001226 {
Simon Kelley52d4abf2012-03-21 21:39:48 +00001227 new->next = daemon->listeners;
1228 daemon->listeners = new;
Simon Kelley619000a2020-04-29 00:09:58 +01001229
1230 if (!dienow)
1231 {
1232 int port = prettyprint_addr(&if_tmp->addr, daemon->addrbuff);
Simon Kelley4c30e962021-03-12 22:09:14 +00001233 my_syslog(LOG_DEBUG|MS_DEBUG, _("listening on %s port %d"), daemon->addrbuff, port);
Simon Kelley619000a2020-04-29 00:09:58 +01001234 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001235 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001236}
1237
Simon Kelleydc27e142013-10-16 13:09:53 +01001238/* In --bind-interfaces, the only access control is the addresses we're listening on.
1239 There's nothing to avoid a query to the address of an internal interface arriving via
1240 an external interface where we don't want to accept queries, except that in the usual
1241 case the addresses of internal interfaces are RFC1918. When bind-interfaces in use,
1242 and we listen on an address that looks like it's probably globally routeable, shout.
1243
1244 The fix is to use --bind-dynamic, which actually checks the arrival interface too.
1245 Tough if your platform doesn't support this.
Simon Kelley2329bef2013-12-03 13:41:16 +00001246
1247 Note that checking the arrival interface is supported in the standard IPv6 API and
1248 always done, so we don't warn about any IPv6 addresses here.
Simon Kelleydc27e142013-10-16 13:09:53 +01001249*/
1250
1251void warn_bound_listeners(void)
1252{
1253 struct irec *iface;
1254 int advice = 0;
1255
1256 for (iface = daemon->interfaces; iface; iface = iface->next)
Simon Kelleyf7029f52013-11-21 15:09:09 +00001257 if (!iface->dns_auth)
Simon Kelleydc27e142013-10-16 13:09:53 +01001258 {
Simon Kelleydc27e142013-10-16 13:09:53 +01001259 if (iface->addr.sa.sa_family == AF_INET)
1260 {
1261 if (!private_net(iface->addr.in.sin_addr, 1))
1262 {
1263 inet_ntop(AF_INET, &iface->addr.in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley2329bef2013-12-03 13:41:16 +00001264 iface->warned = advice = 1;
1265 my_syslog(LOG_WARNING,
1266 _("LOUD WARNING: listening on %s may accept requests via interfaces other than %s"),
1267 daemon->addrbuff, iface->name);
Simon Kelleydc27e142013-10-16 13:09:53 +01001268 }
1269 }
Simon Kelleydc27e142013-10-16 13:09:53 +01001270 }
1271
1272 if (advice)
Simon Kelleyf7029f52013-11-21 15:09:09 +00001273 my_syslog(LOG_WARNING, _("LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"));
Simon Kelleydc27e142013-10-16 13:09:53 +01001274}
1275
Petr Menšíkad59f272017-03-17 17:22:19 +00001276void warn_wild_labels(void)
1277{
1278 struct irec *iface;
1279
1280 for (iface = daemon->interfaces; iface; iface = iface->next)
1281 if (iface->found && iface->name && iface->label)
1282 my_syslog(LOG_WARNING, _("warning: using interface %s instead"), iface->name);
1283}
1284
Simon Kelleyf7029f52013-11-21 15:09:09 +00001285void warn_int_names(void)
1286{
1287 struct interface_name *intname;
1288
1289 for (intname = daemon->int_names; intname; intname = intname->next)
1290 if (!intname->addr)
1291 my_syslog(LOG_WARNING, _("warning: no addresses found for interface %s"), intname->intr);
1292}
1293
Simon Kelley74c95c22011-10-19 09:33:39 +01001294int is_dad_listeners(void)
1295{
1296 struct irec *iface;
1297
1298 if (option_bool(OPT_NOWILD))
1299 for (iface = daemon->interfaces; iface; iface = iface->next)
1300 if (iface->dad && !iface->done)
1301 return 1;
1302
1303 return 0;
1304}
Simon Kelley5d162f22012-12-20 14:55:46 +00001305
1306#ifdef HAVE_DHCP6
1307void join_multicast(int dienow)
1308{
1309 struct irec *iface, *tmp;
1310
1311 for (iface = daemon->interfaces; iface; iface = iface->next)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001312 if (iface->addr.sa.sa_family == AF_INET6 && iface->dhcp6_ok && !iface->multicast_done)
Simon Kelley5d162f22012-12-20 14:55:46 +00001313 {
1314 /* There's an irec per address but we only want to join for multicast
1315 once per interface. Weed out duplicates. */
1316 for (tmp = daemon->interfaces; tmp; tmp = tmp->next)
1317 if (tmp->multicast_done && tmp->index == iface->index)
1318 break;
1319
1320 iface->multicast_done = 1;
1321
1322 if (!tmp)
1323 {
1324 struct ipv6_mreq mreq;
1325 int err = 0;
1326
1327 mreq.ipv6mr_interface = iface->index;
1328
1329 inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
1330
Simon Kelleyff7eea22013-09-04 18:01:38 +01001331 if ((daemon->doing_dhcp6 || daemon->relay6) &&
Simon Kelley5d162f22012-12-20 14:55:46 +00001332 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
Simon Kelley9cdcfe92015-08-26 22:38:08 +01001333 err = errno;
Simon Kelley5d162f22012-12-20 14:55:46 +00001334
1335 inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
1336
1337 if (daemon->doing_dhcp6 &&
1338 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
Simon Kelley9cdcfe92015-08-26 22:38:08 +01001339 err = errno;
Simon Kelley5d162f22012-12-20 14:55:46 +00001340
1341 inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
1342
1343 if (daemon->doing_ra &&
1344 setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
Simon Kelley9cdcfe92015-08-26 22:38:08 +01001345 err = errno;
Simon Kelley5d162f22012-12-20 14:55:46 +00001346
1347 if (err)
1348 {
1349 char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
Simon Kelley9cdcfe92015-08-26 22:38:08 +01001350 errno = err;
1351
1352#ifdef HAVE_LINUX_NETWORK
1353 if (errno == ENOMEM)
1354 my_syslog(LOG_ERR, _("try increasing /proc/sys/net/core/optmem_max"));
1355#endif
1356
Simon Kelley5d162f22012-12-20 14:55:46 +00001357 if (dienow)
1358 die(s, iface->name, EC_BADNET);
1359 else
1360 my_syslog(LOG_ERR, s, iface->name, strerror(errno));
1361 }
1362 }
1363 }
1364}
1365#endif
1366
Simon Kelley9d6918d2017-10-13 17:55:09 +01001367int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)
Simon Kelley824af852008-02-12 20:43:05 +00001368{
1369 union mysockaddr addr_copy = *addr;
Simon Kelleya2a7e042020-12-12 23:26:45 +00001370 unsigned short port;
Simon Kelley4a8c0982021-03-26 21:19:39 +00001371 int tries = 1;
1372 unsigned short ports_avail = 1;
1373
Simon Kelleya2a7e042020-12-12 23:26:45 +00001374 if (addr_copy.sa.sa_family == AF_INET)
1375 port = addr_copy.in.sin_port;
1376 else
1377 port = addr_copy.in6.sin6_port;
Simon Kelley824af852008-02-12 20:43:05 +00001378
1379 /* cannot set source _port_ for TCP connections. */
1380 if (is_tcp)
Simon Kelleya2a7e042020-12-12 23:26:45 +00001381 port = 0;
Simon Kelley4a8c0982021-03-26 21:19:39 +00001382 else if (port == 0 && daemon->max_port != 0)
Simon Kelley824af852008-02-12 20:43:05 +00001383 {
Simon Kelley4a8c0982021-03-26 21:19:39 +00001384 /* Bind a random port within the range given by min-port and max-port if either
1385 or both are set. Otherwise use the OS's random ephemeral port allocation by
1386 leaving port == 0 and tries == 1 */
1387 ports_avail = daemon->max_port - daemon->min_port + 1;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001388 tries = (ports_avail < SMALL_PORT_RANGE) ? ports_avail : 100;
Simon Kelley4a8c0982021-03-26 21:19:39 +00001389 port = htons(daemon->min_port + (rand16() % ports_avail));
Simon Kelley824af852008-02-12 20:43:05 +00001390 }
1391
Simon Kelley4a8c0982021-03-26 21:19:39 +00001392 while (1)
Simon Kelleya2a7e042020-12-12 23:26:45 +00001393 {
Simon Kelley4a8c0982021-03-26 21:19:39 +00001394 /* elide bind() call if it's to port 0, address 0 */
Simon Kelleya2a7e042020-12-12 23:26:45 +00001395 if (addr_copy.sa.sa_family == AF_INET)
Simon Kelleya2a7e042020-12-12 23:26:45 +00001396 {
Simon Kelley4a8c0982021-03-26 21:19:39 +00001397 if (port == 0 && addr_copy.in.sin_addr.s_addr == 0)
1398 break;
1399 addr_copy.in.sin_port = port;
1400 }
1401 else
1402 {
1403 if (port == 0 && IN6_IS_ADDR_UNSPECIFIED(&addr_copy.in6.sin6_addr))
1404 break;
1405 addr_copy.in6.sin6_port = port;
Simon Kelleya2a7e042020-12-12 23:26:45 +00001406 }
1407
Simon Kelley4a8c0982021-03-26 21:19:39 +00001408 if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) != -1)
1409 break;
Simon Kelleya2a7e042020-12-12 23:26:45 +00001410
Simon Kelley4a8c0982021-03-26 21:19:39 +00001411 if (errno != EADDRINUSE && errno != EACCES)
1412 return 0;
Simon Kelleya2a7e042020-12-12 23:26:45 +00001413
Simon Kelley4a8c0982021-03-26 21:19:39 +00001414 if (--tries == 0)
1415 return 0;
1416
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001417 /* For small ranges, do a systematic search, not a random one. */
1418 if (ports_avail < SMALL_PORT_RANGE)
1419 {
1420 unsigned short hport = ntohs(port);
1421 if (hport++ == daemon->max_port)
1422 hport = daemon->min_port;
1423 port = htons(hport);
1424 }
1425 else
1426 port = htons(daemon->min_port + (rand16() % ports_avail));
Simon Kelley4a8c0982021-03-26 21:19:39 +00001427 }
Simon Kelley9d6918d2017-10-13 17:55:09 +01001428
1429 if (!is_tcp && ifindex > 0)
1430 {
1431#if defined(IP_UNICAST_IF)
1432 if (addr_copy.sa.sa_family == AF_INET)
1433 {
1434 uint32_t ifindex_opt = htonl(ifindex);
1435 return setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_opt, sizeof(ifindex_opt)) == 0;
1436 }
1437#endif
Simon Kelleyee875042018-10-23 22:10:17 +01001438#if defined (IPV6_UNICAST_IF)
Simon Kelley9d6918d2017-10-13 17:55:09 +01001439 if (addr_copy.sa.sa_family == AF_INET6)
1440 {
1441 uint32_t ifindex_opt = htonl(ifindex);
1442 return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_opt, sizeof(ifindex_opt)) == 0;
1443 }
1444#endif
1445 }
1446
Kevin Darbyshire-Bryant70c50ef2020-03-06 10:31:15 +00001447 (void)intname; /* suppress potential unused warning */
Simon Kelley824af852008-02-12 20:43:05 +00001448#if defined(SO_BINDTODEVICE)
Simon Kelley73a08a22009-02-05 20:28:08 +00001449 if (intname[0] != 0 &&
Simon Kelley316e2732010-01-22 20:16:09 +00001450 setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
Simon Kelley824af852008-02-12 20:43:05 +00001451 return 0;
1452#endif
1453
1454 return 1;
1455}
1456
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001457static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname, unsigned int ifindex)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001458{
1459 struct serverfd *sfd;
Simon Kelley824af852008-02-12 20:43:05 +00001460 int errsave;
Simon Kelleye83915d2018-04-10 21:27:26 +01001461 int opt = 1;
1462
Simon Kelley1a6bca82008-07-11 11:11:42 +01001463 /* when using random ports, servers which would otherwise use
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001464 the INADDR_ANY/port0 socket have sfd set to NULL, this is
1465 anything without an explictly set source port. */
1466 if (!daemon->osport)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001467 {
1468 errno = 0;
1469
1470 if (addr->sa.sa_family == AF_INET &&
Simon Kelley1a6bca82008-07-11 11:11:42 +01001471 addr->in.sin_port == htons(0))
1472 return NULL;
1473
Simon Kelley1a6bca82008-07-11 11:11:42 +01001474 if (addr->sa.sa_family == AF_INET6 &&
Simon Kelley1a6bca82008-07-11 11:11:42 +01001475 addr->in6.sin6_port == htons(0))
1476 return NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001477 }
Beniamino Galvani2675f202016-08-28 20:44:05 +01001478
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001479 /* may have a suitable one already */
Simon Kelley824af852008-02-12 20:43:05 +00001480 for (sfd = daemon->sfds; sfd; sfd = sfd->next )
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001481 if (ifindex == sfd->ifindex &&
1482 sockaddr_isequal(&sfd->source_addr, addr) &&
1483 strcmp(intname, sfd->interface) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001484 return sfd;
1485
1486 /* need to make a new one. */
1487 errno = ENOMEM; /* in case malloc fails. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001488 if (!(sfd = whine_malloc(sizeof(struct serverfd))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001489 return NULL;
1490
1491 if ((sfd->fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
1492 {
1493 free(sfd);
1494 return NULL;
1495 }
Simon Kelleye83915d2018-04-10 21:27:26 +01001496
1497 if ((addr->sa.sa_family == AF_INET6 && setsockopt(sfd->fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1) ||
1498 !local_bind(sfd->fd, addr, intname, ifindex, 0) || !fix_fd(sfd->fd))
Simon Kelley824af852008-02-12 20:43:05 +00001499 {
Simon Kelleye83915d2018-04-10 21:27:26 +01001500 errsave = errno; /* save error from bind/setsockopt. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001501 close(sfd->fd);
1502 free(sfd);
1503 errno = errsave;
1504 return NULL;
1505 }
Beniamino Galvani2675f202016-08-28 20:44:05 +01001506
Petr Menšík47b45b22018-08-15 18:17:00 +02001507 safe_strncpy(sfd->interface, intname, sizeof(sfd->interface));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001508 sfd->source_addr = *addr;
Simon Kelley824af852008-02-12 20:43:05 +00001509 sfd->next = daemon->sfds;
Beniamino Galvani2675f202016-08-28 20:44:05 +01001510 sfd->ifindex = ifindex;
Simon Kelley4441cf72018-04-10 21:39:54 +01001511 sfd->preallocated = 0;
Simon Kelley824af852008-02-12 20:43:05 +00001512 daemon->sfds = sfd;
Beniamino Galvani2675f202016-08-28 20:44:05 +01001513
Simon Kelley824af852008-02-12 20:43:05 +00001514 return sfd;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001515}
1516
Simon Kelley824af852008-02-12 20:43:05 +00001517/* create upstream sockets during startup, before root is dropped which may be needed
1518 this allows query_port to be a low port and interface binding */
1519void pre_allocate_sfds(void)
1520{
1521 struct server *srv;
Simon Kelley4441cf72018-04-10 21:39:54 +01001522 struct serverfd *sfd;
Simon Kelley824af852008-02-12 20:43:05 +00001523
1524 if (daemon->query_port != 0)
1525 {
1526 union mysockaddr addr;
1527 memset(&addr, 0, sizeof(addr));
1528 addr.in.sin_family = AF_INET;
1529 addr.in.sin_addr.s_addr = INADDR_ANY;
1530 addr.in.sin_port = htons(daemon->query_port);
1531#ifdef HAVE_SOCKADDR_SA_LEN
1532 addr.in.sin_len = sizeof(struct sockaddr_in);
1533#endif
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001534 if ((sfd = allocate_sfd(&addr, "", 0)))
Simon Kelley4441cf72018-04-10 21:39:54 +01001535 sfd->preallocated = 1;
Simon Kelleyee875042018-10-23 22:10:17 +01001536
Simon Kelley824af852008-02-12 20:43:05 +00001537 memset(&addr, 0, sizeof(addr));
1538 addr.in6.sin6_family = AF_INET6;
1539 addr.in6.sin6_addr = in6addr_any;
1540 addr.in6.sin6_port = htons(daemon->query_port);
1541#ifdef HAVE_SOCKADDR_SA_LEN
1542 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
1543#endif
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001544 if ((sfd = allocate_sfd(&addr, "", 0)))
Simon Kelley4441cf72018-04-10 21:39:54 +01001545 sfd->preallocated = 1;
Simon Kelley824af852008-02-12 20:43:05 +00001546 }
1547
1548 for (srv = daemon->servers; srv; srv = srv->next)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001549 if (!allocate_sfd(&srv->source_addr, srv->interface, srv->ifindex) &&
Simon Kelley1a6bca82008-07-11 11:11:42 +01001550 errno != 0 &&
Simon Kelley28866e92011-02-14 20:19:14 +00001551 option_bool(OPT_NOWILD))
Simon Kelley824af852008-02-12 20:43:05 +00001552 {
Petr Mensik51cdd1a2019-07-04 20:28:08 +02001553 (void)prettyprint_addr(&srv->source_addr, daemon->namebuff);
Simon Kelley73a08a22009-02-05 20:28:08 +00001554 if (srv->interface[0] != 0)
Simon Kelley824af852008-02-12 20:43:05 +00001555 {
1556 strcat(daemon->namebuff, " ");
1557 strcat(daemon->namebuff, srv->interface);
1558 }
1559 die(_("failed to bind server socket for %s: %s"),
1560 daemon->namebuff, EC_BADNET);
1561 }
1562}
1563
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001564void check_servers(int no_loop_check)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001565{
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001566 struct irec *iface;
Simon Kelley7bcca002014-02-19 17:45:17 +00001567 struct server *serv;
Beniamino Galvani2675f202016-08-28 20:44:05 +01001568 struct serverfd *sfd, *tmp, **up;
Simon Kelleyb9702602016-05-03 22:34:06 +01001569 int port = 0, count;
Hannu Nyman3e2496f2017-02-11 13:44:08 +00001570 int locals = 0;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001571
1572#ifdef HAVE_LOOP
1573 if (!no_loop_check)
1574 loop_send_probes();
1575#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001576
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001577 /* clear all marks. */
1578 mark_servers(0);
1579
1580 /* interface may be new since startup */
Simon Kelley28866e92011-02-14 20:19:14 +00001581 if (!option_bool(OPT_NOWILD))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001582 enumerate_interfaces(0);
Simon Kelley4441cf72018-04-10 21:39:54 +01001583
1584 /* don't garbage collect pre-allocated sfds. */
Beniamino Galvani2675f202016-08-28 20:44:05 +01001585 for (sfd = daemon->sfds; sfd; sfd = sfd->next)
Simon Kelley4441cf72018-04-10 21:39:54 +01001586 sfd->used = sfd->preallocated;
Beniamino Galvani2675f202016-08-28 20:44:05 +01001587
Simon Kelleyb9702602016-05-03 22:34:06 +01001588 for (count = 0, serv = daemon->servers; serv; serv = serv->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001589 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001590 /* Init edns_pktsz for newly created server records. */
1591 if (serv->edns_pktsz == 0)
1592 serv->edns_pktsz = daemon->edns_pktsz;
1593
Simon Kelley367341f2016-01-12 15:58:23 +00001594#ifdef HAVE_DNSSEC
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001595 if (option_bool(OPT_DNSSEC_VALID))
1596 {
1597 if (!(serv->flags & SERV_FOR_NODOTS))
1598 serv->flags |= SERV_DO_DNSSEC;
1599
1600 /* Disable DNSSEC validation when using server=/domain/.... servers
1601 unless there's a configured trust anchor. */
1602 if (strlen(serv->domain) != 0)
1603 {
1604 struct ds_config *ds;
1605 char *domain = serv->domain;
Simon Kelleya49c5c22017-10-10 22:04:59 +01001606
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001607 /* .example.com is valid */
1608 while (*domain == '.')
1609 domain++;
1610
1611 for (ds = daemon->ds; ds; ds = ds->next)
1612 if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
1613 break;
1614
1615 if (!ds)
1616 serv->flags &= ~SERV_DO_DNSSEC;
Simon Kelley367341f2016-01-12 15:58:23 +00001617 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001618 }
Simon Kelley367341f2016-01-12 15:58:23 +00001619#endif
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001620
1621 port = prettyprint_addr(&serv->addr, daemon->namebuff);
1622
1623 /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
1624 if (serv->addr.sa.sa_family == AF_INET &&
1625 serv->addr.in.sin_addr.s_addr == 0)
1626 {
1627 serv->flags |= SERV_MARK;
1628 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001629 }
1630
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001631 for (iface = daemon->interfaces; iface; iface = iface->next)
1632 if (sockaddr_isequal(&serv->addr, &iface->addr))
1633 break;
1634 if (iface)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001635 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001636 my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
1637 serv->flags |= SERV_MARK;
1638 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001639 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001640
1641 /* Do we need a socket set? */
1642 if (!serv->sfd &&
1643 !(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface, serv->ifindex)) &&
1644 errno != 0)
1645 {
1646 my_syslog(LOG_WARNING,
1647 _("ignoring nameserver %s - cannot make/bind socket: %s"),
1648 daemon->namebuff, strerror(errno));
1649 serv->flags |= SERV_MARK;
1650 continue;
1651 }
1652
1653 if (serv->sfd)
1654 serv->sfd->used = 1;
1655
1656 if (count == SERVERS_LOGGED)
1657 my_syslog(LOG_INFO, _("more servers are defined but not logged"));
1658
1659 if (++count > SERVERS_LOGGED)
1660 continue;
1661
1662 if (strlen(serv->domain) != 0 || (serv->flags & SERV_FOR_NODOTS))
1663 {
1664 char *s1, *s2, *s3 = "", *s4 = "";
1665
1666#ifdef HAVE_DNSSEC
1667 if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
1668 s3 = _("(no DNSSEC)");
1669#endif
1670 if (serv->flags & SERV_FOR_NODOTS)
1671 s1 = _("unqualified"), s2 = _("names");
1672 else if (strlen(serv->domain) == 0)
1673 s1 = _("default"), s2 = "";
1674 else
1675 s1 = _("domain"), s2 = serv->domain, s4 = (serv->flags & SERV_WILDCARD) ? "*" : "";
1676
1677 my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s%s %s"), daemon->namebuff, port, s1, s4, s2, s3);
1678 }
1679#ifdef HAVE_LOOP
1680 else if (serv->flags & SERV_LOOP)
1681 my_syslog(LOG_INFO, _("NOT using nameserver %s#%d - query loop detected"), daemon->namebuff, port);
1682#endif
1683 else if (serv->interface[0] != 0)
1684 my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, serv->interface);
1685 else
1686 my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
1687
1688 }
1689
1690 for (count = 0, serv = daemon->local_domains; serv; serv = serv->next)
1691 {
1692 if (++count > SERVERS_LOGGED)
1693 continue;
1694
1695 if ((serv->flags & SERV_LITERAL_ADDRESS) &&
1696 !(serv->flags & (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)) &&
1697 strlen(serv->domain))
1698 {
1699 count--;
1700 if (++locals <= LOCALS_LOGGED)
1701 my_syslog(LOG_INFO, _("using only locally-known addresses for %s"), serv->domain);
1702 }
1703 else if (serv->flags & SERV_USE_RESOLV)
1704 my_syslog(LOG_INFO, _("using standard nameservers for %s"), serv->domain);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001705 }
Simon Kelleyb9702602016-05-03 22:34:06 +01001706
Hannu Nyman3e2496f2017-02-11 13:44:08 +00001707 if (locals > LOCALS_LOGGED)
1708 my_syslog(LOG_INFO, _("using %d more local addresses"), locals - LOCALS_LOGGED);
Simon Kelleyb9702602016-05-03 22:34:06 +01001709 if (count - 1 > SERVERS_LOGGED)
1710 my_syslog(LOG_INFO, _("using %d more nameservers"), count - SERVERS_LOGGED - 1);
Simon Kelley7bcca002014-02-19 17:45:17 +00001711
Beniamino Galvani2675f202016-08-28 20:44:05 +01001712 /* Remove unused sfds */
1713 for (sfd = daemon->sfds, up = &daemon->sfds; sfd; sfd = tmp)
1714 {
1715 tmp = sfd->next;
1716 if (!sfd->used)
1717 {
1718 *up = sfd->next;
1719 close(sfd->fd);
1720 free(sfd);
1721 }
1722 else
1723 up = &sfd->next;
1724 }
1725
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001726 cleanup_servers(); /* remove servers we just deleted. */
1727 build_server_array();
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001728}
Simon Kelley849a8352006-06-09 21:02:31 +01001729
1730/* Return zero if no servers found, in that case we keep polling.
1731 This is a protection against an update-time/write race on resolv.conf */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001732int reload_servers(char *fname)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001733{
1734 FILE *f;
1735 char *line;
Simon Kelley849a8352006-06-09 21:02:31 +01001736 int gotone = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001737
Simon Kelley849a8352006-06-09 21:02:31 +01001738 /* buff happens to be MAXDNAME long... */
1739 if (!(f = fopen(fname, "r")))
1740 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001741 my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));
Simon Kelley849a8352006-06-09 21:02:31 +01001742 return 0;
1743 }
Simon Kelleyd68c2ca2014-02-18 22:30:30 +00001744
1745 mark_servers(SERV_FROM_RESOLV);
1746
Simon Kelley849a8352006-06-09 21:02:31 +01001747 while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
1748 {
1749 union mysockaddr addr, source_addr;
1750 char *token = strtok(line, " \t\n\r");
1751
Simon Kelley5aabfc72007-08-29 11:24:47 +01001752 if (!token)
1753 continue;
1754 if (strcmp(token, "nameserver") != 0 && strcmp(token, "server") != 0)
Simon Kelley849a8352006-06-09 21:02:31 +01001755 continue;
1756 if (!(token = strtok(NULL, " \t\n\r")))
1757 continue;
1758
1759 memset(&addr, 0, sizeof(addr));
1760 memset(&source_addr, 0, sizeof(source_addr));
1761
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001762 if (inet_pton(AF_INET, token, &addr.in.sin_addr) > 0)
Simon Kelley849a8352006-06-09 21:02:31 +01001763 {
1764#ifdef HAVE_SOCKADDR_SA_LEN
1765 source_addr.in.sin_len = addr.in.sin_len = sizeof(source_addr.in);
1766#endif
1767 source_addr.in.sin_family = addr.in.sin_family = AF_INET;
1768 addr.in.sin_port = htons(NAMESERVER_PORT);
1769 source_addr.in.sin_addr.s_addr = INADDR_ANY;
1770 source_addr.in.sin_port = htons(daemon->query_port);
1771 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001772 else
1773 {
1774 int scope_index = 0;
1775 char *scope_id = strchr(token, '%');
1776
1777 if (scope_id)
1778 {
1779 *(scope_id++) = 0;
1780 scope_index = if_nametoindex(scope_id);
1781 }
1782
1783 if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
1784 {
Simon Kelley849a8352006-06-09 21:02:31 +01001785#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley7de060b2011-08-26 17:24:52 +01001786 source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
Simon Kelley849a8352006-06-09 21:02:31 +01001787#endif
Simon Kelley7de060b2011-08-26 17:24:52 +01001788 source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
1789 source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
1790 addr.in6.sin6_port = htons(NAMESERVER_PORT);
1791 addr.in6.sin6_scope_id = scope_index;
1792 source_addr.in6.sin6_addr = in6addr_any;
1793 source_addr.in6.sin6_port = htons(daemon->query_port);
1794 source_addr.in6.sin6_scope_id = 0;
1795 }
1796 else
1797 continue;
Simon Kelley849a8352006-06-09 21:02:31 +01001798 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001799
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001800 add_update_server(SERV_FROM_RESOLV, &addr, &source_addr, NULL, NULL, NULL);
Simon Kelley849a8352006-06-09 21:02:31 +01001801 gotone = 1;
1802 }
1803
Simon Kelley849a8352006-06-09 21:02:31 +01001804 fclose(f);
Simon Kelleyd68c2ca2014-02-18 22:30:30 +00001805 cleanup_servers();
Simon Kelley849a8352006-06-09 21:02:31 +01001806
1807 return gotone;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001808}
1809
Simon Kelley1ee9be42013-12-09 16:50:19 +00001810/* Called when addresses are added or deleted from an interface */
1811void newaddress(time_t now)
1812{
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001813 struct dhcp_relay *relay;
1814
Simon Kelley1ee9be42013-12-09 16:50:19 +00001815 (void)now;
1816
Simon Kelley89b12ed2014-03-06 13:27:57 +00001817 if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
1818 daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
Simon Kelley1ee9be42013-12-09 16:50:19 +00001819 enumerate_interfaces(0);
1820
1821 if (option_bool(OPT_CLEVERBIND))
1822 create_bound_listeners(0);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001823
1824#ifdef HAVE_DHCP
1825 /* clear cache of subnet->relay index */
1826 for (relay = daemon->relay4; relay; relay = relay->next)
1827 relay->iface_index = 0;
1828#endif
Simon Kelley1ee9be42013-12-09 16:50:19 +00001829
1830#ifdef HAVE_DHCP6
1831 if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
1832 join_multicast(0);
1833
1834 if (daemon->doing_dhcp6 || daemon->doing_ra)
1835 dhcp_construct_contexts(now);
1836
1837 if (daemon->doing_dhcp6)
1838 lease_find_interfaces(now);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001839
1840 for (relay = daemon->relay6; relay; relay = relay->next)
1841 relay->iface_index = 0;
Simon Kelley1ee9be42013-12-09 16:50:19 +00001842#endif
1843}