blob: fda50bdc0564def43a5b2bc06954efe963f82d4c [file] [log] [blame]
Simon Kelley59546082012-01-06 20:02:04 +00001/* dnsmasq is Copyright (c) 2000-2012 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
32 strncpy(name, ifr.ifr_name, IF_NAMESIZE);
33
34 return 1;
35}
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;
85 strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
86 if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0)
87 return 0;
88
89 if (lifr.lifr_index == index) {
90 strncpy(name, lifr.lifr_name, IF_NAMESIZE);
91 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{
102 if (index == 0 || !if_indextoname(index, name))
103 return 0;
104
105 return 1;
106}
107
108#endif
109
Simon Kelleyc72daea2012-01-05 21:33:27 +0000110int iface_check(int family, struct all_addr *addr, char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000111{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000112 struct iname *tmp;
Simon Kelley309331f2006-04-22 15:05:01 +0100113 int ret = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100114
Simon Kelley309331f2006-04-22 15:05:01 +0100115 /* Note: have to check all and not bail out early, so that we set the
116 "used" flags. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100117
Simon Kelleyc72daea2012-01-05 21:33:27 +0000118 if (daemon->if_names || daemon->if_addrs)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100119 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100120 ret = 0;
121
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100122 for (tmp = daemon->if_names; tmp; tmp = tmp->next)
123 if (tmp->name && (strcmp(tmp->name, name) == 0))
124 ret = tmp->used = 1;
125
126 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000127 if (tmp->addr.sa.sa_family == family)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100128 {
129 if (family == AF_INET &&
130 tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
131 ret = tmp->used = 1;
132#ifdef HAVE_IPV6
133 else if (family == AF_INET6 &&
134 IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
135 &addr->addr.addr6))
136 ret = tmp->used = 1;
137#endif
138 }
139 }
140
141 for (tmp = daemon->if_except; tmp; tmp = tmp->next)
142 if (tmp->name && (strcmp(tmp->name, name) == 0))
143 ret = 0;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000144
Simon Kelley309331f2006-04-22 15:05:01 +0100145 return ret;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100146}
147
Simon Kelley5aabfc72007-08-29 11:24:47 +0100148static int iface_allowed(struct irec **irecp, int if_index,
Simon Kelley74c95c22011-10-19 09:33:39 +0100149 union mysockaddr *addr, struct in_addr netmask, int dad)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100150{
151 struct irec *iface;
Simon Kelley1f15b812009-10-13 17:49:32 +0100152 int fd, mtu = 0, loopback;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100153 struct ifreq ifr;
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100154 int tftp_ok = !!option_bool(OPT_TFTP);
Simon Kelley9380ba72012-04-16 14:41:56 +0100155 int dhcp_ok = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100156#ifdef HAVE_DHCP
Simon Kelley832af0b2007-01-21 20:01:28 +0000157 struct iname *tmp;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100158#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100159
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100160 /* check whether the interface IP has been added already
161 we call this routine multiple times. */
162 for (iface = *irecp; iface; iface = iface->next)
163 if (sockaddr_isequal(&iface->addr, addr))
Simon Kelley74c95c22011-10-19 09:33:39 +0100164 {
165 iface->dad = dad;
166 return 1;
167 }
168
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100169 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
Simon Kelley7622fc02009-06-04 20:32:05 +0100170 !indextoname(fd, if_index, ifr.ifr_name) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100171 ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
172 {
173 if (fd != -1)
174 {
175 int errsave = errno;
176 close(fd);
177 errno = errsave;
178 }
179 return 0;
180 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100181
182 loopback = ifr.ifr_flags & IFF_LOOPBACK;
Simon Kelley9380ba72012-04-16 14:41:56 +0100183
184 if (loopback)
185 dhcp_ok = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100186
187 if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
188 mtu = ifr.ifr_mtu;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100189
190 close(fd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000191
Simon Kelley59353a62004-11-21 19:34:28 +0000192 /* If we are restricting the set of interfaces to use, make
193 sure that loopback interfaces are in that set. */
Simon Kelley1f15b812009-10-13 17:49:32 +0100194 if (daemon->if_names && loopback)
Simon Kelley59353a62004-11-21 19:34:28 +0000195 {
196 struct iname *lo;
197 for (lo = daemon->if_names; lo; lo = lo->next)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100198 if (lo->name && strcmp(lo->name, ifr.ifr_name) == 0)
Simon Kelley4ce4f372012-06-14 11:50:45 +0100199 break;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100200
Simon Kelley5aabfc72007-08-29 11:24:47 +0100201 if (!lo &&
202 (lo = whine_malloc(sizeof(struct iname))) &&
203 (lo->name = whine_malloc(strlen(ifr.ifr_name)+1)))
Simon Kelley59353a62004-11-21 19:34:28 +0000204 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100205 strcpy(lo->name, ifr.ifr_name);
Simon Kelley4ce4f372012-06-14 11:50:45 +0100206 lo->used = 1;
Simon Kelley59353a62004-11-21 19:34:28 +0000207 lo->next = daemon->if_names;
208 daemon->if_names = lo;
209 }
210 }
211
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100212 if (addr->sa.sa_family == AF_INET &&
213 !iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name))
214 return 1;
215
216#ifdef HAVE_DHCP
217 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
218 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
Simon Kelley28866e92011-02-14 20:19:14 +0000219 {
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100220 tftp_ok = 0;
221 dhcp_ok = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000222 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100223#endif
Simon Kelley28866e92011-02-14 20:19:14 +0000224
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100225#ifdef HAVE_IPV6
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100226 if (addr->sa.sa_family == AF_INET6 &&
227 !iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name))
228 return 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100229#endif
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100230
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100231
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100232 /* add to list */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100233 if ((iface = whine_malloc(sizeof(struct irec))))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100234 {
235 iface->addr = *addr;
236 iface->netmask = netmask;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100237 iface->tftp_ok = tftp_ok;
Simon Kelley9380ba72012-04-16 14:41:56 +0100238 iface->dhcp_ok = dhcp_ok;
Simon Kelley1f15b812009-10-13 17:49:32 +0100239 iface->mtu = mtu;
Simon Kelley74c95c22011-10-19 09:33:39 +0100240 iface->dad = dad;
241 iface->done = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100242 if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
Simon Kelley6f13e532012-04-17 14:25:06 +0100243 {
244 strcpy(iface->name, ifr.ifr_name);
245 iface->next = *irecp;
246 *irecp = iface;
247 return 1;
248 }
249 free(iface);
Simon Kelley44a2a312004-03-10 20:04:35 +0000250 }
251
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100252 errno = ENOMEM;
253 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000254}
255
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100256#ifdef HAVE_IPV6
Simon Kelleyc72daea2012-01-05 21:33:27 +0000257static int iface_allowed_v6(struct in6_addr *local, int prefix,
Simon Kelley74c95c22011-10-19 09:33:39 +0100258 int scope, int if_index, int dad, void *vparam)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000259{
Simon Kelley59353a62004-11-21 19:34:28 +0000260 union mysockaddr addr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100261 struct in_addr netmask; /* dummy */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100262 netmask.s_addr = 0;
Simon Kelley52b92f42012-01-22 16:05:15 +0000263
264 (void)prefix; /* warning */
265 (void)scope; /* warning */
Simon Kelley44a2a312004-03-10 20:04:35 +0000266
Simon Kelley849a8352006-06-09 21:02:31 +0100267 memset(&addr, 0, sizeof(addr));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000268#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100269 addr.in6.sin6_len = sizeof(addr.in6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000270#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100271 addr.in6.sin6_family = AF_INET6;
272 addr.in6.sin6_addr = *local;
273 addr.in6.sin6_port = htons(daemon->port);
Simon Kelley52b92f42012-01-22 16:05:15 +0000274 addr.in6.sin6_scope_id = if_index;
Simon Kelley849a8352006-06-09 21:02:31 +0100275
Simon Kelley74c95c22011-10-19 09:33:39 +0100276 return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, dad);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100277}
278#endif
Simon Kelley59353a62004-11-21 19:34:28 +0000279
Simon Kelley5aabfc72007-08-29 11:24:47 +0100280static int iface_allowed_v4(struct in_addr local, int if_index,
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100281 struct in_addr netmask, struct in_addr broadcast, void *vparam)
282{
283 union mysockaddr addr;
Simon Kelley849a8352006-06-09 21:02:31 +0100284
285 memset(&addr, 0, sizeof(addr));
Simon Kelley1ab84e22004-01-29 16:48:35 +0000286#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100287 addr.in.sin_len = sizeof(addr.in);
Simon Kelley1ab84e22004-01-29 16:48:35 +0000288#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100289 addr.in.sin_family = AF_INET;
290 addr.in.sin_addr = broadcast; /* warning */
291 addr.in.sin_addr = local;
292 addr.in.sin_port = htons(daemon->port);
Simon Kelley44a2a312004-03-10 20:04:35 +0000293
Simon Kelley74c95c22011-10-19 09:33:39 +0100294 return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100295}
296
Simon Kelley5aabfc72007-08-29 11:24:47 +0100297int enumerate_interfaces(void)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100298{
299#ifdef HAVE_IPV6
Simon Kelley28866e92011-02-14 20:19:14 +0000300 if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))
301 return 0;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100302#endif
Simon Kelley28866e92011-02-14 20:19:14 +0000303
304 return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4);
Simon Kelley44a2a312004-03-10 20:04:35 +0000305}
306
Simon Kelley5aabfc72007-08-29 11:24:47 +0100307/* set NONBLOCK bit on fd: See Stevens 16.6 */
Simon Kelley7cebd202006-05-06 14:13:33 +0100308int fix_fd(int fd)
309{
310 int flags;
311
312 if ((flags = fcntl(fd, F_GETFL)) == -1 ||
Simon Kelley5aabfc72007-08-29 11:24:47 +0100313 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
Simon Kelley7cebd202006-05-06 14:13:33 +0100314 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100315
Simon Kelley7cebd202006-05-06 14:13:33 +0100316 return 1;
317}
318
Simon Kelley74c95c22011-10-19 09:33:39 +0100319static int make_sock(union mysockaddr *addr, int type, int dienow)
Simon Kelley44a2a312004-03-10 20:04:35 +0000320{
Simon Kelley28866e92011-02-14 20:19:14 +0000321 int family = addr->sa.sa_family;
322 int fd, rc, opt = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100323
Simon Kelley28866e92011-02-14 20:19:14 +0000324 if ((fd = socket(family, type, 0)) == -1)
Simon Kelley316e2732010-01-22 20:16:09 +0000325 {
Simon Kelley28866e92011-02-14 20:19:14 +0000326 int port;
Simon Kelley39f1b8e2012-06-20 20:04:27 +0100327 char *s;
Simon Kelley28866e92011-02-14 20:19:14 +0000328
329 /* No error if the kernel just doesn't support this IP flavour */
330 if (errno == EPROTONOSUPPORT ||
331 errno == EAFNOSUPPORT ||
332 errno == EINVAL)
333 return -1;
334
335 err:
Simon Kelley39f1b8e2012-06-20 20:04:27 +0100336 port = prettyprint_addr(addr, daemon->addrbuff);
337 if (!option_bool(OPT_NOWILD) && !option_bool(OPT_CLEVERBIND))
338 sprintf(daemon->addrbuff, "port %d", port);
339 s = _("failed to create listening socket for %s: %s");
340
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100341 if (fd != -1)
342 close (fd);
Simon Kelley39f1b8e2012-06-20 20:04:27 +0100343
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100344 if (dienow)
345 {
346 /* failure to bind addresses given by --listen-address at this point
347 is OK if we're doing bind-dynamic */
348 if (!option_bool(OPT_CLEVERBIND))
349 die(s, daemon->addrbuff, EC_BADNET);
350 }
351 else
352 my_syslog(LOG_WARNING, s, daemon->addrbuff, strerror(errno));
353
Simon Kelley74c95c22011-10-19 09:33:39 +0100354 return -1;
Simon Kelley28866e92011-02-14 20:19:14 +0000355 }
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100356
Simon Kelley28866e92011-02-14 20:19:14 +0000357 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
358 goto err;
359
360#ifdef HAVE_IPV6
Simon Kelleyc72daea2012-01-05 21:33:27 +0000361 if (family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000362 goto err;
363#endif
364
Simon Kelley74c95c22011-10-19 09:33:39 +0100365 if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000366 goto err;
367
368 if (type == SOCK_STREAM)
369 {
370 if (listen(fd, 5) == -1)
371 goto err;
372 }
373 else if (!option_bool(OPT_NOWILD))
374 {
375 if (family == AF_INET)
376 {
377#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000378 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000379 goto err;
380#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
381 if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
382 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1)
383 goto err;
384#endif
385 }
386#ifdef HAVE_IPV6
Simon Kelleyc72daea2012-01-05 21:33:27 +0000387 else if (!set_ipv6pktinfo(fd))
388 goto err;
Simon Kelley316e2732010-01-22 20:16:09 +0000389#endif
Simon Kelley28866e92011-02-14 20:19:14 +0000390 }
Simon Kelleyc72daea2012-01-05 21:33:27 +0000391
Simon Kelley28866e92011-02-14 20:19:14 +0000392 return fd;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100393}
Simon Kelleyc72daea2012-01-05 21:33:27 +0000394
395#ifdef HAVE_IPV6
396int set_ipv6pktinfo(int fd)
397{
398 int opt = 1;
399
400 /* The API changed around Linux 2.6.14 but the old ABI is still supported:
401 handle all combinations of headers and kernel.
402 OpenWrt note that this fixes the problem addressed by your very broken patch. */
403 daemon->v6pktinfo = IPV6_PKTINFO;
404
405#ifdef IPV6_RECVPKTINFO
406 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)) != -1)
407 return 1;
408# ifdef IPV6_2292PKTINFO
409 else if (errno == ENOPROTOOPT && setsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
410 {
411 daemon->v6pktinfo = IPV6_2292PKTINFO;
412 return 1;
413 }
414# endif
415#else
416 if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &opt, sizeof(opt)) != -1)
417 return 1;
418#endif
419
420 return 0;
421}
422#endif
Simon Kelley28866e92011-02-14 20:19:14 +0000423
Simon Kelley74c95c22011-10-19 09:33:39 +0100424static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
Simon Kelley28866e92011-02-14 20:19:14 +0000425{
426 struct listener *l = NULL;
427 int fd = -1, tcpfd = -1, tftpfd = -1;
428
429 if (daemon->port != 0)
430 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100431 fd = make_sock(addr, SOCK_DGRAM, dienow);
432 tcpfd = make_sock(addr, SOCK_STREAM, dienow);
Simon Kelley28866e92011-02-14 20:19:14 +0000433 }
434
435#ifdef HAVE_TFTP
436 if (do_tftp)
437 {
438 if (addr->sa.sa_family == AF_INET)
439 {
440 /* port must be restored to DNS port for TCP code */
441 short save = addr->in.sin_port;
442 addr->in.sin_port = htons(TFTP_PORT);
Simon Kelley74c95c22011-10-19 09:33:39 +0100443 tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
Simon Kelley28866e92011-02-14 20:19:14 +0000444 addr->in.sin_port = save;
445 }
446# ifdef HAVE_IPV6
447 else
448 {
449 short save = addr->in6.sin6_port;
450 addr->in6.sin6_port = htons(TFTP_PORT);
Simon Kelley74c95c22011-10-19 09:33:39 +0100451 tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
Simon Kelley28866e92011-02-14 20:19:14 +0000452 addr->in6.sin6_port = save;
453 }
454# endif
455 }
Simon Kelley44a2a312004-03-10 20:04:35 +0000456#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100457
Simon Kelley28866e92011-02-14 20:19:14 +0000458 if (fd != -1 || tcpfd != -1 || tftpfd != -1)
459 {
460 l = safe_malloc(sizeof(struct listener));
461 l->next = NULL;
462 l->family = addr->sa.sa_family;
463 l->fd = fd;
464 l->tcpfd = tcpfd;
465 l->tftpfd = tftpfd;
466 }
467
468 return l;
469}
470
Simon Kelley74c95c22011-10-19 09:33:39 +0100471void create_wildcard_listeners(void)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100472{
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100473 union mysockaddr addr;
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100474 struct listener *l, *l6;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100475
Simon Kelley849a8352006-06-09 21:02:31 +0100476 memset(&addr, 0, sizeof(addr));
Simon Kelley28866e92011-02-14 20:19:14 +0000477#ifdef HAVE_SOCKADDR_SA_LEN
478 addr.in.sin_len = sizeof(addr.in);
479#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100480 addr.in.sin_family = AF_INET;
481 addr.in.sin_addr.s_addr = INADDR_ANY;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100482 addr.in.sin_port = htons(daemon->port);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100483
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100484 l = create_listeners(&addr, !!option_bool(OPT_TFTP), 1);
Simon Kelley28866e92011-02-14 20:19:14 +0000485
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100486#ifdef HAVE_IPV6
Simon Kelley28866e92011-02-14 20:19:14 +0000487 memset(&addr, 0, sizeof(addr));
488# ifdef HAVE_SOCKADDR_SA_LEN
489 addr.in6.sin6_len = sizeof(addr.in6);
490# endif
491 addr.in6.sin6_family = AF_INET6;
492 addr.in6.sin6_addr = in6addr_any;
493 addr.in6.sin6_port = htons(daemon->port);
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100494
495 l6 = create_listeners(&addr, !!option_bool(OPT_TFTP), 1);
Simon Kelley28866e92011-02-14 20:19:14 +0000496 if (l)
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100497 l->next = l6;
Simon Kelley28866e92011-02-14 20:19:14 +0000498 else
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100499 l = l6;
Simon Kelley832af0b2007-01-21 20:01:28 +0000500#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100501
Simon Kelley74c95c22011-10-19 09:33:39 +0100502 daemon->listeners = l;
Simon Kelley44a2a312004-03-10 20:04:35 +0000503}
504
Simon Kelley74c95c22011-10-19 09:33:39 +0100505void create_bound_listeners(int dienow)
Simon Kelley44a2a312004-03-10 20:04:35 +0000506{
Simon Kelley74c95c22011-10-19 09:33:39 +0100507 struct listener *new;
Simon Kelley44a2a312004-03-10 20:04:35 +0000508 struct irec *iface;
Simon Kelley52d4abf2012-03-21 21:39:48 +0000509 struct iname *if_tmp;
Simon Kelley73a08a22009-02-05 20:28:08 +0000510
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100511 for (iface = daemon->interfaces; iface; iface = iface->next)
Simon Kelley74c95c22011-10-19 09:33:39 +0100512 if (!iface->done && !iface->dad &&
513 (new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
Simon Kelley28866e92011-02-14 20:19:14 +0000514 {
515 new->iface = iface;
Simon Kelley74c95c22011-10-19 09:33:39 +0100516 new->next = daemon->listeners;
517 daemon->listeners = new;
518 iface->done = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000519 }
Simon Kelley52d4abf2012-03-21 21:39:48 +0000520
521 /* Check for --listen-address options that haven't been used because there's
522 no interface with a matching address. These may be valid: eg it's possible
523 to listen on 127.0.1.1 even if the loopback interface is 127.0.0.1
524
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100525 If the address isn't valid the bind() will fail and we'll die()
526 (except in bind-dynamic mode, when we'll complain but keep trying.)
Simon Kelley52d4abf2012-03-21 21:39:48 +0000527
528 The resulting listeners have the ->iface field NULL, and this has to be
529 handled by the DNS and TFTP code. It disables --localise-queries processing
530 (no netmask) and some MTU login the tftp code. */
531
532 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
533 if (!if_tmp->used &&
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100534 (new = create_listeners(&if_tmp->addr, !!option_bool(OPT_TFTP), dienow)))
Simon Kelley52d4abf2012-03-21 21:39:48 +0000535 {
536 new->iface = NULL;
537 new->next = daemon->listeners;
538 daemon->listeners = new;
539 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000540}
541
Simon Kelley74c95c22011-10-19 09:33:39 +0100542int is_dad_listeners(void)
543{
544 struct irec *iface;
545
546 if (option_bool(OPT_NOWILD))
547 for (iface = daemon->interfaces; iface; iface = iface->next)
548 if (iface->dad && !iface->done)
549 return 1;
550
551 return 0;
552}
Simon Kelley9009d742008-11-14 20:04:27 +0000553/* return a UDP socket bound to a random port, have to cope with straying into
Simon Kelley1a6bca82008-07-11 11:11:42 +0100554 occupied port nos and reserved ones. */
555int random_sock(int family)
556{
557 int fd;
558
559 if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
560 {
Simon Kelley3927da42008-07-20 15:10:39 +0100561 union mysockaddr addr;
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100562 unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port;
Simon Kelley9009d742008-11-14 20:04:27 +0000563 int tries = ports_avail < 30 ? 3 * ports_avail : 100;
Simon Kelley3927da42008-07-20 15:10:39 +0100564
Simon Kelley1a6bca82008-07-11 11:11:42 +0100565 memset(&addr, 0, sizeof(addr));
Simon Kelley3927da42008-07-20 15:10:39 +0100566 addr.sa.sa_family = family;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100567
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100568 /* don't loop forever if all ports in use. */
569
Simon Kelley1a6bca82008-07-11 11:11:42 +0100570 if (fix_fd(fd))
Simon Kelley9009d742008-11-14 20:04:27 +0000571 while(tries--)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100572 {
573 unsigned short port = rand16();
574
Simon Kelley3927da42008-07-20 15:10:39 +0100575 if (daemon->min_port != 0)
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100576 port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
Simon Kelley1a6bca82008-07-11 11:11:42 +0100577
578 if (family == AF_INET)
579 {
580 addr.in.sin_addr.s_addr = INADDR_ANY;
Simon Kelley3927da42008-07-20 15:10:39 +0100581 addr.in.sin_port = port;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100582#ifdef HAVE_SOCKADDR_SA_LEN
583 addr.in.sin_len = sizeof(struct sockaddr_in);
584#endif
585 }
586#ifdef HAVE_IPV6
587 else
588 {
589 addr.in6.sin6_addr = in6addr_any;
Simon Kelley3927da42008-07-20 15:10:39 +0100590 addr.in6.sin6_port = port;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100591#ifdef HAVE_SOCKADDR_SA_LEN
592 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
593#endif
594 }
595#endif
596
597 if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)
598 return fd;
599
600 if (errno != EADDRINUSE && errno != EACCES)
601 break;
602 }
603
604 close(fd);
605 }
606
607 return -1;
608}
609
610
Simon Kelley824af852008-02-12 20:43:05 +0000611int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
612{
613 union mysockaddr addr_copy = *addr;
614
615 /* cannot set source _port_ for TCP connections. */
616 if (is_tcp)
617 {
618 if (addr_copy.sa.sa_family == AF_INET)
619 addr_copy.in.sin_port = 0;
620#ifdef HAVE_IPV6
621 else
622 addr_copy.in6.sin6_port = 0;
623#endif
624 }
625
626 if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
627 return 0;
628
629#if defined(SO_BINDTODEVICE)
Simon Kelley73a08a22009-02-05 20:28:08 +0000630 if (intname[0] != 0 &&
Simon Kelley316e2732010-01-22 20:16:09 +0000631 setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
Simon Kelley824af852008-02-12 20:43:05 +0000632 return 0;
633#endif
634
635 return 1;
636}
637
638static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000639{
640 struct serverfd *sfd;
Simon Kelley824af852008-02-12 20:43:05 +0000641 int errsave;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100642
Simon Kelley1a6bca82008-07-11 11:11:42 +0100643 /* when using random ports, servers which would otherwise use
644 the INADDR_ANY/port0 socket have sfd set to NULL */
Simon Kelley73a08a22009-02-05 20:28:08 +0000645 if (!daemon->osport && intname[0] == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100646 {
647 errno = 0;
648
649 if (addr->sa.sa_family == AF_INET &&
650 addr->in.sin_addr.s_addr == INADDR_ANY &&
651 addr->in.sin_port == htons(0))
652 return NULL;
653
654#ifdef HAVE_IPV6
655 if (addr->sa.sa_family == AF_INET6 &&
656 memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
657 addr->in6.sin6_port == htons(0))
658 return NULL;
659#endif
660 }
661
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000662 /* may have a suitable one already */
Simon Kelley824af852008-02-12 20:43:05 +0000663 for (sfd = daemon->sfds; sfd; sfd = sfd->next )
664 if (sockaddr_isequal(&sfd->source_addr, addr) &&
665 strcmp(intname, sfd->interface) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000666 return sfd;
667
668 /* need to make a new one. */
669 errno = ENOMEM; /* in case malloc fails. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100670 if (!(sfd = whine_malloc(sizeof(struct serverfd))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000671 return NULL;
672
673 if ((sfd->fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
674 {
675 free(sfd);
676 return NULL;
677 }
678
Simon Kelley824af852008-02-12 20:43:05 +0000679 if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd))
680 {
681 errsave = errno; /* save error from bind. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000682 close(sfd->fd);
683 free(sfd);
684 errno = errsave;
685 return NULL;
686 }
Simon Kelley824af852008-02-12 20:43:05 +0000687
688 strcpy(sfd->interface, intname);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000689 sfd->source_addr = *addr;
Simon Kelley824af852008-02-12 20:43:05 +0000690 sfd->next = daemon->sfds;
691 daemon->sfds = sfd;
692 return sfd;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000693}
694
Simon Kelley824af852008-02-12 20:43:05 +0000695/* create upstream sockets during startup, before root is dropped which may be needed
696 this allows query_port to be a low port and interface binding */
697void pre_allocate_sfds(void)
698{
699 struct server *srv;
700
701 if (daemon->query_port != 0)
702 {
703 union mysockaddr addr;
704 memset(&addr, 0, sizeof(addr));
705 addr.in.sin_family = AF_INET;
706 addr.in.sin_addr.s_addr = INADDR_ANY;
707 addr.in.sin_port = htons(daemon->query_port);
708#ifdef HAVE_SOCKADDR_SA_LEN
709 addr.in.sin_len = sizeof(struct sockaddr_in);
710#endif
711 allocate_sfd(&addr, "");
712#ifdef HAVE_IPV6
713 memset(&addr, 0, sizeof(addr));
714 addr.in6.sin6_family = AF_INET6;
715 addr.in6.sin6_addr = in6addr_any;
716 addr.in6.sin6_port = htons(daemon->query_port);
717#ifdef HAVE_SOCKADDR_SA_LEN
718 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
719#endif
720 allocate_sfd(&addr, "");
721#endif
722 }
723
724 for (srv = daemon->servers; srv; srv = srv->next)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100725 if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
Simon Kelley824af852008-02-12 20:43:05 +0000726 !allocate_sfd(&srv->source_addr, srv->interface) &&
Simon Kelley1a6bca82008-07-11 11:11:42 +0100727 errno != 0 &&
Simon Kelley28866e92011-02-14 20:19:14 +0000728 option_bool(OPT_NOWILD))
Simon Kelley824af852008-02-12 20:43:05 +0000729 {
Simon Kelley316e2732010-01-22 20:16:09 +0000730 prettyprint_addr(&srv->source_addr, daemon->namebuff);
Simon Kelley73a08a22009-02-05 20:28:08 +0000731 if (srv->interface[0] != 0)
Simon Kelley824af852008-02-12 20:43:05 +0000732 {
733 strcat(daemon->namebuff, " ");
734 strcat(daemon->namebuff, srv->interface);
735 }
736 die(_("failed to bind server socket for %s: %s"),
737 daemon->namebuff, EC_BADNET);
738 }
739}
740
741
Simon Kelley5aabfc72007-08-29 11:24:47 +0100742void check_servers(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000743{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000744 struct irec *iface;
Simon Kelley3be34542004-09-11 19:12:13 +0100745 struct server *new, *tmp, *ret = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000746 int port = 0;
747
Simon Kelley316e2732010-01-22 20:16:09 +0000748 /* interface may be new since startup */
Simon Kelley28866e92011-02-14 20:19:14 +0000749 if (!option_bool(OPT_NOWILD))
Simon Kelley316e2732010-01-22 20:16:09 +0000750 enumerate_interfaces();
751
Simon Kelley3be34542004-09-11 19:12:13 +0100752 for (new = daemon->servers; new; new = tmp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000753 {
754 tmp = new->next;
755
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100756 if (!(new->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000757 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100758 port = prettyprint_addr(&new->addr, daemon->namebuff);
759
Simon Kelley16972692006-10-16 20:04:18 +0100760 /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
761 if (new->addr.sa.sa_family == AF_INET &&
762 new->addr.in.sin_addr.s_addr == 0)
763 {
764 free(new);
765 continue;
766 }
767
Simon Kelley3d8df262005-08-29 12:19:27 +0100768 for (iface = daemon->interfaces; iface; iface = iface->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000769 if (sockaddr_isequal(&new->addr, &iface->addr))
770 break;
771 if (iface)
772 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100773 my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000774 free(new);
775 continue;
776 }
777
778 /* Do we need a socket set? */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100779 if (!new->sfd &&
780 !(new->sfd = allocate_sfd(&new->source_addr, new->interface)) &&
781 errno != 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000782 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100783 my_syslog(LOG_WARNING,
784 _("ignoring nameserver %s - cannot make/bind socket: %s"),
785 daemon->namebuff, strerror(errno));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000786 free(new);
787 continue;
788 }
789 }
790
791 /* reverse order - gets it right. */
792 new->next = ret;
793 ret = new;
794
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100795 if (!(new->flags & SERV_NO_REBIND))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000796 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100797 if (new->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
798 {
799 char *s1, *s2;
800 if (!(new->flags & SERV_HAS_DOMAIN))
801 s1 = _("unqualified"), s2 = _("names");
802 else if (strlen(new->domain) == 0)
803 s1 = _("default"), s2 = "";
804 else
805 s1 = _("domain"), s2 = new->domain;
806
807 if (new->flags & SERV_NO_ADDR)
808 my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
809 else if (new->flags & SERV_USE_RESOLV)
810 my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
811 else if (!(new->flags & SERV_LITERAL_ADDRESS))
812 my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
813 }
814 else if (new->interface[0] != 0)
815 my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, new->interface);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000816 else
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100817 my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000818 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000819 }
820
Simon Kelley3be34542004-09-11 19:12:13 +0100821 daemon->servers = ret;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000822}
Simon Kelley849a8352006-06-09 21:02:31 +0100823
824/* Return zero if no servers found, in that case we keep polling.
825 This is a protection against an update-time/write race on resolv.conf */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100826int reload_servers(char *fname)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000827{
828 FILE *f;
829 char *line;
830 struct server *old_servers = NULL;
831 struct server *new_servers = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +0100832 struct server *serv;
833 int gotone = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000834
Simon Kelley849a8352006-06-09 21:02:31 +0100835 /* buff happens to be MAXDNAME long... */
836 if (!(f = fopen(fname, "r")))
837 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100838 my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));
Simon Kelley849a8352006-06-09 21:02:31 +0100839 return 0;
840 }
841
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000842 /* move old servers to free list - we can reuse the memory
843 and not risk malloc if there are the same or fewer new servers.
844 Servers which were specced on the command line go to the new list. */
Simon Kelley849a8352006-06-09 21:02:31 +0100845 for (serv = daemon->servers; serv;)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000846 {
847 struct server *tmp = serv->next;
848 if (serv->flags & SERV_FROM_RESOLV)
849 {
850 serv->next = old_servers;
Simon Kelley849a8352006-06-09 21:02:31 +0100851 old_servers = serv;
852 /* forward table rules reference servers, so have to blow them away */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100853 server_gone(serv);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000854 }
855 else
856 {
857 serv->next = new_servers;
858 new_servers = serv;
859 }
860 serv = tmp;
861 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000862
Simon Kelley849a8352006-06-09 21:02:31 +0100863 while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
864 {
865 union mysockaddr addr, source_addr;
866 char *token = strtok(line, " \t\n\r");
867
Simon Kelley5aabfc72007-08-29 11:24:47 +0100868 if (!token)
869 continue;
870 if (strcmp(token, "nameserver") != 0 && strcmp(token, "server") != 0)
Simon Kelley849a8352006-06-09 21:02:31 +0100871 continue;
872 if (!(token = strtok(NULL, " \t\n\r")))
873 continue;
874
875 memset(&addr, 0, sizeof(addr));
876 memset(&source_addr, 0, sizeof(source_addr));
877
878 if ((addr.in.sin_addr.s_addr = inet_addr(token)) != (in_addr_t) -1)
879 {
880#ifdef HAVE_SOCKADDR_SA_LEN
881 source_addr.in.sin_len = addr.in.sin_len = sizeof(source_addr.in);
882#endif
883 source_addr.in.sin_family = addr.in.sin_family = AF_INET;
884 addr.in.sin_port = htons(NAMESERVER_PORT);
885 source_addr.in.sin_addr.s_addr = INADDR_ANY;
886 source_addr.in.sin_port = htons(daemon->query_port);
887 }
888#ifdef HAVE_IPV6
Simon Kelley7de060b2011-08-26 17:24:52 +0100889 else
890 {
891 int scope_index = 0;
892 char *scope_id = strchr(token, '%');
893
894 if (scope_id)
895 {
896 *(scope_id++) = 0;
897 scope_index = if_nametoindex(scope_id);
898 }
899
900 if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
901 {
Simon Kelley849a8352006-06-09 21:02:31 +0100902#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley7de060b2011-08-26 17:24:52 +0100903 source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
Simon Kelley849a8352006-06-09 21:02:31 +0100904#endif
Simon Kelley7de060b2011-08-26 17:24:52 +0100905 source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
906 source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
907 addr.in6.sin6_port = htons(NAMESERVER_PORT);
908 addr.in6.sin6_scope_id = scope_index;
909 source_addr.in6.sin6_addr = in6addr_any;
910 source_addr.in6.sin6_port = htons(daemon->query_port);
911 source_addr.in6.sin6_scope_id = 0;
912 }
913 else
914 continue;
Simon Kelley849a8352006-06-09 21:02:31 +0100915 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100916#else /* IPV6 */
Simon Kelley849a8352006-06-09 21:02:31 +0100917 else
918 continue;
Simon Kelley7de060b2011-08-26 17:24:52 +0100919#endif
920
Simon Kelley849a8352006-06-09 21:02:31 +0100921 if (old_servers)
922 {
923 serv = old_servers;
924 old_servers = old_servers->next;
925 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100926 else if (!(serv = whine_malloc(sizeof (struct server))))
Simon Kelley849a8352006-06-09 21:02:31 +0100927 continue;
928
929 /* this list is reverse ordered:
930 it gets reversed again in check_servers */
931 serv->next = new_servers;
932 new_servers = serv;
933 serv->addr = addr;
934 serv->source_addr = source_addr;
935 serv->domain = NULL;
Simon Kelley824af852008-02-12 20:43:05 +0000936 serv->interface[0] = 0;
Simon Kelley849a8352006-06-09 21:02:31 +0100937 serv->sfd = NULL;
938 serv->flags = SERV_FROM_RESOLV;
Simon Kelley824af852008-02-12 20:43:05 +0000939 serv->queries = serv->failed_queries = 0;
Simon Kelley849a8352006-06-09 21:02:31 +0100940 gotone = 1;
941 }
942
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000943 /* Free any memory not used. */
Simon Kelley849a8352006-06-09 21:02:31 +0100944 while (old_servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000945 {
946 struct server *tmp = old_servers->next;
947 free(old_servers);
948 old_servers = tmp;
949 }
950
Simon Kelley3be34542004-09-11 19:12:13 +0100951 daemon->servers = new_servers;
Simon Kelley849a8352006-06-09 21:02:31 +0100952 fclose(f);
953
954 return gotone;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000955}
956
957
Simon Kelleyf2621c72007-04-29 19:47:21 +0100958/* Use an IPv4 listener socket for ioctling */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100959struct in_addr get_ifaddr(char *intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100960{
961 struct listener *l;
962 struct ifreq ifr;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100963 struct sockaddr_in ret;
964
965 ret.sin_addr.s_addr = -1;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000966
Simon Kelley28866e92011-02-14 20:19:14 +0000967 for (l = daemon->listeners;
968 l && (l->family != AF_INET || l->fd == -1);
969 l = l->next);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100970
971 strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
972 ifr.ifr_addr.sa_family = AF_INET;
973
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100974 if (l && ioctl(l->fd, SIOCGIFADDR, &ifr) != -1)
975 memcpy(&ret, &ifr.ifr_addr, sizeof(ret));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100976
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100977 return ret.sin_addr;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100978}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000979
980
981