blob: 792914bb935b609078cc8874e2f20e7d74183105 [file] [log] [blame]
Simon Kelley61744352013-01-31 14:34:40 +00001/* dnsmasq is Copyright (c) 2000-2013 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 Kelley4f7b3042012-11-28 21:27:02 +0000110int iface_check(int family, struct all_addr *addr, char *name, int *auth)
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 Kelley429798f2012-12-10 20:45:53 +0000117
Simon Kelley4f7b3042012-11-28 21:27:02 +0000118 if (auth)
Simon Kelley429798f2012-12-10 20:45:53 +0000119 *auth = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100120
Simon Kelleyc72daea2012-01-05 21:33:27 +0000121 if (daemon->if_names || daemon->if_addrs)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100122 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100123 ret = 0;
124
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100125 for (tmp = daemon->if_names; tmp; tmp = tmp->next)
Simon Kelley49333cb2013-03-15 20:30:51 +0000126 if (tmp->name && wildcard_match(tmp->name, name))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100127 ret = tmp->used = 1;
128
Simon Kelley429798f2012-12-10 20:45:53 +0000129 if (addr)
130 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
131 if (tmp->addr.sa.sa_family == family)
132 {
133 if (family == AF_INET &&
134 tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
135 ret = tmp->used = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100136#ifdef HAVE_IPV6
Simon Kelley429798f2012-12-10 20:45:53 +0000137 else if (family == AF_INET6 &&
138 IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
139 &addr->addr.addr6))
140 ret = tmp->used = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100141#endif
Simon Kelley429798f2012-12-10 20:45:53 +0000142 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100143 }
144
145 for (tmp = daemon->if_except; tmp; tmp = tmp->next)
Simon Kelley49333cb2013-03-15 20:30:51 +0000146 if (tmp->name && wildcard_match(tmp->name, name))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100147 ret = 0;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000148
Simon Kelley429798f2012-12-10 20:45:53 +0000149
150 for (tmp = daemon->authinterface; tmp; tmp = tmp->next)
151 if (tmp->name)
152 {
153 if (strcmp(tmp->name, name) == 0)
154 break;
155 }
156 else if (addr && tmp->addr.sa.sa_family == AF_INET && family == AF_INET &&
157 tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
158 break;
159#ifdef HAVE_IPV6
160 else if (addr && tmp->addr.sa.sa_family == AF_INET6 && family == AF_INET6 &&
161 IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, &addr->addr.addr6))
162 break;
163#endif
164
165 if (tmp && auth)
166 {
167 *auth = 1;
168 ret = 1;
169 }
170
Simon Kelley309331f2006-04-22 15:05:01 +0100171 return ret;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100172}
Simon Kelleye25db1f2013-01-29 22:10:26 +0000173
174
175/* Fix for problem that the kernel sometimes reports the loopback inerface as the
176 arrival interface when a packet originates locally, even when sent to address of
177 an interface other than the loopback. Accept packet if it arrived via a loopback
178 interface, even when we're not accepting packets that way, as long as the destination
179 address is one we're believing. Interface list must be up-to-date before calling. */
180int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
181{
182 struct ifreq ifr;
183 struct irec *iface;
184
185 strncpy(ifr.ifr_name, name, IF_NAMESIZE);
186 if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&
187 ifr.ifr_flags & IFF_LOOPBACK)
188 {
189 for (iface = daemon->interfaces; iface; iface = iface->next)
190 if (iface->addr.sa.sa_family == family)
191 {
192 if (family == AF_INET)
193 {
194 if (iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
195 return 1;
196 }
197#ifdef HAVE_IPV6
198 else if (IN6_ARE_ADDR_EQUAL(&iface->addr.in6.sin6_addr, &addr->addr.addr6))
199 return 1;
200#endif
201
202 }
203 }
204 return 0;
205}
206
Simon Kelley5aabfc72007-08-29 11:24:47 +0100207static int iface_allowed(struct irec **irecp, int if_index,
Simon Kelley74c95c22011-10-19 09:33:39 +0100208 union mysockaddr *addr, struct in_addr netmask, int dad)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100209{
210 struct irec *iface;
Simon Kelley1f15b812009-10-13 17:49:32 +0100211 int fd, mtu = 0, loopback;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100212 struct ifreq ifr;
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100213 int tftp_ok = !!option_bool(OPT_TFTP);
Simon Kelley9380ba72012-04-16 14:41:56 +0100214 int dhcp_ok = 1;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000215 int auth_dns = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100216#ifdef HAVE_DHCP
Simon Kelley832af0b2007-01-21 20:01:28 +0000217 struct iname *tmp;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100218#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100219
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100220 /* check whether the interface IP has been added already
221 we call this routine multiple times. */
222 for (iface = *irecp; iface; iface = iface->next)
223 if (sockaddr_isequal(&iface->addr, addr))
Simon Kelley74c95c22011-10-19 09:33:39 +0100224 {
225 iface->dad = dad;
226 return 1;
227 }
228
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100229 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
Simon Kelley7622fc02009-06-04 20:32:05 +0100230 !indextoname(fd, if_index, ifr.ifr_name) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100231 ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
232 {
233 if (fd != -1)
234 {
235 int errsave = errno;
236 close(fd);
237 errno = errsave;
238 }
239 return 0;
240 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100241
242 loopback = ifr.ifr_flags & IFF_LOOPBACK;
Simon Kelley9380ba72012-04-16 14:41:56 +0100243
244 if (loopback)
245 dhcp_ok = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100246
247 if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
248 mtu = ifr.ifr_mtu;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100249
250 close(fd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000251
Simon Kelley59353a62004-11-21 19:34:28 +0000252 /* If we are restricting the set of interfaces to use, make
253 sure that loopback interfaces are in that set. */
Simon Kelley1f15b812009-10-13 17:49:32 +0100254 if (daemon->if_names && loopback)
Simon Kelley59353a62004-11-21 19:34:28 +0000255 {
256 struct iname *lo;
257 for (lo = daemon->if_names; lo; lo = lo->next)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100258 if (lo->name && strcmp(lo->name, ifr.ifr_name) == 0)
Simon Kelley4ce4f372012-06-14 11:50:45 +0100259 break;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100260
Simon Kelley38365ff2013-02-05 14:35:54 +0000261 if (!lo && (lo = whine_malloc(sizeof(struct iname))))
Simon Kelley59353a62004-11-21 19:34:28 +0000262 {
Simon Kelley38365ff2013-02-05 14:35:54 +0000263 if ((lo->name = whine_malloc(strlen(ifr.ifr_name)+1)))
264 {
265 strcpy(lo->name, ifr.ifr_name);
266 lo->used = 1;
267 lo->next = daemon->if_names;
268 daemon->if_names = lo;
269 }
270 else
271 free(lo);
Simon Kelley59353a62004-11-21 19:34:28 +0000272 }
273 }
274
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100275 if (addr->sa.sa_family == AF_INET &&
Simon Kelley4f7b3042012-11-28 21:27:02 +0000276 !iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, &auth_dns))
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100277 return 1;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000278
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100279#ifdef HAVE_IPV6
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100280 if (addr->sa.sa_family == AF_INET6 &&
Simon Kelley4f7b3042012-11-28 21:27:02 +0000281 !iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, &auth_dns))
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100282 return 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100283#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +0000284
285#ifdef HAVE_DHCP
286 /* No DHCP where we're doing auth DNS. */
287 if (auth_dns)
288 {
289 tftp_ok = 0;
290 dhcp_ok = 0;
291 }
292 else
293 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
Simon Kelley49333cb2013-03-15 20:30:51 +0000294 if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
Simon Kelley4f7b3042012-11-28 21:27:02 +0000295 {
296 tftp_ok = 0;
297 dhcp_ok = 0;
298 }
299#endif
300
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100301 /* add to list */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100302 if ((iface = whine_malloc(sizeof(struct irec))))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100303 {
304 iface->addr = *addr;
305 iface->netmask = netmask;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100306 iface->tftp_ok = tftp_ok;
Simon Kelley9380ba72012-04-16 14:41:56 +0100307 iface->dhcp_ok = dhcp_ok;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000308 iface->dns_auth = auth_dns;
Simon Kelley1f15b812009-10-13 17:49:32 +0100309 iface->mtu = mtu;
Simon Kelley74c95c22011-10-19 09:33:39 +0100310 iface->dad = dad;
Simon Kelley5d162f22012-12-20 14:55:46 +0000311 iface->done = iface->multicast_done = 0;
312 iface->index = if_index;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100313 if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
Simon Kelley6f13e532012-04-17 14:25:06 +0100314 {
315 strcpy(iface->name, ifr.ifr_name);
316 iface->next = *irecp;
317 *irecp = iface;
318 return 1;
319 }
320 free(iface);
Simon Kelley5d162f22012-12-20 14:55:46 +0000321
Simon Kelley44a2a312004-03-10 20:04:35 +0000322 }
323
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100324 errno = ENOMEM;
325 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000326}
327
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100328#ifdef HAVE_IPV6
Simon Kelleyc72daea2012-01-05 21:33:27 +0000329static int iface_allowed_v6(struct in6_addr *local, int prefix,
Simon Kelleybad7b872012-12-20 22:00:39 +0000330 int scope, int if_index, int flags,
Simon Kelley1f776932012-12-16 19:46:08 +0000331 int preferred, int valid, void *vparam)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000332{
Simon Kelley59353a62004-11-21 19:34:28 +0000333 union mysockaddr addr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100334 struct in_addr netmask; /* dummy */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100335 netmask.s_addr = 0;
Simon Kelley52b92f42012-01-22 16:05:15 +0000336
337 (void)prefix; /* warning */
338 (void)scope; /* warning */
Simon Kelley1f776932012-12-16 19:46:08 +0000339 (void)preferred;
340 (void)valid;
Simon Kelley44a2a312004-03-10 20:04:35 +0000341
Simon Kelley849a8352006-06-09 21:02:31 +0100342 memset(&addr, 0, sizeof(addr));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000343#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100344 addr.in6.sin6_len = sizeof(addr.in6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000345#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100346 addr.in6.sin6_family = AF_INET6;
347 addr.in6.sin6_addr = *local;
348 addr.in6.sin6_port = htons(daemon->port);
Simon Kelley52b92f42012-01-22 16:05:15 +0000349 addr.in6.sin6_scope_id = if_index;
Simon Kelley849a8352006-06-09 21:02:31 +0100350
Simon Kelleybad7b872012-12-20 22:00:39 +0000351 return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, !!(flags & IFACE_TENTATIVE));
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100352}
353#endif
Simon Kelley59353a62004-11-21 19:34:28 +0000354
Simon Kelley5aabfc72007-08-29 11:24:47 +0100355static int iface_allowed_v4(struct in_addr local, int if_index,
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100356 struct in_addr netmask, struct in_addr broadcast, void *vparam)
357{
358 union mysockaddr addr;
Simon Kelley849a8352006-06-09 21:02:31 +0100359
360 memset(&addr, 0, sizeof(addr));
Simon Kelley1ab84e22004-01-29 16:48:35 +0000361#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100362 addr.in.sin_len = sizeof(addr.in);
Simon Kelley1ab84e22004-01-29 16:48:35 +0000363#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100364 addr.in.sin_family = AF_INET;
365 addr.in.sin_addr = broadcast; /* warning */
366 addr.in.sin_addr = local;
367 addr.in.sin_port = htons(daemon->port);
Simon Kelley44a2a312004-03-10 20:04:35 +0000368
Simon Kelley74c95c22011-10-19 09:33:39 +0100369 return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100370}
371
Simon Kelley5aabfc72007-08-29 11:24:47 +0100372int enumerate_interfaces(void)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100373{
374#ifdef HAVE_IPV6
Simon Kelley28866e92011-02-14 20:19:14 +0000375 if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))
376 return 0;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100377#endif
Simon Kelley28866e92011-02-14 20:19:14 +0000378
379 return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4);
Simon Kelley44a2a312004-03-10 20:04:35 +0000380}
381
Simon Kelley5aabfc72007-08-29 11:24:47 +0100382/* set NONBLOCK bit on fd: See Stevens 16.6 */
Simon Kelley7cebd202006-05-06 14:13:33 +0100383int fix_fd(int fd)
384{
385 int flags;
386
387 if ((flags = fcntl(fd, F_GETFL)) == -1 ||
Simon Kelley5aabfc72007-08-29 11:24:47 +0100388 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
Simon Kelley7cebd202006-05-06 14:13:33 +0100389 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100390
Simon Kelley7cebd202006-05-06 14:13:33 +0100391 return 1;
392}
393
Simon Kelley74c95c22011-10-19 09:33:39 +0100394static int make_sock(union mysockaddr *addr, int type, int dienow)
Simon Kelley44a2a312004-03-10 20:04:35 +0000395{
Simon Kelley28866e92011-02-14 20:19:14 +0000396 int family = addr->sa.sa_family;
397 int fd, rc, opt = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100398
Simon Kelley28866e92011-02-14 20:19:14 +0000399 if ((fd = socket(family, type, 0)) == -1)
Simon Kelley316e2732010-01-22 20:16:09 +0000400 {
Simon Kelley28866e92011-02-14 20:19:14 +0000401 int port;
Simon Kelley39f1b8e2012-06-20 20:04:27 +0100402 char *s;
Simon Kelley28866e92011-02-14 20:19:14 +0000403
404 /* No error if the kernel just doesn't support this IP flavour */
405 if (errno == EPROTONOSUPPORT ||
406 errno == EAFNOSUPPORT ||
407 errno == EINVAL)
408 return -1;
409
410 err:
Simon Kelley39f1b8e2012-06-20 20:04:27 +0100411 port = prettyprint_addr(addr, daemon->addrbuff);
412 if (!option_bool(OPT_NOWILD) && !option_bool(OPT_CLEVERBIND))
413 sprintf(daemon->addrbuff, "port %d", port);
414 s = _("failed to create listening socket for %s: %s");
415
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100416 if (fd != -1)
417 close (fd);
Simon Kelley39f1b8e2012-06-20 20:04:27 +0100418
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100419 if (dienow)
420 {
421 /* failure to bind addresses given by --listen-address at this point
422 is OK if we're doing bind-dynamic */
423 if (!option_bool(OPT_CLEVERBIND))
424 die(s, daemon->addrbuff, EC_BADNET);
425 }
426 else
427 my_syslog(LOG_WARNING, s, daemon->addrbuff, strerror(errno));
428
Simon Kelley74c95c22011-10-19 09:33:39 +0100429 return -1;
Simon Kelley28866e92011-02-14 20:19:14 +0000430 }
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100431
Simon Kelley28866e92011-02-14 20:19:14 +0000432 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
433 goto err;
434
435#ifdef HAVE_IPV6
Simon Kelleyc72daea2012-01-05 21:33:27 +0000436 if (family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000437 goto err;
438#endif
439
Simon Kelley74c95c22011-10-19 09:33:39 +0100440 if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000441 goto err;
442
443 if (type == SOCK_STREAM)
444 {
445 if (listen(fd, 5) == -1)
446 goto err;
447 }
448 else if (!option_bool(OPT_NOWILD))
449 {
450 if (family == AF_INET)
451 {
452#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000453 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
Simon Kelley28866e92011-02-14 20:19:14 +0000454 goto err;
455#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
456 if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
457 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1)
458 goto err;
459#endif
460 }
461#ifdef HAVE_IPV6
Simon Kelleyc72daea2012-01-05 21:33:27 +0000462 else if (!set_ipv6pktinfo(fd))
463 goto err;
Simon Kelley316e2732010-01-22 20:16:09 +0000464#endif
Simon Kelley28866e92011-02-14 20:19:14 +0000465 }
Simon Kelleyc72daea2012-01-05 21:33:27 +0000466
Simon Kelley28866e92011-02-14 20:19:14 +0000467 return fd;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100468}
Simon Kelleyc72daea2012-01-05 21:33:27 +0000469
470#ifdef HAVE_IPV6
471int set_ipv6pktinfo(int fd)
472{
473 int opt = 1;
474
475 /* The API changed around Linux 2.6.14 but the old ABI is still supported:
476 handle all combinations of headers and kernel.
477 OpenWrt note that this fixes the problem addressed by your very broken patch. */
478 daemon->v6pktinfo = IPV6_PKTINFO;
479
480#ifdef IPV6_RECVPKTINFO
481 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)) != -1)
482 return 1;
483# ifdef IPV6_2292PKTINFO
484 else if (errno == ENOPROTOOPT && setsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
485 {
486 daemon->v6pktinfo = IPV6_2292PKTINFO;
487 return 1;
488 }
489# endif
490#else
491 if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &opt, sizeof(opt)) != -1)
492 return 1;
493#endif
494
495 return 0;
496}
497#endif
Simon Kelley22ce5502013-01-22 13:53:04 +0000498
499
500/* Find the interface on which a TCP connection arrived, if possible, or zero otherwise. */
501int tcp_interface(int fd, int af)
502{
503 int if_index = 0;
504
505#ifdef HAVE_LINUX_NETWORK
506 int opt = 1;
507 struct cmsghdr *cmptr;
508 struct msghdr msg;
509
510 /* use mshdr do that the CMSDG_* macros are available */
511 msg.msg_control = daemon->packet;
512 msg.msg_controllen = daemon->packet_buff_sz;
513
514 /* we overwrote the buffer... */
515 daemon->srv_save = NULL;
516
517 if (af == AF_INET)
518 {
519 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&
520 getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)
521 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
522 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
523 {
524 union {
525 unsigned char *c;
526 struct in_pktinfo *p;
527 } p;
528
529 p.c = CMSG_DATA(cmptr);
530 if_index = p.p->ipi_ifindex;
531 }
532 }
533#ifdef HAVE_IPV6
534 else
535 {
536 /* Only the RFC-2292 API has the ability to find the interface for TCP connections,
537 it was removed in RFC-3542 !!!!
538
539 Fortunately, Linux kept the 2292 ABI when it moved to 3542. The following code always
540 uses the old ABI, and should work with pre- and post-3542 kernel headers */
541
542#ifdef IPV6_2292PKTOPTIONS
543# define PKTOPTIONS IPV6_2292PKTOPTIONS
544#else
545# define PKTOPTIONS IPV6_PKTOPTIONS
546#endif
547
548 if (set_ipv6pktinfo(fd) &&
549 getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)
550 {
551 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
552 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
553 {
554 union {
555 unsigned char *c;
556 struct in6_pktinfo *p;
557 } p;
558 p.c = CMSG_DATA(cmptr);
559
560 if_index = p.p->ipi6_ifindex;
561 }
562 }
563 }
564#endif /* IPV6 */
565#endif /* Linux */
566
567 return if_index;
568}
Simon Kelley28866e92011-02-14 20:19:14 +0000569
Simon Kelley74c95c22011-10-19 09:33:39 +0100570static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
Simon Kelley28866e92011-02-14 20:19:14 +0000571{
572 struct listener *l = NULL;
573 int fd = -1, tcpfd = -1, tftpfd = -1;
574
575 if (daemon->port != 0)
576 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100577 fd = make_sock(addr, SOCK_DGRAM, dienow);
578 tcpfd = make_sock(addr, SOCK_STREAM, dienow);
Simon Kelley28866e92011-02-14 20:19:14 +0000579 }
580
581#ifdef HAVE_TFTP
582 if (do_tftp)
583 {
584 if (addr->sa.sa_family == AF_INET)
585 {
586 /* port must be restored to DNS port for TCP code */
587 short save = addr->in.sin_port;
588 addr->in.sin_port = htons(TFTP_PORT);
Simon Kelley74c95c22011-10-19 09:33:39 +0100589 tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
Simon Kelley28866e92011-02-14 20:19:14 +0000590 addr->in.sin_port = save;
591 }
592# ifdef HAVE_IPV6
593 else
594 {
595 short save = addr->in6.sin6_port;
596 addr->in6.sin6_port = htons(TFTP_PORT);
Simon Kelley74c95c22011-10-19 09:33:39 +0100597 tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
Simon Kelley28866e92011-02-14 20:19:14 +0000598 addr->in6.sin6_port = save;
599 }
600# endif
601 }
Simon Kelley44a2a312004-03-10 20:04:35 +0000602#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100603
Simon Kelley28866e92011-02-14 20:19:14 +0000604 if (fd != -1 || tcpfd != -1 || tftpfd != -1)
605 {
606 l = safe_malloc(sizeof(struct listener));
607 l->next = NULL;
608 l->family = addr->sa.sa_family;
609 l->fd = fd;
610 l->tcpfd = tcpfd;
611 l->tftpfd = tftpfd;
612 }
613
614 return l;
615}
616
Simon Kelley74c95c22011-10-19 09:33:39 +0100617void create_wildcard_listeners(void)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100618{
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100619 union mysockaddr addr;
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100620 struct listener *l, *l6;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100621
Simon Kelley849a8352006-06-09 21:02:31 +0100622 memset(&addr, 0, sizeof(addr));
Simon Kelley28866e92011-02-14 20:19:14 +0000623#ifdef HAVE_SOCKADDR_SA_LEN
624 addr.in.sin_len = sizeof(addr.in);
625#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100626 addr.in.sin_family = AF_INET;
627 addr.in.sin_addr.s_addr = INADDR_ANY;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100628 addr.in.sin_port = htons(daemon->port);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100629
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100630 l = create_listeners(&addr, !!option_bool(OPT_TFTP), 1);
Simon Kelley28866e92011-02-14 20:19:14 +0000631
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100632#ifdef HAVE_IPV6
Simon Kelley28866e92011-02-14 20:19:14 +0000633 memset(&addr, 0, sizeof(addr));
634# ifdef HAVE_SOCKADDR_SA_LEN
635 addr.in6.sin6_len = sizeof(addr.in6);
636# endif
637 addr.in6.sin6_family = AF_INET6;
638 addr.in6.sin6_addr = in6addr_any;
639 addr.in6.sin6_port = htons(daemon->port);
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100640
641 l6 = create_listeners(&addr, !!option_bool(OPT_TFTP), 1);
Simon Kelley28866e92011-02-14 20:19:14 +0000642 if (l)
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100643 l->next = l6;
Simon Kelley28866e92011-02-14 20:19:14 +0000644 else
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100645 l = l6;
Simon Kelley832af0b2007-01-21 20:01:28 +0000646#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100647
Simon Kelley74c95c22011-10-19 09:33:39 +0100648 daemon->listeners = l;
Simon Kelley44a2a312004-03-10 20:04:35 +0000649}
650
Simon Kelley74c95c22011-10-19 09:33:39 +0100651void create_bound_listeners(int dienow)
Simon Kelley44a2a312004-03-10 20:04:35 +0000652{
Simon Kelley74c95c22011-10-19 09:33:39 +0100653 struct listener *new;
Simon Kelley44a2a312004-03-10 20:04:35 +0000654 struct irec *iface;
Simon Kelley52d4abf2012-03-21 21:39:48 +0000655 struct iname *if_tmp;
Simon Kelley73a08a22009-02-05 20:28:08 +0000656
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100657 for (iface = daemon->interfaces; iface; iface = iface->next)
Simon Kelley74c95c22011-10-19 09:33:39 +0100658 if (!iface->done && !iface->dad &&
659 (new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
Simon Kelley28866e92011-02-14 20:19:14 +0000660 {
661 new->iface = iface;
Simon Kelley74c95c22011-10-19 09:33:39 +0100662 new->next = daemon->listeners;
663 daemon->listeners = new;
664 iface->done = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000665 }
Simon Kelley52d4abf2012-03-21 21:39:48 +0000666
667 /* Check for --listen-address options that haven't been used because there's
668 no interface with a matching address. These may be valid: eg it's possible
669 to listen on 127.0.1.1 even if the loopback interface is 127.0.0.1
670
Simon Kelley5f11b3e2012-08-16 14:04:05 +0100671 If the address isn't valid the bind() will fail and we'll die()
672 (except in bind-dynamic mode, when we'll complain but keep trying.)
Simon Kelley52d4abf2012-03-21 21:39:48 +0000673
674 The resulting listeners have the ->iface field NULL, and this has to be
675 handled by the DNS and TFTP code. It disables --localise-queries processing
676 (no netmask) and some MTU login the tftp code. */
677
678 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
679 if (!if_tmp->used &&
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100680 (new = create_listeners(&if_tmp->addr, !!option_bool(OPT_TFTP), dienow)))
Simon Kelley52d4abf2012-03-21 21:39:48 +0000681 {
682 new->iface = NULL;
683 new->next = daemon->listeners;
684 daemon->listeners = new;
685 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000686}
687
Simon Kelley74c95c22011-10-19 09:33:39 +0100688int is_dad_listeners(void)
689{
690 struct irec *iface;
691
692 if (option_bool(OPT_NOWILD))
693 for (iface = daemon->interfaces; iface; iface = iface->next)
694 if (iface->dad && !iface->done)
695 return 1;
696
697 return 0;
698}
Simon Kelley5d162f22012-12-20 14:55:46 +0000699
700#ifdef HAVE_DHCP6
701void join_multicast(int dienow)
702{
703 struct irec *iface, *tmp;
704
705 for (iface = daemon->interfaces; iface; iface = iface->next)
Simon Kelley19624462012-12-28 11:18:09 +0000706 if (iface->addr.sa.sa_family == AF_INET6 && iface->dhcp_ok && !iface->multicast_done)
Simon Kelley5d162f22012-12-20 14:55:46 +0000707 {
708 /* There's an irec per address but we only want to join for multicast
709 once per interface. Weed out duplicates. */
710 for (tmp = daemon->interfaces; tmp; tmp = tmp->next)
711 if (tmp->multicast_done && tmp->index == iface->index)
712 break;
713
714 iface->multicast_done = 1;
715
716 if (!tmp)
717 {
718 struct ipv6_mreq mreq;
719 int err = 0;
720
721 mreq.ipv6mr_interface = iface->index;
722
723 inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
724
725 if (daemon->doing_dhcp6 &&
726 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
727 err = 1;
728
729 inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
730
731 if (daemon->doing_dhcp6 &&
732 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
733 err = 1;
734
735 inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
736
737 if (daemon->doing_ra &&
738 setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
739 err = 1;
740
741 if (err)
742 {
743 char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
744 if (dienow)
745 die(s, iface->name, EC_BADNET);
746 else
747 my_syslog(LOG_ERR, s, iface->name, strerror(errno));
748 }
749 }
750 }
751}
752#endif
753
Simon Kelley9009d742008-11-14 20:04:27 +0000754/* return a UDP socket bound to a random port, have to cope with straying into
Simon Kelley1a6bca82008-07-11 11:11:42 +0100755 occupied port nos and reserved ones. */
756int random_sock(int family)
757{
758 int fd;
759
760 if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
761 {
Simon Kelley3927da42008-07-20 15:10:39 +0100762 union mysockaddr addr;
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100763 unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port;
Simon Kelley9009d742008-11-14 20:04:27 +0000764 int tries = ports_avail < 30 ? 3 * ports_avail : 100;
Simon Kelley3927da42008-07-20 15:10:39 +0100765
Simon Kelley1a6bca82008-07-11 11:11:42 +0100766 memset(&addr, 0, sizeof(addr));
Simon Kelley3927da42008-07-20 15:10:39 +0100767 addr.sa.sa_family = family;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100768
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100769 /* don't loop forever if all ports in use. */
770
Simon Kelley1a6bca82008-07-11 11:11:42 +0100771 if (fix_fd(fd))
Simon Kelley9009d742008-11-14 20:04:27 +0000772 while(tries--)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100773 {
774 unsigned short port = rand16();
775
Simon Kelley3927da42008-07-20 15:10:39 +0100776 if (daemon->min_port != 0)
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100777 port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
Simon Kelley1a6bca82008-07-11 11:11:42 +0100778
779 if (family == AF_INET)
780 {
781 addr.in.sin_addr.s_addr = INADDR_ANY;
Simon Kelley3927da42008-07-20 15:10:39 +0100782 addr.in.sin_port = port;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100783#ifdef HAVE_SOCKADDR_SA_LEN
784 addr.in.sin_len = sizeof(struct sockaddr_in);
785#endif
786 }
787#ifdef HAVE_IPV6
788 else
789 {
790 addr.in6.sin6_addr = in6addr_any;
Simon Kelley3927da42008-07-20 15:10:39 +0100791 addr.in6.sin6_port = port;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100792#ifdef HAVE_SOCKADDR_SA_LEN
793 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
794#endif
795 }
796#endif
797
798 if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)
799 return fd;
800
801 if (errno != EADDRINUSE && errno != EACCES)
802 break;
803 }
804
805 close(fd);
806 }
807
808 return -1;
809}
810
811
Simon Kelley824af852008-02-12 20:43:05 +0000812int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
813{
814 union mysockaddr addr_copy = *addr;
815
816 /* cannot set source _port_ for TCP connections. */
817 if (is_tcp)
818 {
819 if (addr_copy.sa.sa_family == AF_INET)
820 addr_copy.in.sin_port = 0;
821#ifdef HAVE_IPV6
822 else
823 addr_copy.in6.sin6_port = 0;
824#endif
825 }
826
827 if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
828 return 0;
829
830#if defined(SO_BINDTODEVICE)
Simon Kelley73a08a22009-02-05 20:28:08 +0000831 if (intname[0] != 0 &&
Simon Kelley316e2732010-01-22 20:16:09 +0000832 setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
Simon Kelley824af852008-02-12 20:43:05 +0000833 return 0;
834#endif
835
836 return 1;
837}
838
839static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000840{
841 struct serverfd *sfd;
Simon Kelley824af852008-02-12 20:43:05 +0000842 int errsave;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100843
Simon Kelley1a6bca82008-07-11 11:11:42 +0100844 /* when using random ports, servers which would otherwise use
845 the INADDR_ANY/port0 socket have sfd set to NULL */
Simon Kelley73a08a22009-02-05 20:28:08 +0000846 if (!daemon->osport && intname[0] == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100847 {
848 errno = 0;
849
850 if (addr->sa.sa_family == AF_INET &&
851 addr->in.sin_addr.s_addr == INADDR_ANY &&
852 addr->in.sin_port == htons(0))
853 return NULL;
854
855#ifdef HAVE_IPV6
856 if (addr->sa.sa_family == AF_INET6 &&
857 memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
858 addr->in6.sin6_port == htons(0))
859 return NULL;
860#endif
861 }
862
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000863 /* may have a suitable one already */
Simon Kelley824af852008-02-12 20:43:05 +0000864 for (sfd = daemon->sfds; sfd; sfd = sfd->next )
865 if (sockaddr_isequal(&sfd->source_addr, addr) &&
866 strcmp(intname, sfd->interface) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000867 return sfd;
868
869 /* need to make a new one. */
870 errno = ENOMEM; /* in case malloc fails. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100871 if (!(sfd = whine_malloc(sizeof(struct serverfd))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000872 return NULL;
873
874 if ((sfd->fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
875 {
876 free(sfd);
877 return NULL;
878 }
879
Simon Kelley824af852008-02-12 20:43:05 +0000880 if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd))
881 {
882 errsave = errno; /* save error from bind. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000883 close(sfd->fd);
884 free(sfd);
885 errno = errsave;
886 return NULL;
887 }
Simon Kelley824af852008-02-12 20:43:05 +0000888
889 strcpy(sfd->interface, intname);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000890 sfd->source_addr = *addr;
Simon Kelley824af852008-02-12 20:43:05 +0000891 sfd->next = daemon->sfds;
892 daemon->sfds = sfd;
893 return sfd;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000894}
895
Simon Kelley824af852008-02-12 20:43:05 +0000896/* create upstream sockets during startup, before root is dropped which may be needed
897 this allows query_port to be a low port and interface binding */
898void pre_allocate_sfds(void)
899{
900 struct server *srv;
901
902 if (daemon->query_port != 0)
903 {
904 union mysockaddr addr;
905 memset(&addr, 0, sizeof(addr));
906 addr.in.sin_family = AF_INET;
907 addr.in.sin_addr.s_addr = INADDR_ANY;
908 addr.in.sin_port = htons(daemon->query_port);
909#ifdef HAVE_SOCKADDR_SA_LEN
910 addr.in.sin_len = sizeof(struct sockaddr_in);
911#endif
912 allocate_sfd(&addr, "");
913#ifdef HAVE_IPV6
914 memset(&addr, 0, sizeof(addr));
915 addr.in6.sin6_family = AF_INET6;
916 addr.in6.sin6_addr = in6addr_any;
917 addr.in6.sin6_port = htons(daemon->query_port);
918#ifdef HAVE_SOCKADDR_SA_LEN
919 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
920#endif
921 allocate_sfd(&addr, "");
922#endif
923 }
924
925 for (srv = daemon->servers; srv; srv = srv->next)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100926 if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
Simon Kelley824af852008-02-12 20:43:05 +0000927 !allocate_sfd(&srv->source_addr, srv->interface) &&
Simon Kelley1a6bca82008-07-11 11:11:42 +0100928 errno != 0 &&
Simon Kelley28866e92011-02-14 20:19:14 +0000929 option_bool(OPT_NOWILD))
Simon Kelley824af852008-02-12 20:43:05 +0000930 {
Simon Kelley316e2732010-01-22 20:16:09 +0000931 prettyprint_addr(&srv->source_addr, daemon->namebuff);
Simon Kelley73a08a22009-02-05 20:28:08 +0000932 if (srv->interface[0] != 0)
Simon Kelley824af852008-02-12 20:43:05 +0000933 {
934 strcat(daemon->namebuff, " ");
935 strcat(daemon->namebuff, srv->interface);
936 }
937 die(_("failed to bind server socket for %s: %s"),
938 daemon->namebuff, EC_BADNET);
939 }
940}
941
942
Simon Kelley5aabfc72007-08-29 11:24:47 +0100943void check_servers(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000944{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000945 struct irec *iface;
Simon Kelley3be34542004-09-11 19:12:13 +0100946 struct server *new, *tmp, *ret = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000947 int port = 0;
948
Simon Kelley316e2732010-01-22 20:16:09 +0000949 /* interface may be new since startup */
Simon Kelley28866e92011-02-14 20:19:14 +0000950 if (!option_bool(OPT_NOWILD))
Simon Kelley316e2732010-01-22 20:16:09 +0000951 enumerate_interfaces();
952
Simon Kelley3be34542004-09-11 19:12:13 +0100953 for (new = daemon->servers; new; new = tmp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000954 {
955 tmp = new->next;
956
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100957 if (!(new->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000958 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100959 port = prettyprint_addr(&new->addr, daemon->namebuff);
960
Simon Kelley16972692006-10-16 20:04:18 +0100961 /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
962 if (new->addr.sa.sa_family == AF_INET &&
963 new->addr.in.sin_addr.s_addr == 0)
964 {
965 free(new);
966 continue;
967 }
968
Simon Kelley3d8df262005-08-29 12:19:27 +0100969 for (iface = daemon->interfaces; iface; iface = iface->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000970 if (sockaddr_isequal(&new->addr, &iface->addr))
971 break;
972 if (iface)
973 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100974 my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000975 free(new);
976 continue;
977 }
978
979 /* Do we need a socket set? */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100980 if (!new->sfd &&
981 !(new->sfd = allocate_sfd(&new->source_addr, new->interface)) &&
982 errno != 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000983 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100984 my_syslog(LOG_WARNING,
985 _("ignoring nameserver %s - cannot make/bind socket: %s"),
986 daemon->namebuff, strerror(errno));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000987 free(new);
988 continue;
989 }
990 }
991
992 /* reverse order - gets it right. */
993 new->next = ret;
994 ret = new;
995
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100996 if (!(new->flags & SERV_NO_REBIND))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000997 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100998 if (new->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
999 {
1000 char *s1, *s2;
1001 if (!(new->flags & SERV_HAS_DOMAIN))
1002 s1 = _("unqualified"), s2 = _("names");
1003 else if (strlen(new->domain) == 0)
1004 s1 = _("default"), s2 = "";
1005 else
1006 s1 = _("domain"), s2 = new->domain;
1007
1008 if (new->flags & SERV_NO_ADDR)
1009 my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
1010 else if (new->flags & SERV_USE_RESOLV)
1011 my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
1012 else if (!(new->flags & SERV_LITERAL_ADDRESS))
1013 my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
1014 }
1015 else if (new->interface[0] != 0)
1016 my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, new->interface);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001017 else
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001018 my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001019 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001020 }
1021
Simon Kelley3be34542004-09-11 19:12:13 +01001022 daemon->servers = ret;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001023}
Simon Kelley849a8352006-06-09 21:02:31 +01001024
1025/* Return zero if no servers found, in that case we keep polling.
1026 This is a protection against an update-time/write race on resolv.conf */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001027int reload_servers(char *fname)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001028{
1029 FILE *f;
1030 char *line;
1031 struct server *old_servers = NULL;
1032 struct server *new_servers = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01001033 struct server *serv;
1034 int gotone = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001035
Simon Kelley849a8352006-06-09 21:02:31 +01001036 /* buff happens to be MAXDNAME long... */
1037 if (!(f = fopen(fname, "r")))
1038 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001039 my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));
Simon Kelley849a8352006-06-09 21:02:31 +01001040 return 0;
1041 }
1042
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001043 /* move old servers to free list - we can reuse the memory
1044 and not risk malloc if there are the same or fewer new servers.
1045 Servers which were specced on the command line go to the new list. */
Simon Kelley849a8352006-06-09 21:02:31 +01001046 for (serv = daemon->servers; serv;)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001047 {
1048 struct server *tmp = serv->next;
1049 if (serv->flags & SERV_FROM_RESOLV)
1050 {
1051 serv->next = old_servers;
Simon Kelley849a8352006-06-09 21:02:31 +01001052 old_servers = serv;
1053 /* forward table rules reference servers, so have to blow them away */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001054 server_gone(serv);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001055 }
1056 else
1057 {
1058 serv->next = new_servers;
1059 new_servers = serv;
1060 }
1061 serv = tmp;
1062 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001063
Simon Kelley849a8352006-06-09 21:02:31 +01001064 while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
1065 {
1066 union mysockaddr addr, source_addr;
1067 char *token = strtok(line, " \t\n\r");
1068
Simon Kelley5aabfc72007-08-29 11:24:47 +01001069 if (!token)
1070 continue;
1071 if (strcmp(token, "nameserver") != 0 && strcmp(token, "server") != 0)
Simon Kelley849a8352006-06-09 21:02:31 +01001072 continue;
1073 if (!(token = strtok(NULL, " \t\n\r")))
1074 continue;
1075
1076 memset(&addr, 0, sizeof(addr));
1077 memset(&source_addr, 0, sizeof(source_addr));
1078
1079 if ((addr.in.sin_addr.s_addr = inet_addr(token)) != (in_addr_t) -1)
1080 {
1081#ifdef HAVE_SOCKADDR_SA_LEN
1082 source_addr.in.sin_len = addr.in.sin_len = sizeof(source_addr.in);
1083#endif
1084 source_addr.in.sin_family = addr.in.sin_family = AF_INET;
1085 addr.in.sin_port = htons(NAMESERVER_PORT);
1086 source_addr.in.sin_addr.s_addr = INADDR_ANY;
1087 source_addr.in.sin_port = htons(daemon->query_port);
1088 }
1089#ifdef HAVE_IPV6
Simon Kelley7de060b2011-08-26 17:24:52 +01001090 else
1091 {
1092 int scope_index = 0;
1093 char *scope_id = strchr(token, '%');
1094
1095 if (scope_id)
1096 {
1097 *(scope_id++) = 0;
1098 scope_index = if_nametoindex(scope_id);
1099 }
1100
1101 if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
1102 {
Simon Kelley849a8352006-06-09 21:02:31 +01001103#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley7de060b2011-08-26 17:24:52 +01001104 source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
Simon Kelley849a8352006-06-09 21:02:31 +01001105#endif
Simon Kelley7de060b2011-08-26 17:24:52 +01001106 source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
1107 source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
1108 addr.in6.sin6_port = htons(NAMESERVER_PORT);
1109 addr.in6.sin6_scope_id = scope_index;
1110 source_addr.in6.sin6_addr = in6addr_any;
1111 source_addr.in6.sin6_port = htons(daemon->query_port);
1112 source_addr.in6.sin6_scope_id = 0;
1113 }
1114 else
1115 continue;
Simon Kelley849a8352006-06-09 21:02:31 +01001116 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001117#else /* IPV6 */
Simon Kelley849a8352006-06-09 21:02:31 +01001118 else
1119 continue;
Simon Kelley7de060b2011-08-26 17:24:52 +01001120#endif
1121
Simon Kelley849a8352006-06-09 21:02:31 +01001122 if (old_servers)
1123 {
1124 serv = old_servers;
1125 old_servers = old_servers->next;
1126 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001127 else if (!(serv = whine_malloc(sizeof (struct server))))
Simon Kelley849a8352006-06-09 21:02:31 +01001128 continue;
1129
1130 /* this list is reverse ordered:
1131 it gets reversed again in check_servers */
1132 serv->next = new_servers;
1133 new_servers = serv;
1134 serv->addr = addr;
1135 serv->source_addr = source_addr;
1136 serv->domain = NULL;
Simon Kelley824af852008-02-12 20:43:05 +00001137 serv->interface[0] = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01001138 serv->sfd = NULL;
1139 serv->flags = SERV_FROM_RESOLV;
Simon Kelley824af852008-02-12 20:43:05 +00001140 serv->queries = serv->failed_queries = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01001141 gotone = 1;
1142 }
1143
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001144 /* Free any memory not used. */
Simon Kelley849a8352006-06-09 21:02:31 +01001145 while (old_servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001146 {
1147 struct server *tmp = old_servers->next;
1148 free(old_servers);
1149 old_servers = tmp;
1150 }
1151
Simon Kelley3be34542004-09-11 19:12:13 +01001152 daemon->servers = new_servers;
Simon Kelley849a8352006-06-09 21:02:31 +01001153 fclose(f);
1154
1155 return gotone;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001156}
1157
1158
Simon Kelleyf2621c72007-04-29 19:47:21 +01001159/* Use an IPv4 listener socket for ioctling */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001160struct in_addr get_ifaddr(char *intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001161{
1162 struct listener *l;
1163 struct ifreq ifr;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001164 struct sockaddr_in ret;
1165
1166 ret.sin_addr.s_addr = -1;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001167
Simon Kelley28866e92011-02-14 20:19:14 +00001168 for (l = daemon->listeners;
1169 l && (l->family != AF_INET || l->fd == -1);
1170 l = l->next);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001171
1172 strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
1173 ifr.ifr_addr.sa_family = AF_INET;
1174
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001175 if (l && ioctl(l->fd, SIOCGIFADDR, &ifr) != -1)
1176 memcpy(&ret, &ifr.ifr_addr, sizeof(ret));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001177
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001178 return ret.sin_addr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001179}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001180
1181
1182