blob: 8ee9907d2f7d8cf6f2201fad025493ac26301db2 [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 {
120#ifdef HAVE_DHCP
121 struct dhcp_context *range;
122#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100123
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100124 ret = 0;
125
126#ifdef HAVE_DHCP
127 for (range = daemon->dhcp; range; range = range->next)
128 if (range->interface && strcmp(range->interface, name) == 0)
129 ret = 1;
130#endif
131
132 for (tmp = daemon->if_names; tmp; tmp = tmp->next)
133 if (tmp->name && (strcmp(tmp->name, name) == 0))
134 ret = tmp->used = 1;
135
136 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000137 if (tmp->addr.sa.sa_family == family)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100138 {
139 if (family == AF_INET &&
140 tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
141 ret = tmp->used = 1;
142#ifdef HAVE_IPV6
143 else if (family == AF_INET6 &&
144 IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
145 &addr->addr.addr6))
146 ret = tmp->used = 1;
147#endif
148 }
149 }
150
151 for (tmp = daemon->if_except; tmp; tmp = tmp->next)
152 if (tmp->name && (strcmp(tmp->name, name) == 0))
153 ret = 0;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000154
Simon Kelley309331f2006-04-22 15:05:01 +0100155 return ret;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100156}
157
Simon Kelley5aabfc72007-08-29 11:24:47 +0100158static int iface_allowed(struct irec **irecp, int if_index,
Simon Kelley74c95c22011-10-19 09:33:39 +0100159 union mysockaddr *addr, struct in_addr netmask, int dad)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100160{
161 struct irec *iface;
Simon Kelley1f15b812009-10-13 17:49:32 +0100162 int fd, mtu = 0, loopback;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100163 struct ifreq ifr;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100164 int tftp_ok = daemon->tftp_unlimited;
Simon Kelley9380ba72012-04-16 14:41:56 +0100165 int dhcp_ok = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100166#ifdef HAVE_DHCP
Simon Kelley832af0b2007-01-21 20:01:28 +0000167 struct iname *tmp;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100168#endif
169 struct interface_list *ir = NULL;
170
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100171 /* check whether the interface IP has been added already
172 we call this routine multiple times. */
173 for (iface = *irecp; iface; iface = iface->next)
174 if (sockaddr_isequal(&iface->addr, addr))
Simon Kelley74c95c22011-10-19 09:33:39 +0100175 {
176 iface->dad = dad;
177 return 1;
178 }
179
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100180 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
Simon Kelley7622fc02009-06-04 20:32:05 +0100181 !indextoname(fd, if_index, ifr.ifr_name) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100182 ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
183 {
184 if (fd != -1)
185 {
186 int errsave = errno;
187 close(fd);
188 errno = errsave;
189 }
190 return 0;
191 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100192
193 loopback = ifr.ifr_flags & IFF_LOOPBACK;
Simon Kelley9380ba72012-04-16 14:41:56 +0100194
195 if (loopback)
196 dhcp_ok = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100197
198 if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
199 mtu = ifr.ifr_mtu;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100200
201 close(fd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000202
Simon Kelley59353a62004-11-21 19:34:28 +0000203 /* If we are restricting the set of interfaces to use, make
204 sure that loopback interfaces are in that set. */
Simon Kelley1f15b812009-10-13 17:49:32 +0100205 if (daemon->if_names && loopback)
Simon Kelley59353a62004-11-21 19:34:28 +0000206 {
207 struct iname *lo;
208 for (lo = daemon->if_names; lo; lo = lo->next)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100209 if (lo->name && strcmp(lo->name, ifr.ifr_name) == 0)
Simon Kelley59353a62004-11-21 19:34:28 +0000210 {
211 lo->isloop = 1;
212 break;
213 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100214
Simon Kelley5aabfc72007-08-29 11:24:47 +0100215 if (!lo &&
216 (lo = whine_malloc(sizeof(struct iname))) &&
217 (lo->name = whine_malloc(strlen(ifr.ifr_name)+1)))
Simon Kelley59353a62004-11-21 19:34:28 +0000218 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100219 strcpy(lo->name, ifr.ifr_name);
Simon Kelley59353a62004-11-21 19:34:28 +0000220 lo->isloop = lo->used = 1;
221 lo->next = daemon->if_names;
222 daemon->if_names = lo;
223 }
224 }
225
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100226#ifdef HAVE_TFTP
227 /* implement wierd TFTP service rules */
Simon Kelley28866e92011-02-14 20:19:14 +0000228 for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
229 if (strcmp(ir->interface, ifr.ifr_name) == 0)
230 {
231 tftp_ok = 1;
232 break;
233 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100234#endif
Simon Kelley28866e92011-02-14 20:19:14 +0000235
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100236 if (!ir)
237 {
238 if (addr->sa.sa_family == AF_INET &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000239 !iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100240 return 1;
241
242#ifdef HAVE_DHCP
243 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
244 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
Simon Kelley9380ba72012-04-16 14:41:56 +0100245 {
246 tftp_ok = 0;
247 dhcp_ok = 0;
248 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100249#endif
250
251#ifdef HAVE_IPV6
252 if (addr->sa.sa_family == AF_INET6 &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000253 !iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100254 return 1;
255#endif
256 }
257
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100258 /* add to list */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100259 if ((iface = whine_malloc(sizeof(struct irec))))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100260 {
261 iface->addr = *addr;
262 iface->netmask = netmask;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100263 iface->tftp_ok = tftp_ok;
Simon Kelley9380ba72012-04-16 14:41:56 +0100264 iface->dhcp_ok = dhcp_ok;
Simon Kelley1f15b812009-10-13 17:49:32 +0100265 iface->mtu = mtu;
Simon Kelley74c95c22011-10-19 09:33:39 +0100266 iface->dad = dad;
267 iface->done = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100268 if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
Simon Kelley6f13e532012-04-17 14:25:06 +0100269 {
270 strcpy(iface->name, ifr.ifr_name);
271 iface->next = *irecp;
272 *irecp = iface;
273 return 1;
274 }
275 free(iface);
Simon Kelley44a2a312004-03-10 20:04:35 +0000276 }
277
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100278 errno = ENOMEM;
279 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000280}
281
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100282#ifdef HAVE_IPV6
Simon Kelleyc72daea2012-01-05 21:33:27 +0000283static int iface_allowed_v6(struct in6_addr *local, int prefix,
Simon Kelley74c95c22011-10-19 09:33:39 +0100284 int scope, int if_index, int dad, void *vparam)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000285{
Simon Kelley59353a62004-11-21 19:34:28 +0000286 union mysockaddr addr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100287 struct in_addr netmask; /* dummy */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100288 netmask.s_addr = 0;
Simon Kelley52b92f42012-01-22 16:05:15 +0000289
290 (void)prefix; /* warning */
291 (void)scope; /* warning */
Simon Kelley44a2a312004-03-10 20:04:35 +0000292
Simon Kelley849a8352006-06-09 21:02:31 +0100293 memset(&addr, 0, sizeof(addr));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000294#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100295 addr.in6.sin6_len = sizeof(addr.in6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000296#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100297 addr.in6.sin6_family = AF_INET6;
298 addr.in6.sin6_addr = *local;
299 addr.in6.sin6_port = htons(daemon->port);
Simon Kelley52b92f42012-01-22 16:05:15 +0000300 addr.in6.sin6_scope_id = if_index;
Simon Kelley849a8352006-06-09 21:02:31 +0100301
Simon Kelley74c95c22011-10-19 09:33:39 +0100302 return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, dad);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100303}
304#endif
Simon Kelley59353a62004-11-21 19:34:28 +0000305
Simon Kelley5aabfc72007-08-29 11:24:47 +0100306static int iface_allowed_v4(struct in_addr local, int if_index,
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100307 struct in_addr netmask, struct in_addr broadcast, void *vparam)
308{
309 union mysockaddr addr;
Simon Kelley849a8352006-06-09 21:02:31 +0100310
311 memset(&addr, 0, sizeof(addr));
Simon Kelley1ab84e22004-01-29 16:48:35 +0000312#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100313 addr.in.sin_len = sizeof(addr.in);
Simon Kelley1ab84e22004-01-29 16:48:35 +0000314#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100315 addr.in.sin_family = AF_INET;
316 addr.in.sin_addr = broadcast; /* warning */
317 addr.in.sin_addr = local;
318 addr.in.sin_port = htons(daemon->port);
Simon Kelley44a2a312004-03-10 20:04:35 +0000319
Simon Kelley74c95c22011-10-19 09:33:39 +0100320 return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100321}
322
Simon Kelley5aabfc72007-08-29 11:24:47 +0100323int enumerate_interfaces(void)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100324{
325#ifdef HAVE_IPV6
Simon Kelley28866e92011-02-14 20:19:14 +0000326 if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))
327 return 0;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100328#endif
Simon Kelley28866e92011-02-14 20:19:14 +0000329
330 return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4);
Simon Kelley44a2a312004-03-10 20:04:35 +0000331}
332
Simon Kelley5aabfc72007-08-29 11:24:47 +0100333/* set NONBLOCK bit on fd: See Stevens 16.6 */
Simon Kelley7cebd202006-05-06 14:13:33 +0100334int fix_fd(int fd)
335{
336 int flags;
337
338 if ((flags = fcntl(fd, F_GETFL)) == -1 ||
Simon Kelley5aabfc72007-08-29 11:24:47 +0100339 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
Simon Kelley7cebd202006-05-06 14:13:33 +0100340 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100341
Simon Kelley7cebd202006-05-06 14:13:33 +0100342 return 1;
343}
344
Simon Kelley74c95c22011-10-19 09:33:39 +0100345static int make_sock(union mysockaddr *addr, int type, int dienow)
Simon Kelley44a2a312004-03-10 20:04:35 +0000346{
Simon Kelley28866e92011-02-14 20:19:14 +0000347 int family = addr->sa.sa_family;
348 int fd, rc, opt = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100349
Simon Kelley28866e92011-02-14 20:19:14 +0000350 if ((fd = socket(family, type, 0)) == -1)
Simon Kelley316e2732010-01-22 20:16:09 +0000351 {
Simon Kelley28866e92011-02-14 20:19:14 +0000352 int port;
353
354 /* No error if the kernel just doesn't support this IP flavour */
355 if (errno == EPROTONOSUPPORT ||
356 errno == EAFNOSUPPORT ||
357 errno == EINVAL)
358 return -1;
359
360 err:
Simon Kelley74c95c22011-10-19 09:33:39 +0100361 if (dienow)
362 {
363 port = prettyprint_addr(addr, daemon->namebuff);
364 if (!option_bool(OPT_NOWILD))
365 sprintf(daemon->namebuff, "port %d", port);
366 die(_("failed to create listening socket for %s: %s"),
367 daemon->namebuff, EC_BADNET);
368
369 }
370 return -1;
Simon Kelley28866e92011-02-14 20:19:14 +0000371 }
372
373 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
374 goto err;
375
376#ifdef HAVE_IPV6
Simon Kelleyc72daea2012-01-05 21:33:27 +0000377 if (family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000378 goto err;
379#endif
380
Simon Kelley74c95c22011-10-19 09:33:39 +0100381 if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000382 goto err;
383
384 if (type == SOCK_STREAM)
385 {
386 if (listen(fd, 5) == -1)
387 goto err;
388 }
389 else if (!option_bool(OPT_NOWILD))
390 {
391 if (family == AF_INET)
392 {
393#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000394 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000395 goto err;
396#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
397 if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
398 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1)
399 goto err;
400#endif
401 }
402#ifdef HAVE_IPV6
Simon Kelleyc72daea2012-01-05 21:33:27 +0000403 else if (!set_ipv6pktinfo(fd))
404 goto err;
Simon Kelley316e2732010-01-22 20:16:09 +0000405#endif
Simon Kelley28866e92011-02-14 20:19:14 +0000406 }
Simon Kelleyc72daea2012-01-05 21:33:27 +0000407
Simon Kelley28866e92011-02-14 20:19:14 +0000408 return fd;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100409}
Simon Kelleyc72daea2012-01-05 21:33:27 +0000410
411#ifdef HAVE_IPV6
412int set_ipv6pktinfo(int fd)
413{
414 int opt = 1;
415
416 /* The API changed around Linux 2.6.14 but the old ABI is still supported:
417 handle all combinations of headers and kernel.
418 OpenWrt note that this fixes the problem addressed by your very broken patch. */
419 daemon->v6pktinfo = IPV6_PKTINFO;
420
421#ifdef IPV6_RECVPKTINFO
422 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)) != -1)
423 return 1;
424# ifdef IPV6_2292PKTINFO
425 else if (errno == ENOPROTOOPT && setsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
426 {
427 daemon->v6pktinfo = IPV6_2292PKTINFO;
428 return 1;
429 }
430# endif
431#else
432 if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &opt, sizeof(opt)) != -1)
433 return 1;
434#endif
435
436 return 0;
437}
438#endif
Simon Kelley28866e92011-02-14 20:19:14 +0000439
Simon Kelley74c95c22011-10-19 09:33:39 +0100440static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
Simon Kelley28866e92011-02-14 20:19:14 +0000441{
442 struct listener *l = NULL;
443 int fd = -1, tcpfd = -1, tftpfd = -1;
444
445 if (daemon->port != 0)
446 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100447 fd = make_sock(addr, SOCK_DGRAM, dienow);
448 tcpfd = make_sock(addr, SOCK_STREAM, dienow);
Simon Kelley28866e92011-02-14 20:19:14 +0000449 }
450
451#ifdef HAVE_TFTP
452 if (do_tftp)
453 {
454 if (addr->sa.sa_family == AF_INET)
455 {
456 /* port must be restored to DNS port for TCP code */
457 short save = addr->in.sin_port;
458 addr->in.sin_port = htons(TFTP_PORT);
Simon Kelley74c95c22011-10-19 09:33:39 +0100459 tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
Simon Kelley28866e92011-02-14 20:19:14 +0000460 addr->in.sin_port = save;
461 }
462# ifdef HAVE_IPV6
463 else
464 {
465 short save = addr->in6.sin6_port;
466 addr->in6.sin6_port = htons(TFTP_PORT);
Simon Kelley74c95c22011-10-19 09:33:39 +0100467 tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
Simon Kelley28866e92011-02-14 20:19:14 +0000468 addr->in6.sin6_port = save;
469 }
470# endif
471 }
Simon Kelley44a2a312004-03-10 20:04:35 +0000472#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100473
Simon Kelley28866e92011-02-14 20:19:14 +0000474 if (fd != -1 || tcpfd != -1 || tftpfd != -1)
475 {
476 l = safe_malloc(sizeof(struct listener));
477 l->next = NULL;
478 l->family = addr->sa.sa_family;
479 l->fd = fd;
480 l->tcpfd = tcpfd;
481 l->tftpfd = tftpfd;
482 }
483
484 return l;
485}
486
Simon Kelley74c95c22011-10-19 09:33:39 +0100487void create_wildcard_listeners(void)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100488{
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100489 union mysockaddr addr;
Simon Kelley28866e92011-02-14 20:19:14 +0000490 struct listener *l;
491 int tftp_enabled = daemon->tftp_unlimited || daemon->tftp_interfaces;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100492
Simon Kelley849a8352006-06-09 21:02:31 +0100493 memset(&addr, 0, sizeof(addr));
Simon Kelley28866e92011-02-14 20:19:14 +0000494#ifdef HAVE_SOCKADDR_SA_LEN
495 addr.in.sin_len = sizeof(addr.in);
496#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100497 addr.in.sin_family = AF_INET;
498 addr.in.sin_addr.s_addr = INADDR_ANY;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100499 addr.in.sin_port = htons(daemon->port);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100500
Simon Kelley74c95c22011-10-19 09:33:39 +0100501 l = create_listeners(&addr, tftp_enabled, 1);
Simon Kelley28866e92011-02-14 20:19:14 +0000502
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100503#ifdef HAVE_IPV6
Simon Kelley28866e92011-02-14 20:19:14 +0000504 memset(&addr, 0, sizeof(addr));
505# ifdef HAVE_SOCKADDR_SA_LEN
506 addr.in6.sin6_len = sizeof(addr.in6);
507# endif
508 addr.in6.sin6_family = AF_INET6;
509 addr.in6.sin6_addr = in6addr_any;
510 addr.in6.sin6_port = htons(daemon->port);
Simon Kelley824af852008-02-12 20:43:05 +0000511
Simon Kelley28866e92011-02-14 20:19:14 +0000512 if (l)
Simon Kelley74c95c22011-10-19 09:33:39 +0100513 l->next = create_listeners(&addr, tftp_enabled, 1);
Simon Kelley28866e92011-02-14 20:19:14 +0000514 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100515 l = create_listeners(&addr, tftp_enabled, 1);
Simon Kelley832af0b2007-01-21 20:01:28 +0000516#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100517
Simon Kelley74c95c22011-10-19 09:33:39 +0100518 daemon->listeners = l;
Simon Kelley44a2a312004-03-10 20:04:35 +0000519}
520
Simon Kelley74c95c22011-10-19 09:33:39 +0100521void create_bound_listeners(int dienow)
Simon Kelley44a2a312004-03-10 20:04:35 +0000522{
Simon Kelley74c95c22011-10-19 09:33:39 +0100523 struct listener *new;
Simon Kelley44a2a312004-03-10 20:04:35 +0000524 struct irec *iface;
Simon Kelley52d4abf2012-03-21 21:39:48 +0000525 struct iname *if_tmp;
Simon Kelley73a08a22009-02-05 20:28:08 +0000526
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100527 for (iface = daemon->interfaces; iface; iface = iface->next)
Simon Kelley74c95c22011-10-19 09:33:39 +0100528 if (!iface->done && !iface->dad &&
529 (new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
Simon Kelley28866e92011-02-14 20:19:14 +0000530 {
531 new->iface = iface;
Simon Kelley74c95c22011-10-19 09:33:39 +0100532 new->next = daemon->listeners;
533 daemon->listeners = new;
534 iface->done = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000535 }
Simon Kelley52d4abf2012-03-21 21:39:48 +0000536
537 /* Check for --listen-address options that haven't been used because there's
538 no interface with a matching address. These may be valid: eg it's possible
539 to listen on 127.0.1.1 even if the loopback interface is 127.0.0.1
540
541 If the address isn't valid the bind() will fail and we'll die().
542
543 The resulting listeners have the ->iface field NULL, and this has to be
544 handled by the DNS and TFTP code. It disables --localise-queries processing
545 (no netmask) and some MTU login the tftp code. */
546
547 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
548 if (!if_tmp->used &&
549 (new = create_listeners(&if_tmp->addr, 1, dienow)))
550 {
551 new->iface = NULL;
552 new->next = daemon->listeners;
553 daemon->listeners = new;
554 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000555}
556
Simon Kelley74c95c22011-10-19 09:33:39 +0100557int is_dad_listeners(void)
558{
559 struct irec *iface;
560
561 if (option_bool(OPT_NOWILD))
562 for (iface = daemon->interfaces; iface; iface = iface->next)
563 if (iface->dad && !iface->done)
564 return 1;
565
566 return 0;
567}
Simon Kelley9009d742008-11-14 20:04:27 +0000568/* return a UDP socket bound to a random port, have to cope with straying into
Simon Kelley1a6bca82008-07-11 11:11:42 +0100569 occupied port nos and reserved ones. */
570int random_sock(int family)
571{
572 int fd;
573
574 if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
575 {
Simon Kelley3927da42008-07-20 15:10:39 +0100576 union mysockaddr addr;
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100577 unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port;
Simon Kelley9009d742008-11-14 20:04:27 +0000578 int tries = ports_avail < 30 ? 3 * ports_avail : 100;
Simon Kelley3927da42008-07-20 15:10:39 +0100579
Simon Kelley1a6bca82008-07-11 11:11:42 +0100580 memset(&addr, 0, sizeof(addr));
Simon Kelley3927da42008-07-20 15:10:39 +0100581 addr.sa.sa_family = family;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100582
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100583 /* don't loop forever if all ports in use. */
584
Simon Kelley1a6bca82008-07-11 11:11:42 +0100585 if (fix_fd(fd))
Simon Kelley9009d742008-11-14 20:04:27 +0000586 while(tries--)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100587 {
588 unsigned short port = rand16();
589
Simon Kelley3927da42008-07-20 15:10:39 +0100590 if (daemon->min_port != 0)
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100591 port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
Simon Kelley1a6bca82008-07-11 11:11:42 +0100592
593 if (family == AF_INET)
594 {
595 addr.in.sin_addr.s_addr = INADDR_ANY;
Simon Kelley3927da42008-07-20 15:10:39 +0100596 addr.in.sin_port = port;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100597#ifdef HAVE_SOCKADDR_SA_LEN
598 addr.in.sin_len = sizeof(struct sockaddr_in);
599#endif
600 }
601#ifdef HAVE_IPV6
602 else
603 {
604 addr.in6.sin6_addr = in6addr_any;
Simon Kelley3927da42008-07-20 15:10:39 +0100605 addr.in6.sin6_port = port;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100606#ifdef HAVE_SOCKADDR_SA_LEN
607 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
608#endif
609 }
610#endif
611
612 if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)
613 return fd;
614
615 if (errno != EADDRINUSE && errno != EACCES)
616 break;
617 }
618
619 close(fd);
620 }
621
622 return -1;
623}
624
625
Simon Kelley824af852008-02-12 20:43:05 +0000626int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
627{
628 union mysockaddr addr_copy = *addr;
629
630 /* cannot set source _port_ for TCP connections. */
631 if (is_tcp)
632 {
633 if (addr_copy.sa.sa_family == AF_INET)
634 addr_copy.in.sin_port = 0;
635#ifdef HAVE_IPV6
636 else
637 addr_copy.in6.sin6_port = 0;
638#endif
639 }
640
641 if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
642 return 0;
643
644#if defined(SO_BINDTODEVICE)
Simon Kelley73a08a22009-02-05 20:28:08 +0000645 if (intname[0] != 0 &&
Simon Kelley316e2732010-01-22 20:16:09 +0000646 setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
Simon Kelley824af852008-02-12 20:43:05 +0000647 return 0;
648#endif
649
650 return 1;
651}
652
653static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000654{
655 struct serverfd *sfd;
Simon Kelley824af852008-02-12 20:43:05 +0000656 int errsave;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100657
Simon Kelley1a6bca82008-07-11 11:11:42 +0100658 /* when using random ports, servers which would otherwise use
659 the INADDR_ANY/port0 socket have sfd set to NULL */
Simon Kelley73a08a22009-02-05 20:28:08 +0000660 if (!daemon->osport && intname[0] == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100661 {
662 errno = 0;
663
664 if (addr->sa.sa_family == AF_INET &&
665 addr->in.sin_addr.s_addr == INADDR_ANY &&
666 addr->in.sin_port == htons(0))
667 return NULL;
668
669#ifdef HAVE_IPV6
670 if (addr->sa.sa_family == AF_INET6 &&
671 memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
672 addr->in6.sin6_port == htons(0))
673 return NULL;
674#endif
675 }
676
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000677 /* may have a suitable one already */
Simon Kelley824af852008-02-12 20:43:05 +0000678 for (sfd = daemon->sfds; sfd; sfd = sfd->next )
679 if (sockaddr_isequal(&sfd->source_addr, addr) &&
680 strcmp(intname, sfd->interface) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000681 return sfd;
682
683 /* need to make a new one. */
684 errno = ENOMEM; /* in case malloc fails. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100685 if (!(sfd = whine_malloc(sizeof(struct serverfd))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000686 return NULL;
687
688 if ((sfd->fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
689 {
690 free(sfd);
691 return NULL;
692 }
693
Simon Kelley824af852008-02-12 20:43:05 +0000694 if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd))
695 {
696 errsave = errno; /* save error from bind. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000697 close(sfd->fd);
698 free(sfd);
699 errno = errsave;
700 return NULL;
701 }
Simon Kelley824af852008-02-12 20:43:05 +0000702
703 strcpy(sfd->interface, intname);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000704 sfd->source_addr = *addr;
Simon Kelley824af852008-02-12 20:43:05 +0000705 sfd->next = daemon->sfds;
706 daemon->sfds = sfd;
707 return sfd;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000708}
709
Simon Kelley824af852008-02-12 20:43:05 +0000710/* create upstream sockets during startup, before root is dropped which may be needed
711 this allows query_port to be a low port and interface binding */
712void pre_allocate_sfds(void)
713{
714 struct server *srv;
715
716 if (daemon->query_port != 0)
717 {
718 union mysockaddr addr;
719 memset(&addr, 0, sizeof(addr));
720 addr.in.sin_family = AF_INET;
721 addr.in.sin_addr.s_addr = INADDR_ANY;
722 addr.in.sin_port = htons(daemon->query_port);
723#ifdef HAVE_SOCKADDR_SA_LEN
724 addr.in.sin_len = sizeof(struct sockaddr_in);
725#endif
726 allocate_sfd(&addr, "");
727#ifdef HAVE_IPV6
728 memset(&addr, 0, sizeof(addr));
729 addr.in6.sin6_family = AF_INET6;
730 addr.in6.sin6_addr = in6addr_any;
731 addr.in6.sin6_port = htons(daemon->query_port);
732#ifdef HAVE_SOCKADDR_SA_LEN
733 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
734#endif
735 allocate_sfd(&addr, "");
736#endif
737 }
738
739 for (srv = daemon->servers; srv; srv = srv->next)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100740 if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
Simon Kelley824af852008-02-12 20:43:05 +0000741 !allocate_sfd(&srv->source_addr, srv->interface) &&
Simon Kelley1a6bca82008-07-11 11:11:42 +0100742 errno != 0 &&
Simon Kelley28866e92011-02-14 20:19:14 +0000743 option_bool(OPT_NOWILD))
Simon Kelley824af852008-02-12 20:43:05 +0000744 {
Simon Kelley316e2732010-01-22 20:16:09 +0000745 prettyprint_addr(&srv->source_addr, daemon->namebuff);
Simon Kelley73a08a22009-02-05 20:28:08 +0000746 if (srv->interface[0] != 0)
Simon Kelley824af852008-02-12 20:43:05 +0000747 {
748 strcat(daemon->namebuff, " ");
749 strcat(daemon->namebuff, srv->interface);
750 }
751 die(_("failed to bind server socket for %s: %s"),
752 daemon->namebuff, EC_BADNET);
753 }
754}
755
756
Simon Kelley5aabfc72007-08-29 11:24:47 +0100757void check_servers(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000758{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000759 struct irec *iface;
Simon Kelley3be34542004-09-11 19:12:13 +0100760 struct server *new, *tmp, *ret = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000761 int port = 0;
762
Simon Kelley316e2732010-01-22 20:16:09 +0000763 /* interface may be new since startup */
Simon Kelley28866e92011-02-14 20:19:14 +0000764 if (!option_bool(OPT_NOWILD))
Simon Kelley316e2732010-01-22 20:16:09 +0000765 enumerate_interfaces();
766
Simon Kelley3be34542004-09-11 19:12:13 +0100767 for (new = daemon->servers; new; new = tmp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000768 {
769 tmp = new->next;
770
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100771 if (!(new->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000772 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100773 port = prettyprint_addr(&new->addr, daemon->namebuff);
774
Simon Kelley16972692006-10-16 20:04:18 +0100775 /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
776 if (new->addr.sa.sa_family == AF_INET &&
777 new->addr.in.sin_addr.s_addr == 0)
778 {
779 free(new);
780 continue;
781 }
782
Simon Kelley3d8df262005-08-29 12:19:27 +0100783 for (iface = daemon->interfaces; iface; iface = iface->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000784 if (sockaddr_isequal(&new->addr, &iface->addr))
785 break;
786 if (iface)
787 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100788 my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000789 free(new);
790 continue;
791 }
792
793 /* Do we need a socket set? */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100794 if (!new->sfd &&
795 !(new->sfd = allocate_sfd(&new->source_addr, new->interface)) &&
796 errno != 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000797 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100798 my_syslog(LOG_WARNING,
799 _("ignoring nameserver %s - cannot make/bind socket: %s"),
800 daemon->namebuff, strerror(errno));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000801 free(new);
802 continue;
803 }
804 }
805
806 /* reverse order - gets it right. */
807 new->next = ret;
808 ret = new;
809
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100810 if (!(new->flags & SERV_NO_REBIND))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000811 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100812 if (new->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
813 {
814 char *s1, *s2;
815 if (!(new->flags & SERV_HAS_DOMAIN))
816 s1 = _("unqualified"), s2 = _("names");
817 else if (strlen(new->domain) == 0)
818 s1 = _("default"), s2 = "";
819 else
820 s1 = _("domain"), s2 = new->domain;
821
822 if (new->flags & SERV_NO_ADDR)
823 my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
824 else if (new->flags & SERV_USE_RESOLV)
825 my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
826 else if (!(new->flags & SERV_LITERAL_ADDRESS))
827 my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
828 }
829 else if (new->interface[0] != 0)
830 my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, new->interface);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000831 else
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100832 my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000833 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000834 }
835
Simon Kelley3be34542004-09-11 19:12:13 +0100836 daemon->servers = ret;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000837}
Simon Kelley849a8352006-06-09 21:02:31 +0100838
839/* Return zero if no servers found, in that case we keep polling.
840 This is a protection against an update-time/write race on resolv.conf */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100841int reload_servers(char *fname)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000842{
843 FILE *f;
844 char *line;
845 struct server *old_servers = NULL;
846 struct server *new_servers = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +0100847 struct server *serv;
848 int gotone = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000849
Simon Kelley849a8352006-06-09 21:02:31 +0100850 /* buff happens to be MAXDNAME long... */
851 if (!(f = fopen(fname, "r")))
852 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100853 my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));
Simon Kelley849a8352006-06-09 21:02:31 +0100854 return 0;
855 }
856
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000857 /* move old servers to free list - we can reuse the memory
858 and not risk malloc if there are the same or fewer new servers.
859 Servers which were specced on the command line go to the new list. */
Simon Kelley849a8352006-06-09 21:02:31 +0100860 for (serv = daemon->servers; serv;)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000861 {
862 struct server *tmp = serv->next;
863 if (serv->flags & SERV_FROM_RESOLV)
864 {
865 serv->next = old_servers;
Simon Kelley849a8352006-06-09 21:02:31 +0100866 old_servers = serv;
867 /* forward table rules reference servers, so have to blow them away */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100868 server_gone(serv);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000869 }
870 else
871 {
872 serv->next = new_servers;
873 new_servers = serv;
874 }
875 serv = tmp;
876 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000877
Simon Kelley849a8352006-06-09 21:02:31 +0100878 while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
879 {
880 union mysockaddr addr, source_addr;
881 char *token = strtok(line, " \t\n\r");
882
Simon Kelley5aabfc72007-08-29 11:24:47 +0100883 if (!token)
884 continue;
885 if (strcmp(token, "nameserver") != 0 && strcmp(token, "server") != 0)
Simon Kelley849a8352006-06-09 21:02:31 +0100886 continue;
887 if (!(token = strtok(NULL, " \t\n\r")))
888 continue;
889
890 memset(&addr, 0, sizeof(addr));
891 memset(&source_addr, 0, sizeof(source_addr));
892
893 if ((addr.in.sin_addr.s_addr = inet_addr(token)) != (in_addr_t) -1)
894 {
895#ifdef HAVE_SOCKADDR_SA_LEN
896 source_addr.in.sin_len = addr.in.sin_len = sizeof(source_addr.in);
897#endif
898 source_addr.in.sin_family = addr.in.sin_family = AF_INET;
899 addr.in.sin_port = htons(NAMESERVER_PORT);
900 source_addr.in.sin_addr.s_addr = INADDR_ANY;
901 source_addr.in.sin_port = htons(daemon->query_port);
902 }
903#ifdef HAVE_IPV6
Simon Kelley7de060b2011-08-26 17:24:52 +0100904 else
905 {
906 int scope_index = 0;
907 char *scope_id = strchr(token, '%');
908
909 if (scope_id)
910 {
911 *(scope_id++) = 0;
912 scope_index = if_nametoindex(scope_id);
913 }
914
915 if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
916 {
Simon Kelley849a8352006-06-09 21:02:31 +0100917#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley7de060b2011-08-26 17:24:52 +0100918 source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
Simon Kelley849a8352006-06-09 21:02:31 +0100919#endif
Simon Kelley7de060b2011-08-26 17:24:52 +0100920 source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
921 source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
922 addr.in6.sin6_port = htons(NAMESERVER_PORT);
923 addr.in6.sin6_scope_id = scope_index;
924 source_addr.in6.sin6_addr = in6addr_any;
925 source_addr.in6.sin6_port = htons(daemon->query_port);
926 source_addr.in6.sin6_scope_id = 0;
927 }
928 else
929 continue;
Simon Kelley849a8352006-06-09 21:02:31 +0100930 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100931#else /* IPV6 */
Simon Kelley849a8352006-06-09 21:02:31 +0100932 else
933 continue;
Simon Kelley7de060b2011-08-26 17:24:52 +0100934#endif
935
Simon Kelley849a8352006-06-09 21:02:31 +0100936 if (old_servers)
937 {
938 serv = old_servers;
939 old_servers = old_servers->next;
940 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100941 else if (!(serv = whine_malloc(sizeof (struct server))))
Simon Kelley849a8352006-06-09 21:02:31 +0100942 continue;
943
944 /* this list is reverse ordered:
945 it gets reversed again in check_servers */
946 serv->next = new_servers;
947 new_servers = serv;
948 serv->addr = addr;
949 serv->source_addr = source_addr;
950 serv->domain = NULL;
Simon Kelley824af852008-02-12 20:43:05 +0000951 serv->interface[0] = 0;
Simon Kelley849a8352006-06-09 21:02:31 +0100952 serv->sfd = NULL;
953 serv->flags = SERV_FROM_RESOLV;
Simon Kelley824af852008-02-12 20:43:05 +0000954 serv->queries = serv->failed_queries = 0;
Simon Kelley849a8352006-06-09 21:02:31 +0100955 gotone = 1;
956 }
957
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000958 /* Free any memory not used. */
Simon Kelley849a8352006-06-09 21:02:31 +0100959 while (old_servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000960 {
961 struct server *tmp = old_servers->next;
962 free(old_servers);
963 old_servers = tmp;
964 }
965
Simon Kelley3be34542004-09-11 19:12:13 +0100966 daemon->servers = new_servers;
Simon Kelley849a8352006-06-09 21:02:31 +0100967 fclose(f);
968
969 return gotone;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000970}
971
972
Simon Kelleyf2621c72007-04-29 19:47:21 +0100973/* Use an IPv4 listener socket for ioctling */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100974struct in_addr get_ifaddr(char *intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100975{
976 struct listener *l;
977 struct ifreq ifr;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100978 struct sockaddr_in ret;
979
980 ret.sin_addr.s_addr = -1;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000981
Simon Kelley28866e92011-02-14 20:19:14 +0000982 for (l = daemon->listeners;
983 l && (l->family != AF_INET || l->fd == -1);
984 l = l->next);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100985
986 strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
987 ifr.ifr_addr.sa_family = AF_INET;
988
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100989 if (l && ioctl(l->fd, SIOCGIFADDR, &ifr) != -1)
990 memcpy(&ret, &ifr.ifr_addr, sizeof(ret));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100991
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100992 return ret.sin_addr;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100993}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000994
995
996