blob: 7815ae611ae39c2dc97953860dcb0cecfc01cb0f [file] [log] [blame]
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001/* dnsmasq is Copyright (c) 2000 - 2003 Simon Kelley
2
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
13/* Author's email: simon@thekelleys.org.uk */
14
15#include "dnsmasq.h"
16
Simon Kelley59353a62004-11-21 19:34:28 +000017static struct irec *add_iface(struct daemon *daemon, struct irec *list,
18 char *name, int is_loopback, union mysockaddr *addr)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000019{
20 struct irec *iface;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000021 struct iname *tmp;
22
Simon Kelley59353a62004-11-21 19:34:28 +000023 /* If we are restricting the set of interfaces to use, make
24 sure that loopback interfaces are in that set. */
25 if (daemon->if_names && is_loopback)
26 {
27 struct iname *lo;
28 for (lo = daemon->if_names; lo; lo = lo->next)
29 if (lo->name && strcmp(lo->name, name) == 0)
30 {
31 lo->isloop = 1;
32 break;
33 }
34 if (!lo)
35 {
36 lo = safe_malloc(sizeof(struct iname));
37 lo->name = safe_string_alloc(name);
38 lo->isloop = lo->used = 1;
39 lo->next = daemon->if_names;
40 daemon->if_names = lo;
41 }
42 }
43
Simon Kelley9e4abcb2004-01-22 19:47:41 +000044 /* check blacklist */
Simon Kelley3be34542004-09-11 19:12:13 +010045 if (daemon->if_except)
46 for (tmp = daemon->if_except; tmp; tmp = tmp->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000047 if (tmp->name && strcmp(tmp->name, name) == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010048 {
49 /* record address of named interfaces, for TCP access control */
50 tmp->addr = *addr;
51 return list;
52 }
53
Simon Kelley44a2a312004-03-10 20:04:35 +000054 /* we may need to check the whitelist */
Simon Kelley3be34542004-09-11 19:12:13 +010055 if (daemon->if_names || daemon->if_addrs)
Simon Kelley44a2a312004-03-10 20:04:35 +000056 {
Simon Kelleyde379512004-06-22 20:23:33 +010057 int found = 0;
58
Simon Kelley3be34542004-09-11 19:12:13 +010059 for (tmp = daemon->if_names; tmp; tmp = tmp->next)
Simon Kelley44a2a312004-03-10 20:04:35 +000060 if (tmp->name && (strcmp(tmp->name, name) == 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +010061 {
62 tmp->addr = *addr;
63 found = tmp->used = 1;
64 }
65
Simon Kelley3be34542004-09-11 19:12:13 +010066 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
Simon Kelleyde379512004-06-22 20:23:33 +010067 if (sockaddr_isequal(&tmp->addr, addr))
68 found = tmp->used = 1;
69
70 if (!found)
Simon Kelleya84fa1d2004-04-23 22:21:21 +010071 return list;
Simon Kelley44a2a312004-03-10 20:04:35 +000072 }
73
Simon Kelley9e4abcb2004-01-22 19:47:41 +000074 /* check whether the interface IP has been added already
Simon Kelley44a2a312004-03-10 20:04:35 +000075 it is possible to have multiple interfaces with the same address */
Simon Kelleya84fa1d2004-04-23 22:21:21 +010076 for (iface = list; iface; iface = iface->next)
77 if (sockaddr_isequal(&iface->addr, addr))
Simon Kelley9e4abcb2004-01-22 19:47:41 +000078 break;
Simon Kelleya84fa1d2004-04-23 22:21:21 +010079 if (iface)
80 return list;
Simon Kelley44a2a312004-03-10 20:04:35 +000081
Simon Kelley9e4abcb2004-01-22 19:47:41 +000082 /* If OK, add it to the head of the list */
Simon Kelley44a2a312004-03-10 20:04:35 +000083 iface = safe_malloc(sizeof(struct irec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +000084 iface->addr = *addr;
Simon Kelleya84fa1d2004-04-23 22:21:21 +010085 iface->next = list;
Simon Kelley44a2a312004-03-10 20:04:35 +000086 return iface;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000087}
88
Simon Kelley44a2a312004-03-10 20:04:35 +000089
Simon Kelley3be34542004-09-11 19:12:13 +010090struct irec *enumerate_interfaces(struct daemon *daemon)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000091{
Simon Kelley59353a62004-11-21 19:34:28 +000092#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
93 FILE *f;
94#endif
95 union mysockaddr addr;
Simon Kelleya84fa1d2004-04-23 22:21:21 +010096 struct irec *iface = NULL;
Simon Kelley44a2a312004-03-10 20:04:35 +000097 char *buf, *ptr;
Simon Kelley1ab84e22004-01-29 16:48:35 +000098 struct ifreq *ifr = NULL;
Simon Kelley44a2a312004-03-10 20:04:35 +000099 struct ifconf ifc;
100 int lastlen = 0;
101 int len = 20 * sizeof(struct ifreq);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000102 int fd = socket(PF_INET, SOCK_DGRAM, 0);
Simon Kelley59353a62004-11-21 19:34:28 +0000103
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000104 if (fd == -1)
Simon Kelley44a2a312004-03-10 20:04:35 +0000105 die ("cannot create socket to enumerate interfaces: %s", NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100106
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000107 while (1)
Simon Kelley44a2a312004-03-10 20:04:35 +0000108 {
109 buf = safe_malloc(len);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000110
Simon Kelley44a2a312004-03-10 20:04:35 +0000111 ifc.ifc_len = len;
112 ifc.ifc_buf = buf;
113 if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
114 {
115 if (errno != EINVAL || lastlen != 0)
116 die ("ioctl error while enumerating interfaces: %s", NULL);
117 }
118 else
119 {
120 if (ifc.ifc_len == lastlen)
121 break; /* got a big enough buffer now */
122 lastlen = ifc.ifc_len;
123 }
124 len += 10*sizeof(struct ifreq);
125 free(buf);
126 }
127
Simon Kelley59353a62004-11-21 19:34:28 +0000128 for (ptr = buf; ptr < buf + ifc.ifc_len; )
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000129 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000130#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley1ab84e22004-01-29 16:48:35 +0000131 /* subsequent entries may not be aligned, so copy into
132 an aligned buffer to avoid nasty complaints about
133 unaligned accesses. */
134 int ifr_len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
135 if (!(ifr = realloc(ifr, ifr_len)))
Simon Kelley44a2a312004-03-10 20:04:35 +0000136 die("cannot allocate buffer", NULL);
Simon Kelley1ab84e22004-01-29 16:48:35 +0000137
138 memcpy(ifr, ptr, ifr_len);
139 ptr += ifr_len;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000140#else
Simon Kelley1ab84e22004-01-29 16:48:35 +0000141 ifr = (struct ifreq *)ptr;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000142 ptr += sizeof(struct ifreq);
143#endif
Simon Kelley44a2a312004-03-10 20:04:35 +0000144
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000145 /* copy address since getting flags overwrites */
146 if (ifr->ifr_addr.sa_family == AF_INET)
147 {
148 addr.in = *((struct sockaddr_in *) &ifr->ifr_addr);
Simon Kelley3be34542004-09-11 19:12:13 +0100149 addr.in.sin_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000150 }
151#ifdef HAVE_IPV6
152 else if (ifr->ifr_addr.sa_family == AF_INET6)
153 {
154#ifdef HAVE_BROKEN_SOCKADDR_IN6
155 addr.in6 = *((struct my_sockaddr_in6 *) &ifr->ifr_addr);
156#else
157 addr.in6 = *((struct sockaddr_in6 *) &ifr->ifr_addr);
158#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100159 addr.in6.sin6_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000160 addr.in6.sin6_flowinfo = htonl(0);
161 }
162#endif
163 else
164 continue; /* unknown address family */
165
166 if (ioctl(fd, SIOCGIFFLAGS, ifr) < 0)
Simon Kelley44a2a312004-03-10 20:04:35 +0000167 die("ioctl error getting interface flags: %m", NULL);
168
Simon Kelley59353a62004-11-21 19:34:28 +0000169 iface = add_iface(daemon, iface, ifr->ifr_name, ifr->ifr_flags & IFF_LOOPBACK, &addr);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000170 }
Simon Kelley59353a62004-11-21 19:34:28 +0000171
172#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
173 /* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
174 /* This code snarfed from net-tools 1.60 and certainly linux specific, though
175 it shouldn't break on other Unices, and their SIOGIFCONF might work. */
176 if ((f = fopen(IP6INTERFACES, "r")))
177 {
178 unsigned int plen, scope, flags, if_idx;
179 char devname[20], addrstring[32];
180
181 while (fscanf(f, "%32s %02x %02x %02x %02x %20s\n",
182 addrstring, &if_idx, &plen, &scope, &flags, devname) != EOF)
183 {
184 int i;
185 struct ifreq sifr;
186 unsigned char *addr6p = (unsigned char *) &addr.in6.sin6_addr;
187 memset(&addr, 0, sizeof(addr));
188 addr.sa.sa_family = AF_INET6;
189 for (i=0; i<16; i++)
190 {
191 unsigned int byte;
192 sscanf(addrstring+i+i, "%02x", &byte);
193 addr6p[i] = byte;
194 }
195 addr.in6.sin6_port = htons(daemon->port);
196 addr.in6.sin6_flowinfo = htonl(0);
197 addr.in6.sin6_scope_id = htonl(scope);
198
199 strncpy(sifr.ifr_name, devname, IF_NAMESIZE);
200 if (ioctl(fd, SIOCGIFFLAGS, &sifr) < 0)
201 die("ioctl error getting interface flags: %m", NULL);
202
203 iface = add_iface(daemon, iface, sifr.ifr_name, sifr.ifr_flags & IFF_LOOPBACK, &addr);
204
205 }
206 fclose(f);
207 }
208#endif /* LINUX */
209
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000210 if (buf)
211 free(buf);
Simon Kelley1ab84e22004-01-29 16:48:35 +0000212#ifdef HAVE_SOCKADDR_SA_LEN
213 if (ifr)
214 free(ifr);
215#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000216 close(fd);
Simon Kelley44a2a312004-03-10 20:04:35 +0000217
218 return iface;
219}
220
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100221#ifdef HAVE_IPV6
222static int create_ipv6_listener(struct listener **link, int port)
Simon Kelley44a2a312004-03-10 20:04:35 +0000223{
224 union mysockaddr addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100225 int tcpfd, fd, flags, save;
226 struct listener *l;
Simon Kelley44a2a312004-03-10 20:04:35 +0000227 int opt = 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000228
Simon Kelley44a2a312004-03-10 20:04:35 +0000229 addr.in6.sin6_family = AF_INET6;
230 addr.in6.sin6_addr = in6addr_any;
231 addr.in6.sin6_port = htons(port);
232 addr.in6.sin6_flowinfo = htonl(0);
233#ifdef HAVE_SOCKADDR_SA_LEN
234 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
235#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100236
237 /* No error of the kernel doesn't support IPv6 */
Simon Kelley44a2a312004-03-10 20:04:35 +0000238 if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100239 return (errno == EPROTONOSUPPORT ||
240 errno == EAFNOSUPPORT ||
241 errno == EINVAL);
242
243 if ((tcpfd = socket(AF_INET6, SOCK_STREAM, 0)) == -1)
Simon Kelley44a2a312004-03-10 20:04:35 +0000244 {
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100245 save = errno;
246 close(fd);
247 errno = save;
248 return 0;
Simon Kelley44a2a312004-03-10 20:04:35 +0000249 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100250
251 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
252 setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
253 setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
254 setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100255 (flags = fcntl(fd, F_GETFL, 0)) == -1 ||
256 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100257 (flags = fcntl(tcpfd, F_GETFL, 0)) == -1 ||
258 fcntl(tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
Simon Kelleydfa666f2004-08-02 18:27:27 +0100259#ifdef IPV6_RECVPKTINFO
260 setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1 ||
261#else
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100262 setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
Simon Kelleydfa666f2004-08-02 18:27:27 +0100263#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100264 bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
265 listen(tcpfd, 5) == -1 ||
266 bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
Simon Kelley44a2a312004-03-10 20:04:35 +0000267 {
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100268 save = errno;
269 close(fd);
270 close(tcpfd);
271 errno = save;
272 return 0;
Simon Kelley44a2a312004-03-10 20:04:35 +0000273 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100274
275 l = safe_malloc(sizeof(struct listener));
276 l->fd = fd;
277 l->tcpfd = tcpfd;
278 l->family = AF_INET6;
279 l->next = NULL;
280 *link = l;
281
282 return 1;
283}
Simon Kelley44a2a312004-03-10 20:04:35 +0000284#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100285
286struct listener *create_wildcard_listeners(int port)
287{
288#if !(defined(IP_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR)))
289 return NULL;
290#else
291 union mysockaddr addr;
292 int opt = 1;
293 struct listener *l, *l6 = NULL;
294 int flags;
295 int tcpfd, fd;
296
297 addr.in.sin_family = AF_INET;
298 addr.in.sin_addr.s_addr = INADDR_ANY;
299 addr.in.sin_port = htons(port);
300#ifdef HAVE_SOCKADDR_SA_LEN
301 addr.in.sin_len = sizeof(struct sockaddr_in);
302#endif
303
304 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
305 return NULL;
Simon Kelley44a2a312004-03-10 20:04:35 +0000306
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100307 if ((tcpfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
308 {
309 close (fd);
310 return NULL;
311 }
Simon Kelleyde379512004-06-22 20:23:33 +0100312
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100313 if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
314 bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
315 listen(tcpfd, 5) == -1 ||
316 (flags = fcntl(tcpfd, F_GETFL, 0)) == -1 ||
317 fcntl(tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
318#ifdef HAVE_IPV6
319 !create_ipv6_listener(&l6, port) ||
320#endif
321 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100322 (flags = fcntl(fd, F_GETFL, 0)) == -1 ||
323 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100324#if defined(IP_PKTINFO)
325 setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
326#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
327 setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
328 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
329#endif
330 bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
331 {
332 close(fd);
333 close(tcpfd);
334 return NULL;
335 }
336
337 l = safe_malloc(sizeof(struct listener));
338 l->family = AF_INET;
339 l->fd = fd;
340 l->tcpfd = tcpfd;
341 l->next = l6;
342
343 return l;
344
Simon Kelleyde379512004-06-22 20:23:33 +0100345#endif
Simon Kelley44a2a312004-03-10 20:04:35 +0000346}
347
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100348struct listener *create_bound_listeners(struct irec *interfaces, int port)
Simon Kelley44a2a312004-03-10 20:04:35 +0000349{
350
351 struct listener *listeners = NULL;
352 struct irec *iface;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100353 int flags = port, opt = 1;
354
Simon Kelley44a2a312004-03-10 20:04:35 +0000355 for (iface = interfaces ;iface; iface = iface->next)
Simon Kelley26128d22004-11-14 16:43:54 +0000356 {
357 struct listener *new = safe_malloc(sizeof(struct listener));
358 new->family = iface->addr.sa.sa_family;
359 new->next = listeners;
Simon Kelley26128d22004-11-14 16:43:54 +0000360 if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
361 (new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
362 setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
363 setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
364 /* See Stevens 16.6 */
365 (flags = fcntl(new->tcpfd, F_GETFL, 0)) == -1 ||
366 fcntl(new->tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
367 (flags = fcntl(new->fd, F_GETFL, 0)) == -1 ||
368 fcntl(new->fd, F_SETFL, flags | O_NONBLOCK) == -1)
369 die("failed to create listening socket: %s", NULL);
370
371#ifdef HAVE_IPV6
372 if (iface->addr.sa.sa_family == AF_INET6)
373 {
374 if (setsockopt(new->fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
375 setsockopt(new->tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
376 die("failed to set IPV6 options on listening socket: %s", NULL);
377 }
378#endif
379
380 if (bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
Simon Kelley59353a62004-11-21 19:34:28 +0000381 bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
382 {
383#ifdef HAVE_IPV6
384 if (iface->addr.sa.sa_family == AF_INET6 && errno == ENODEV)
385 {
386 close(new->tcpfd);
387 close(new->fd);
388 free(new);
389 }
390 else
391#endif
392 die("failed to bind listening socket: %s", NULL);
393 }
394 else
395 {
396 listeners = new;
397 if (listen(new->tcpfd, 5) == -1)
398 die("failed to listen on socket: %s", NULL);
399 }
Simon Kelley26128d22004-11-14 16:43:54 +0000400 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100401
Simon Kelley44a2a312004-03-10 20:04:35 +0000402 return listeners;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000403}
404
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100405struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000406{
407 struct serverfd *sfd;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100408 int flags;
409
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000410 /* may have a suitable one already */
411 for (sfd = *sfds; sfd; sfd = sfd->next )
412 if (sockaddr_isequal(&sfd->source_addr, addr))
413 return sfd;
414
415 /* need to make a new one. */
416 errno = ENOMEM; /* in case malloc fails. */
417 if (!(sfd = malloc(sizeof(struct serverfd))))
418 return NULL;
419
420 if ((sfd->fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
421 {
422 free(sfd);
423 return NULL;
424 }
425
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100426 if (bind(sfd->fd, (struct sockaddr *)addr, sa_len(addr)) == -1 ||
427 (flags = fcntl(sfd->fd, F_GETFL, 0)) == -1 ||
428 fcntl(sfd->fd, F_SETFL, flags | O_NONBLOCK) == -1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000429 {
430 int errsave = errno; /* save error from bind. */
431 close(sfd->fd);
432 free(sfd);
433 errno = errsave;
434 return NULL;
435 }
436
437 sfd->source_addr = *addr;
438 sfd->next = *sfds;
439 *sfds = sfd;
440
441 return sfd;
442}
443
Simon Kelley3be34542004-09-11 19:12:13 +0100444void check_servers(struct daemon *daemon, struct irec *interfaces)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000445{
446 char addrbuff[ADDRSTRLEN];
447 struct irec *iface;
Simon Kelley3be34542004-09-11 19:12:13 +0100448 struct server *new, *tmp, *ret = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000449 int port = 0;
450
451 /* forward table rules reference servers, so have to blow them away */
452 forward_init(0);
453
Simon Kelley3be34542004-09-11 19:12:13 +0100454 daemon->last_server = NULL;
455
456 for (new = daemon->servers; new; new = tmp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000457 {
458 tmp = new->next;
459
460 if (!(new->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)))
461 {
462#ifdef HAVE_IPV6
463 if (new->addr.sa.sa_family == AF_INET)
464 {
465 inet_ntop(AF_INET, &new->addr.in.sin_addr, addrbuff, ADDRSTRLEN);
466 port = ntohs(new->addr.in.sin_port);
467 }
468 else if (new->addr.sa.sa_family == AF_INET6)
469 {
470 inet_ntop(AF_INET6, &new->addr.in6.sin6_addr, addrbuff, ADDRSTRLEN);
471 port = ntohs(new->addr.in6.sin6_port);
472 }
473#else
474 strcpy(addrbuff, inet_ntoa(new->addr.in.sin_addr));
475 port = ntohs(new->addr.in.sin_port);
476#endif
477 for (iface = interfaces; iface; iface = iface->next)
478 if (sockaddr_isequal(&new->addr, &iface->addr))
479 break;
480 if (iface)
481 {
482 syslog(LOG_WARNING, "ignoring nameserver %s - local interface", addrbuff);
483 free(new);
484 continue;
485 }
486
487 /* Do we need a socket set? */
Simon Kelley3be34542004-09-11 19:12:13 +0100488 if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, &daemon->sfds)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000489 {
490 syslog(LOG_WARNING,
491 "ignoring nameserver %s - cannot make/bind socket: %m", addrbuff);
492 free(new);
493 continue;
494 }
495 }
496
497 /* reverse order - gets it right. */
498 new->next = ret;
499 ret = new;
500
501 if (new->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS))
502 {
503 char *s1, *s2;
504 if (new->flags & SERV_HAS_DOMAIN)
505 s1 = "domain", s2 = new->domain;
506 else
507 s1 = "unqualified", s2 = "domains";
508
509 if (new->flags & SERV_NO_ADDR)
510 syslog(LOG_INFO, "using local addresses only for %s %s", s1, s2);
511 else if (!(new->flags & SERV_LITERAL_ADDRESS))
512 syslog(LOG_INFO, "using nameserver %s#%d for %s %s", addrbuff, port, s1, s2);
513 }
514 else
515 syslog(LOG_INFO, "using nameserver %s#%d", addrbuff, port);
516 }
517
Simon Kelley3be34542004-09-11 19:12:13 +0100518 daemon->servers = ret;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000519}
520
Simon Kelley3be34542004-09-11 19:12:13 +0100521void reload_servers(char *fname, struct daemon *daemon)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000522{
523 FILE *f;
524 char *line;
525 struct server *old_servers = NULL;
526 struct server *new_servers = NULL;
Simon Kelley3be34542004-09-11 19:12:13 +0100527 struct server *serv = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000528
529 /* move old servers to free list - we can reuse the memory
530 and not risk malloc if there are the same or fewer new servers.
531 Servers which were specced on the command line go to the new list. */
532 while (serv)
533 {
534 struct server *tmp = serv->next;
535 if (serv->flags & SERV_FROM_RESOLV)
536 {
537 serv->next = old_servers;
538 old_servers = serv;
539 }
540 else
541 {
542 serv->next = new_servers;
543 new_servers = serv;
544 }
545 serv = tmp;
546 }
547
548 /* buff happens to be NAXDNAME long... */
549 f = fopen(fname, "r");
550 if (!f)
551 {
552 syslog(LOG_ERR, "failed to read %s: %m", fname);
553 }
554 else
555 {
556 syslog(LOG_INFO, "reading %s", fname);
Simon Kelley3be34542004-09-11 19:12:13 +0100557 while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000558 {
559 union mysockaddr addr, source_addr;
560 char *token = strtok(line, " \t\n\r");
561 struct server *serv;
562
563 if (!token || strcmp(token, "nameserver") != 0)
564 continue;
Simon Kelleyde379512004-06-22 20:23:33 +0100565 if (!(token = strtok(NULL, " \t\n\r")))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000566 continue;
567
568#ifdef HAVE_IPV6
569 if (inet_pton(AF_INET, token, &addr.in.sin_addr))
570#else
571 if ((addr.in.sin_addr.s_addr = inet_addr(token)) != (in_addr_t) -1)
572#endif
573 {
574#ifdef HAVE_SOCKADDR_SA_LEN
575 source_addr.in.sin_len = addr.in.sin_len = sizeof(struct sockaddr_in);
576#endif
577 source_addr.in.sin_family = addr.in.sin_family = AF_INET;
578 addr.in.sin_port = htons(NAMESERVER_PORT);
579 source_addr.in.sin_addr.s_addr = INADDR_ANY;
Simon Kelley3be34542004-09-11 19:12:13 +0100580 source_addr.in.sin_port = htons(daemon->query_port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000581 }
582#ifdef HAVE_IPV6
583 else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr))
584 {
585#ifdef HAVE_SOCKADDR_SA_LEN
586 source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);
587#endif
588 source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
589 addr.in6.sin6_port = htons(NAMESERVER_PORT);
590 source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = htonl(0);
Simon Kelley44a2a312004-03-10 20:04:35 +0000591 source_addr.in6.sin6_addr = in6addr_any;
Simon Kelley3be34542004-09-11 19:12:13 +0100592 source_addr.in6.sin6_port = htons(daemon->query_port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000593 }
594#endif /* IPV6 */
595 else
596 continue;
597
598 if (old_servers)
599 {
600 serv = old_servers;
601 old_servers = old_servers->next;
602 }
603 else if (!(serv = malloc(sizeof (struct server))))
604 continue;
605
606 /* this list is reverse ordered:
607 it gets reversed again in check_servers */
608 serv->next = new_servers;
609 new_servers = serv;
610 serv->addr = addr;
611 serv->source_addr = source_addr;
612 serv->domain = NULL;
613 serv->sfd = NULL;
614 serv->flags = SERV_FROM_RESOLV;
615 }
616
617 fclose(f);
618 }
619
620 /* Free any memory not used. */
621 while(old_servers)
622 {
623 struct server *tmp = old_servers->next;
624 free(old_servers);
625 old_servers = tmp;
626 }
627
Simon Kelley3be34542004-09-11 19:12:13 +0100628 daemon->servers = new_servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000629}
630
631
632
633
634
635
636