blob: 05a66ca5171a18d0689f152480de85eb7604217a [file] [log] [blame]
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001/* dnsmasq is Copyright (c) 2000 - 2006 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
5 the Free Software Foundation; version 2 dated June, 1991.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11*/
12
Simon Kelley9e4abcb2004-01-22 19:47:41 +000013#include "dnsmasq.h"
14
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010015int iface_check(struct daemon *daemon, int family, struct all_addr *addr, char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000016{
Simon Kelley9e4abcb2004-01-22 19:47:41 +000017 struct iname *tmp;
Simon Kelley309331f2006-04-22 15:05:01 +010018 int ret = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010019
Simon Kelley309331f2006-04-22 15:05:01 +010020 /* Note: have to check all and not bail out early, so that we set the
21 "used" flags. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010022
23 if (daemon->if_names || daemon->if_addrs)
24 {
Simon Kelley309331f2006-04-22 15:05:01 +010025 ret = 0;
26
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010027 for (tmp = daemon->if_names; tmp; tmp = tmp->next)
28 if (tmp->name && (strcmp(tmp->name, name) == 0))
Simon Kelley309331f2006-04-22 15:05:01 +010029 ret = tmp->used = 1;
30
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010031 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
32 if (tmp->addr.sa.sa_family == family)
33 {
34 if (family == AF_INET &&
35 tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
Simon Kelley309331f2006-04-22 15:05:01 +010036 ret = tmp->used = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010037#ifdef HAVE_IPV6
38 else if (family == AF_INET6 &&
39 IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
40 &addr->addr.addr6))
Simon Kelley309331f2006-04-22 15:05:01 +010041 ret = tmp->used = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010042#endif
43 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010044 }
45
Simon Kelley309331f2006-04-22 15:05:01 +010046 for (tmp = daemon->if_except; tmp; tmp = tmp->next)
47 if (tmp->name && (strcmp(tmp->name, name) == 0))
48 ret = 0;
49
50 return ret;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010051}
52
53static int iface_allowed(struct daemon *daemon, struct irec **irecp, int if_index,
54 union mysockaddr *addr, struct in_addr netmask)
55{
56 struct irec *iface;
57 int fd;
58 struct ifreq ifr;
59
60 /* check whether the interface IP has been added already
61 we call this routine multiple times. */
62 for (iface = *irecp; iface; iface = iface->next)
63 if (sockaddr_isequal(&iface->addr, addr))
64 return 1;
65
66#ifdef HAVE_LINUX_NETWORK
67 ifr.ifr_ifindex = if_index;
68#endif
69
70 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
71#ifdef HAVE_LINUX_NETWORK
72 ioctl(fd, SIOCGIFNAME, &ifr) == -1 ||
73#else
74 !if_indextoname(if_index, ifr.ifr_name) ||
75#endif
76 ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
77 {
78 if (fd != -1)
79 {
80 int errsave = errno;
81 close(fd);
82 errno = errsave;
83 }
84 return 0;
85 }
86
87 close(fd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000088
Simon Kelley59353a62004-11-21 19:34:28 +000089 /* If we are restricting the set of interfaces to use, make
90 sure that loopback interfaces are in that set. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010091 if (daemon->if_names && (ifr.ifr_flags & IFF_LOOPBACK))
Simon Kelley59353a62004-11-21 19:34:28 +000092 {
93 struct iname *lo;
94 for (lo = daemon->if_names; lo; lo = lo->next)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010095 if (lo->name && strcmp(lo->name, ifr.ifr_name) == 0)
Simon Kelley59353a62004-11-21 19:34:28 +000096 {
97 lo->isloop = 1;
98 break;
99 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100100
101 if (!lo && (lo = malloc(sizeof(struct iname))))
Simon Kelley59353a62004-11-21 19:34:28 +0000102 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100103 lo->name = safe_malloc(strlen(ifr.ifr_name)+1);
104 strcpy(lo->name, ifr.ifr_name);
Simon Kelley59353a62004-11-21 19:34:28 +0000105 lo->isloop = lo->used = 1;
106 lo->next = daemon->if_names;
107 daemon->if_names = lo;
108 }
109 }
110
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100111 if (addr->sa.sa_family == AF_INET &&
112 !iface_check(daemon, AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name))
113 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100114
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100115#ifdef HAVE_IPV6
116 if (addr->sa.sa_family == AF_INET6 &&
117 !iface_check(daemon, AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name))
118 return 1;
119#endif
120
121 /* add to list */
122 if ((iface = malloc(sizeof(struct irec))))
123 {
124 iface->addr = *addr;
125 iface->netmask = netmask;
126 iface->next = *irecp;
127 *irecp = iface;
128 return 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000129 }
130
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100131 errno = ENOMEM;
132 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000133}
134
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100135#ifdef HAVE_IPV6
136static int iface_allowed_v6(struct daemon *daemon, struct in6_addr *local,
137 int scope, int if_index, void *vparam)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000138{
Simon Kelley59353a62004-11-21 19:34:28 +0000139 union mysockaddr addr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100140 struct in_addr netmask; /* dummy */
Simon Kelley3d8df262005-08-29 12:19:27 +0100141
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100142 netmask.s_addr = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +0000143
Simon Kelley849a8352006-06-09 21:02:31 +0100144 memset(&addr, 0, sizeof(addr));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000145#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100146 addr.in6.sin6_len = sizeof(addr.in6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000147#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100148 addr.in6.sin6_family = AF_INET6;
149 addr.in6.sin6_addr = *local;
150 addr.in6.sin6_port = htons(daemon->port);
151 addr.in6.sin6_scope_id = scope;
Simon Kelley849a8352006-06-09 21:02:31 +0100152
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100153 return iface_allowed(daemon, (struct irec **)vparam, if_index, &addr, netmask);
154}
155#endif
Simon Kelley59353a62004-11-21 19:34:28 +0000156
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100157static int iface_allowed_v4(struct daemon *daemon, struct in_addr local, int if_index,
158 struct in_addr netmask, struct in_addr broadcast, void *vparam)
159{
160 union mysockaddr addr;
Simon Kelley849a8352006-06-09 21:02:31 +0100161
162 memset(&addr, 0, sizeof(addr));
Simon Kelley1ab84e22004-01-29 16:48:35 +0000163#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100164 addr.in.sin_len = sizeof(addr.in);
Simon Kelley1ab84e22004-01-29 16:48:35 +0000165#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100166 addr.in.sin_family = AF_INET;
167 addr.in.sin_addr = broadcast; /* warning */
168 addr.in.sin_addr = local;
169 addr.in.sin_port = htons(daemon->port);
Simon Kelley44a2a312004-03-10 20:04:35 +0000170
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100171 return iface_allowed(daemon, (struct irec **)vparam, if_index, &addr, netmask);
172}
173
174
175int enumerate_interfaces(struct daemon *daemon)
176{
177#ifdef HAVE_IPV6
178 return iface_enumerate(daemon, &daemon->interfaces, iface_allowed_v4, iface_allowed_v6);
179#else
180 return iface_enumerate(daemon, &daemon->interfaces, iface_allowed_v4, NULL);
181#endif
Simon Kelley44a2a312004-03-10 20:04:35 +0000182}
183
Simon Kelley7cebd202006-05-06 14:13:33 +0100184/* set NONBLOCK and CLOEXEC bits on fd: See Stevens 16.6 */
185int fix_fd(int fd)
186{
187 int flags;
188
189 if ((flags = fcntl(fd, F_GETFL)) == -1 ||
190 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
191 (flags = fcntl(fd, F_GETFD)) == -1 ||
192 fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
193 return 0;
194
195 return 1;
196}
197
Simon Kelley309331f2006-04-22 15:05:01 +0100198#if defined(HAVE_IPV6)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100199static int create_ipv6_listener(struct listener **link, int port)
Simon Kelley44a2a312004-03-10 20:04:35 +0000200{
201 union mysockaddr addr;
Simon Kelley7cebd202006-05-06 14:13:33 +0100202 int tcpfd, fd;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100203 struct listener *l;
Simon Kelley44a2a312004-03-10 20:04:35 +0000204 int opt = 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000205
Simon Kelley849a8352006-06-09 21:02:31 +0100206 memset(&addr, 0, sizeof(addr));
Simon Kelley44a2a312004-03-10 20:04:35 +0000207 addr.in6.sin6_family = AF_INET6;
208 addr.in6.sin6_addr = in6addr_any;
209 addr.in6.sin6_port = htons(port);
Simon Kelley44a2a312004-03-10 20:04:35 +0000210#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100211 addr.in6.sin6_len = sizeof(addr.in6);
Simon Kelley44a2a312004-03-10 20:04:35 +0000212#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100213
214 /* No error of the kernel doesn't support IPv6 */
Simon Kelley44a2a312004-03-10 20:04:35 +0000215 if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100216 return (errno == EPROTONOSUPPORT ||
217 errno == EAFNOSUPPORT ||
218 errno == EINVAL);
219
220 if ((tcpfd = socket(AF_INET6, SOCK_STREAM, 0)) == -1)
Simon Kelley26d0dba2006-04-23 20:00:42 +0100221 return 0;
222
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100223 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
224 setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
225 setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
226 setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100227 !fix_fd(fd) ||
228 !fix_fd(tcpfd) ||
Simon Kelleydfa666f2004-08-02 18:27:27 +0100229#ifdef IPV6_RECVPKTINFO
230 setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1 ||
231#else
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100232 setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
Simon Kelleydfa666f2004-08-02 18:27:27 +0100233#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100234 bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
235 listen(tcpfd, 5) == -1 ||
236 bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
Simon Kelley26d0dba2006-04-23 20:00:42 +0100237 return 0;
238
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100239 l = safe_malloc(sizeof(struct listener));
240 l->fd = fd;
241 l->tcpfd = tcpfd;
242 l->family = AF_INET6;
243 l->next = NULL;
244 *link = l;
245
246 return 1;
247}
Simon Kelley44a2a312004-03-10 20:04:35 +0000248#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100249
250struct listener *create_wildcard_listeners(int port)
251{
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100252 union mysockaddr addr;
253 int opt = 1;
254 struct listener *l, *l6 = NULL;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100255 int tcpfd, fd;
256
Simon Kelley849a8352006-06-09 21:02:31 +0100257 memset(&addr, 0, sizeof(addr));
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100258 addr.in.sin_family = AF_INET;
259 addr.in.sin_addr.s_addr = INADDR_ANY;
260 addr.in.sin_port = htons(port);
261#ifdef HAVE_SOCKADDR_SA_LEN
262 addr.in.sin_len = sizeof(struct sockaddr_in);
263#endif
264
Simon Kelley26d0dba2006-04-23 20:00:42 +0100265 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ||
266 (tcpfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100267 return NULL;
Simon Kelley44a2a312004-03-10 20:04:35 +0000268
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100269 if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
270 bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
271 listen(tcpfd, 5) == -1 ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100272 !fix_fd(tcpfd) ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100273#ifdef HAVE_IPV6
274 !create_ipv6_listener(&l6, port) ||
275#endif
276 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100277 !fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100278#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100279 setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
280#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
281 setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
282 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
283#endif
284 bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
Simon Kelley26d0dba2006-04-23 20:00:42 +0100285 return NULL;
286
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100287 l = safe_malloc(sizeof(struct listener));
288 l->family = AF_INET;
289 l->fd = fd;
290 l->tcpfd = tcpfd;
291 l->next = l6;
292
293 return l;
Simon Kelley44a2a312004-03-10 20:04:35 +0000294}
295
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100296struct listener *create_bound_listeners(struct daemon *daemon)
Simon Kelley44a2a312004-03-10 20:04:35 +0000297{
298
299 struct listener *listeners = NULL;
300 struct irec *iface;
Simon Kelley7cebd202006-05-06 14:13:33 +0100301 int opt = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100302
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100303 for (iface = daemon->interfaces; iface; iface = iface->next)
Simon Kelley26128d22004-11-14 16:43:54 +0000304 {
305 struct listener *new = safe_malloc(sizeof(struct listener));
306 new->family = iface->addr.sa.sa_family;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000307 new->iface = iface;
Simon Kelley26128d22004-11-14 16:43:54 +0000308 new->next = listeners;
Simon Kelley26128d22004-11-14 16:43:54 +0000309 if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
310 (new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
311 setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
312 setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100313 !fix_fd(new->tcpfd) ||
314 !fix_fd(new->fd))
Simon Kelleyb8187c82005-11-26 21:46:27 +0000315 die(_("failed to create listening socket: %s"), NULL);
Simon Kelley26128d22004-11-14 16:43:54 +0000316
317#ifdef HAVE_IPV6
318 if (iface->addr.sa.sa_family == AF_INET6)
319 {
320 if (setsockopt(new->fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
321 setsockopt(new->tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000322 die(_("failed to set IPV6 options on listening socket: %s"), NULL);
Simon Kelley26128d22004-11-14 16:43:54 +0000323 }
324#endif
325
326 if (bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
Simon Kelley59353a62004-11-21 19:34:28 +0000327 bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
328 {
329#ifdef HAVE_IPV6
330 if (iface->addr.sa.sa_family == AF_INET6 && errno == ENODEV)
331 {
332 close(new->tcpfd);
333 close(new->fd);
334 free(new);
335 }
336 else
337#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100338 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100339 prettyprint_addr(&iface->addr, daemon->namebuff);
340 die(_("failed to bind listening socket for %s: %s"),
341 daemon->namebuff);
Simon Kelley3d8df262005-08-29 12:19:27 +0100342 }
Simon Kelley59353a62004-11-21 19:34:28 +0000343 }
344 else
345 {
346 listeners = new;
347 if (listen(new->tcpfd, 5) == -1)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000348 die(_("failed to listen on socket: %s"), NULL);
Simon Kelley59353a62004-11-21 19:34:28 +0000349 }
Simon Kelley26128d22004-11-14 16:43:54 +0000350 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100351
Simon Kelley44a2a312004-03-10 20:04:35 +0000352 return listeners;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000353}
354
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100355struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000356{
357 struct serverfd *sfd;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100358
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000359 /* may have a suitable one already */
360 for (sfd = *sfds; sfd; sfd = sfd->next )
361 if (sockaddr_isequal(&sfd->source_addr, addr))
362 return sfd;
363
364 /* need to make a new one. */
365 errno = ENOMEM; /* in case malloc fails. */
366 if (!(sfd = malloc(sizeof(struct serverfd))))
367 return NULL;
368
369 if ((sfd->fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
370 {
371 free(sfd);
372 return NULL;
373 }
374
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100375 if (bind(sfd->fd, (struct sockaddr *)addr, sa_len(addr)) == -1 ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100376 !fix_fd(sfd->fd))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000377 {
378 int errsave = errno; /* save error from bind. */
379 close(sfd->fd);
380 free(sfd);
381 errno = errsave;
382 return NULL;
383 }
384
385 sfd->source_addr = *addr;
386 sfd->next = *sfds;
387 *sfds = sfd;
388
389 return sfd;
390}
391
Simon Kelley3d8df262005-08-29 12:19:27 +0100392void check_servers(struct daemon *daemon)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000393{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000394 struct irec *iface;
Simon Kelley3be34542004-09-11 19:12:13 +0100395 struct server *new, *tmp, *ret = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000396 int port = 0;
397
Simon Kelley3be34542004-09-11 19:12:13 +0100398 for (new = daemon->servers; new; new = tmp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000399 {
400 tmp = new->next;
401
402 if (!(new->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)))
403 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100404 port = prettyprint_addr(&new->addr, daemon->namebuff);
405
Simon Kelley16972692006-10-16 20:04:18 +0100406 /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
407 if (new->addr.sa.sa_family == AF_INET &&
408 new->addr.in.sin_addr.s_addr == 0)
409 {
410 free(new);
411 continue;
412 }
413
Simon Kelley3d8df262005-08-29 12:19:27 +0100414 for (iface = daemon->interfaces; iface; iface = iface->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000415 if (sockaddr_isequal(&new->addr, &iface->addr))
416 break;
417 if (iface)
418 {
Simon Kelleyb8187c82005-11-26 21:46:27 +0000419 syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000420 free(new);
421 continue;
422 }
423
424 /* Do we need a socket set? */
Simon Kelley3be34542004-09-11 19:12:13 +0100425 if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, &daemon->sfds)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000426 {
427 syslog(LOG_WARNING,
Simon Kelleyb8187c82005-11-26 21:46:27 +0000428 _("ignoring nameserver %s - cannot make/bind socket: %m"), daemon->namebuff);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000429 free(new);
430 continue;
431 }
432 }
433
434 /* reverse order - gets it right. */
435 new->next = ret;
436 ret = new;
437
438 if (new->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS))
439 {
440 char *s1, *s2;
441 if (new->flags & SERV_HAS_DOMAIN)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000442 s1 = _("domain"), s2 = new->domain;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000443 else
Simon Kelleyb8187c82005-11-26 21:46:27 +0000444 s1 = _("unqualified"), s2 = _("domains");
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000445
446 if (new->flags & SERV_NO_ADDR)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000447 syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000448 else if (!(new->flags & SERV_LITERAL_ADDRESS))
Simon Kelleyb8187c82005-11-26 21:46:27 +0000449 syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000450 }
451 else
Simon Kelleyb8187c82005-11-26 21:46:27 +0000452 syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000453 }
454
Simon Kelley3be34542004-09-11 19:12:13 +0100455 daemon->servers = ret;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000456}
Simon Kelley849a8352006-06-09 21:02:31 +0100457
458/* Return zero if no servers found, in that case we keep polling.
459 This is a protection against an update-time/write race on resolv.conf */
460int reload_servers(char *fname, struct daemon *daemon)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000461{
462 FILE *f;
463 char *line;
464 struct server *old_servers = NULL;
465 struct server *new_servers = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +0100466 struct server *serv;
467 int gotone = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000468
Simon Kelley849a8352006-06-09 21:02:31 +0100469 /* buff happens to be MAXDNAME long... */
470 if (!(f = fopen(fname, "r")))
471 {
472 syslog(LOG_ERR, _("failed to read %s: %m"), fname);
473 return 0;
474 }
475
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000476 /* move old servers to free list - we can reuse the memory
477 and not risk malloc if there are the same or fewer new servers.
478 Servers which were specced on the command line go to the new list. */
Simon Kelley849a8352006-06-09 21:02:31 +0100479 for (serv = daemon->servers; serv;)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000480 {
481 struct server *tmp = serv->next;
482 if (serv->flags & SERV_FROM_RESOLV)
483 {
484 serv->next = old_servers;
Simon Kelley849a8352006-06-09 21:02:31 +0100485 old_servers = serv;
486 /* forward table rules reference servers, so have to blow them away */
487 server_gone(daemon, serv);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000488 }
489 else
490 {
491 serv->next = new_servers;
492 new_servers = serv;
493 }
494 serv = tmp;
495 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000496
Simon Kelley849a8352006-06-09 21:02:31 +0100497 while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
498 {
499 union mysockaddr addr, source_addr;
500 char *token = strtok(line, " \t\n\r");
501
502 if (!token || strcmp(token, "nameserver") != 0)
503 continue;
504 if (!(token = strtok(NULL, " \t\n\r")))
505 continue;
506
507 memset(&addr, 0, sizeof(addr));
508 memset(&source_addr, 0, sizeof(source_addr));
509
510 if ((addr.in.sin_addr.s_addr = inet_addr(token)) != (in_addr_t) -1)
511 {
512#ifdef HAVE_SOCKADDR_SA_LEN
513 source_addr.in.sin_len = addr.in.sin_len = sizeof(source_addr.in);
514#endif
515 source_addr.in.sin_family = addr.in.sin_family = AF_INET;
516 addr.in.sin_port = htons(NAMESERVER_PORT);
517 source_addr.in.sin_addr.s_addr = INADDR_ANY;
518 source_addr.in.sin_port = htons(daemon->query_port);
519 }
520#ifdef HAVE_IPV6
521 else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
522 {
523#ifdef HAVE_SOCKADDR_SA_LEN
524 source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
525#endif
526 source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
527 addr.in6.sin6_port = htons(NAMESERVER_PORT);
528 source_addr.in6.sin6_addr = in6addr_any;
529 source_addr.in6.sin6_port = htons(daemon->query_port);
530 }
531#endif /* IPV6 */
532 else
533 continue;
534
535 if (old_servers)
536 {
537 serv = old_servers;
538 old_servers = old_servers->next;
539 }
540 else if (!(serv = malloc(sizeof (struct server))))
541 continue;
542
543 /* this list is reverse ordered:
544 it gets reversed again in check_servers */
545 serv->next = new_servers;
546 new_servers = serv;
547 serv->addr = addr;
548 serv->source_addr = source_addr;
549 serv->domain = NULL;
550 serv->sfd = NULL;
551 serv->flags = SERV_FROM_RESOLV;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000552
Simon Kelley849a8352006-06-09 21:02:31 +0100553 gotone = 1;
554 }
555
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000556 /* Free any memory not used. */
Simon Kelley849a8352006-06-09 21:02:31 +0100557 while (old_servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000558 {
559 struct server *tmp = old_servers->next;
560 free(old_servers);
561 old_servers = tmp;
562 }
563
Simon Kelley3be34542004-09-11 19:12:13 +0100564 daemon->servers = new_servers;
Simon Kelley849a8352006-06-09 21:02:31 +0100565 fclose(f);
566
567 return gotone;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000568}
569
570
571
572
573
574
575