blob: d3886e7f266abac4ad1bb2c130dab2a2c3f30d95 [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 Kelley5aabfc72007-08-29 11:24:47 +010015int iface_check(int family, struct all_addr *addr,
Simon Kelley832af0b2007-01-21 20:01:28 +000016 struct ifreq *ifr, int *indexp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000017{
Simon Kelley9e4abcb2004-01-22 19:47:41 +000018 struct iname *tmp;
Simon Kelley309331f2006-04-22 15:05:01 +010019 int ret = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010020
Simon Kelley309331f2006-04-22 15:05:01 +010021 /* Note: have to check all and not bail out early, so that we set the
22 "used" flags. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010023
Simon Kelley832af0b2007-01-21 20:01:28 +000024 if (indexp)
25 {
26#if defined(__FreeBSD__) || defined(__DragonFly__)
27 /* One form of bridging on FreeBSD has the property that packets
28 can be recieved on bridge interfaces which do not have an IP address.
29 We allow these to be treated as aliases of another interface which does have
30 an IP address with --dhcp-bridge=interface,alias,alias */
31 struct dhcp_bridge *bridge, *alias;
32 for (bridge = daemon->bridges; bridge; bridge = bridge->next)
33 {
34 for (alias = bridge->alias; alias; alias = alias->next)
35 if (strncmp(ifr->ifr_name, alias->iface, IF_NAMESIZE) == 0)
36 {
37 int newindex;
38
39 if (!(newindex = if_nametoindex(bridge->iface)))
40 {
Simon Kelleyf2621c72007-04-29 19:47:21 +010041 my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr->ifr_name);
Simon Kelley832af0b2007-01-21 20:01:28 +000042 return 0;
43 }
44 else
45 {
46 *indexp = newindex;
47 strncpy(ifr->ifr_name, bridge->iface, IF_NAMESIZE);
48 break;
49 }
50 }
51 if (alias)
52 break;
53 }
54#endif
55 }
56
57 if (daemon->if_names || (addr && daemon->if_addrs))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010058 {
Simon Kelley309331f2006-04-22 15:05:01 +010059 ret = 0;
60
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010061 for (tmp = daemon->if_names; tmp; tmp = tmp->next)
Simon Kelley832af0b2007-01-21 20:01:28 +000062 if (tmp->name && (strcmp(tmp->name, ifr->ifr_name) == 0))
Simon Kelley309331f2006-04-22 15:05:01 +010063 ret = tmp->used = 1;
64
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010065 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
Simon Kelley832af0b2007-01-21 20:01:28 +000066 if (addr && tmp->addr.sa.sa_family == family)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010067 {
68 if (family == AF_INET &&
69 tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
Simon Kelley309331f2006-04-22 15:05:01 +010070 ret = tmp->used = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010071#ifdef HAVE_IPV6
72 else if (family == AF_INET6 &&
73 IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
74 &addr->addr.addr6))
Simon Kelley309331f2006-04-22 15:05:01 +010075 ret = tmp->used = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010076#endif
77 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010078 }
79
Simon Kelley309331f2006-04-22 15:05:01 +010080 for (tmp = daemon->if_except; tmp; tmp = tmp->next)
Simon Kelley832af0b2007-01-21 20:01:28 +000081 if (tmp->name && (strcmp(tmp->name, ifr->ifr_name) == 0))
Simon Kelley309331f2006-04-22 15:05:01 +010082 ret = 0;
83
84 return ret;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010085}
86
Simon Kelley5aabfc72007-08-29 11:24:47 +010087static int iface_allowed(struct irec **irecp, int if_index,
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010088 union mysockaddr *addr, struct in_addr netmask)
89{
90 struct irec *iface;
91 int fd;
92 struct ifreq ifr;
Simon Kelley832af0b2007-01-21 20:01:28 +000093 int dhcp_ok = 1;
94 struct iname *tmp;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010095
96 /* check whether the interface IP has been added already
97 we call this routine multiple times. */
98 for (iface = *irecp; iface; iface = iface->next)
99 if (sockaddr_isequal(&iface->addr, addr))
100 return 1;
101
102#ifdef HAVE_LINUX_NETWORK
103 ifr.ifr_ifindex = if_index;
104#endif
105
106 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
107#ifdef HAVE_LINUX_NETWORK
108 ioctl(fd, SIOCGIFNAME, &ifr) == -1 ||
109#else
110 !if_indextoname(if_index, ifr.ifr_name) ||
111#endif
112 ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
113 {
114 if (fd != -1)
115 {
116 int errsave = errno;
117 close(fd);
118 errno = errsave;
119 }
120 return 0;
121 }
122
123 close(fd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000124
Simon Kelley59353a62004-11-21 19:34:28 +0000125 /* If we are restricting the set of interfaces to use, make
126 sure that loopback interfaces are in that set. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100127 if (daemon->if_names && (ifr.ifr_flags & IFF_LOOPBACK))
Simon Kelley59353a62004-11-21 19:34:28 +0000128 {
129 struct iname *lo;
130 for (lo = daemon->if_names; lo; lo = lo->next)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100131 if (lo->name && strcmp(lo->name, ifr.ifr_name) == 0)
Simon Kelley59353a62004-11-21 19:34:28 +0000132 {
133 lo->isloop = 1;
134 break;
135 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100136
Simon Kelley5aabfc72007-08-29 11:24:47 +0100137 if (!lo &&
138 (lo = whine_malloc(sizeof(struct iname))) &&
139 (lo->name = whine_malloc(strlen(ifr.ifr_name)+1)))
Simon Kelley59353a62004-11-21 19:34:28 +0000140 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100141 strcpy(lo->name, ifr.ifr_name);
Simon Kelley59353a62004-11-21 19:34:28 +0000142 lo->isloop = lo->used = 1;
143 lo->next = daemon->if_names;
144 daemon->if_names = lo;
145 }
146 }
147
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100148 if (addr->sa.sa_family == AF_INET &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100149 !iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, &ifr, NULL))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100150 return 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000151
152 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
153 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
154 dhcp_ok = 0;
155
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100156#ifdef HAVE_IPV6
157 if (addr->sa.sa_family == AF_INET6 &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100158 !iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, &ifr, NULL))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100159 return 1;
160#endif
161
162 /* add to list */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100163 if ((iface = whine_malloc(sizeof(struct irec))))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100164 {
165 iface->addr = *addr;
166 iface->netmask = netmask;
Simon Kelley832af0b2007-01-21 20:01:28 +0000167 iface->dhcp_ok = dhcp_ok;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100168 iface->next = *irecp;
Simon Kelley832af0b2007-01-21 20:01:28 +0000169 *irecp = iface;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100170 return 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000171 }
172
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100173 errno = ENOMEM;
174 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000175}
176
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100177#ifdef HAVE_IPV6
Simon Kelley5aabfc72007-08-29 11:24:47 +0100178static int iface_allowed_v6(struct in6_addr *local,
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100179 int scope, int if_index, void *vparam)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000180{
Simon Kelley59353a62004-11-21 19:34:28 +0000181 union mysockaddr addr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100182 struct in_addr netmask; /* dummy */
Simon Kelley3d8df262005-08-29 12:19:27 +0100183
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100184 netmask.s_addr = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +0000185
Simon Kelley849a8352006-06-09 21:02:31 +0100186 memset(&addr, 0, sizeof(addr));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000187#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100188 addr.in6.sin6_len = sizeof(addr.in6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000189#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100190 addr.in6.sin6_family = AF_INET6;
191 addr.in6.sin6_addr = *local;
192 addr.in6.sin6_port = htons(daemon->port);
193 addr.in6.sin6_scope_id = scope;
Simon Kelley849a8352006-06-09 21:02:31 +0100194
Simon Kelley5aabfc72007-08-29 11:24:47 +0100195 return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100196}
197#endif
Simon Kelley59353a62004-11-21 19:34:28 +0000198
Simon Kelley5aabfc72007-08-29 11:24:47 +0100199static int iface_allowed_v4(struct in_addr local, int if_index,
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100200 struct in_addr netmask, struct in_addr broadcast, void *vparam)
201{
202 union mysockaddr addr;
Simon Kelley849a8352006-06-09 21:02:31 +0100203
204 memset(&addr, 0, sizeof(addr));
Simon Kelley1ab84e22004-01-29 16:48:35 +0000205#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100206 addr.in.sin_len = sizeof(addr.in);
Simon Kelley1ab84e22004-01-29 16:48:35 +0000207#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100208 addr.in.sin_family = AF_INET;
209 addr.in.sin_addr = broadcast; /* warning */
210 addr.in.sin_addr = local;
211 addr.in.sin_port = htons(daemon->port);
Simon Kelley44a2a312004-03-10 20:04:35 +0000212
Simon Kelley5aabfc72007-08-29 11:24:47 +0100213 return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100214}
215
216
Simon Kelley5aabfc72007-08-29 11:24:47 +0100217int enumerate_interfaces(void)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100218{
219#ifdef HAVE_IPV6
Simon Kelley5aabfc72007-08-29 11:24:47 +0100220 return iface_enumerate(&daemon->interfaces, iface_allowed_v4, iface_allowed_v6);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100221#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100222 return iface_enumerate(&daemon->interfaces, iface_allowed_v4, NULL);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100223#endif
Simon Kelley44a2a312004-03-10 20:04:35 +0000224}
225
Simon Kelley5aabfc72007-08-29 11:24:47 +0100226/* set NONBLOCK bit on fd: See Stevens 16.6 */
Simon Kelley7cebd202006-05-06 14:13:33 +0100227int fix_fd(int fd)
228{
229 int flags;
230
231 if ((flags = fcntl(fd, F_GETFL)) == -1 ||
Simon Kelley5aabfc72007-08-29 11:24:47 +0100232 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
Simon Kelley7cebd202006-05-06 14:13:33 +0100233 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100234
Simon Kelley7cebd202006-05-06 14:13:33 +0100235 return 1;
236}
237
Simon Kelley309331f2006-04-22 15:05:01 +0100238#if defined(HAVE_IPV6)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100239static int create_ipv6_listener(struct listener **link, int port)
Simon Kelley44a2a312004-03-10 20:04:35 +0000240{
241 union mysockaddr addr;
Simon Kelley7cebd202006-05-06 14:13:33 +0100242 int tcpfd, fd;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100243 struct listener *l;
Simon Kelley44a2a312004-03-10 20:04:35 +0000244 int opt = 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000245
Simon Kelley849a8352006-06-09 21:02:31 +0100246 memset(&addr, 0, sizeof(addr));
Simon Kelley44a2a312004-03-10 20:04:35 +0000247 addr.in6.sin6_family = AF_INET6;
248 addr.in6.sin6_addr = in6addr_any;
249 addr.in6.sin6_port = htons(port);
Simon Kelley44a2a312004-03-10 20:04:35 +0000250#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100251 addr.in6.sin6_len = sizeof(addr.in6);
Simon Kelley44a2a312004-03-10 20:04:35 +0000252#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100253
254 /* No error of the kernel doesn't support IPv6 */
Simon Kelley44a2a312004-03-10 20:04:35 +0000255 if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100256 return (errno == EPROTONOSUPPORT ||
257 errno == EAFNOSUPPORT ||
258 errno == EINVAL);
259
260 if ((tcpfd = socket(AF_INET6, SOCK_STREAM, 0)) == -1)
Simon Kelley26d0dba2006-04-23 20:00:42 +0100261 return 0;
262
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100263 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
264 setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
265 setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
266 setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100267 !fix_fd(fd) ||
268 !fix_fd(tcpfd) ||
Simon Kelleydfa666f2004-08-02 18:27:27 +0100269#ifdef IPV6_RECVPKTINFO
270 setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1 ||
271#else
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100272 setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
Simon Kelleydfa666f2004-08-02 18:27:27 +0100273#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100274 bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
275 listen(tcpfd, 5) == -1 ||
276 bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
Simon Kelley26d0dba2006-04-23 20:00:42 +0100277 return 0;
278
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100279 l = safe_malloc(sizeof(struct listener));
280 l->fd = fd;
281 l->tcpfd = tcpfd;
Simon Kelley832af0b2007-01-21 20:01:28 +0000282 l->tftpfd = -1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100283 l->family = AF_INET6;
284 l->next = NULL;
285 *link = l;
286
287 return 1;
288}
Simon Kelley44a2a312004-03-10 20:04:35 +0000289#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100290
Simon Kelley5aabfc72007-08-29 11:24:47 +0100291struct listener *create_wildcard_listeners(void)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100292{
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100293 union mysockaddr addr;
294 int opt = 1;
295 struct listener *l, *l6 = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000296 int tcpfd, fd, tftpfd = -1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100297
Simon Kelley849a8352006-06-09 21:02:31 +0100298 memset(&addr, 0, sizeof(addr));
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100299 addr.in.sin_family = AF_INET;
300 addr.in.sin_addr.s_addr = INADDR_ANY;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100301 addr.in.sin_port = htons(daemon->port);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100302#ifdef HAVE_SOCKADDR_SA_LEN
303 addr.in.sin_len = sizeof(struct sockaddr_in);
304#endif
305
Simon Kelley26d0dba2006-04-23 20:00:42 +0100306 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ||
307 (tcpfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100308 return NULL;
Simon Kelley44a2a312004-03-10 20:04:35 +0000309
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100310 if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
311 bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
312 listen(tcpfd, 5) == -1 ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100313 !fix_fd(tcpfd) ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100314#ifdef HAVE_IPV6
Simon Kelley5aabfc72007-08-29 11:24:47 +0100315 !create_ipv6_listener(&l6, daemon->port) ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100316#endif
317 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100318 !fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100319#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100320 setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
321#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
322 setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
323 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
324#endif
325 bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
Simon Kelley26d0dba2006-04-23 20:00:42 +0100326 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000327
328#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100329 if (daemon->options & OPT_TFTP)
Simon Kelley832af0b2007-01-21 20:01:28 +0000330 {
331 addr.in.sin_port = htons(TFTP_PORT);
332 if ((tftpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
333 return NULL;
Simon Kelley26d0dba2006-04-23 20:00:42 +0100334
Simon Kelley5aabfc72007-08-29 11:24:47 +0100335 if (!fix_fd(tftpfd) ||
Simon Kelley832af0b2007-01-21 20:01:28 +0000336#if defined(HAVE_LINUX_NETWORK)
337 setsockopt(tftpfd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
338#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
339 setsockopt(tftpfd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
340 setsockopt(tftpfd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
341#endif
342 bind(tftpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
343 return NULL;
344 }
345#endif
346
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100347 l = safe_malloc(sizeof(struct listener));
348 l->family = AF_INET;
349 l->fd = fd;
350 l->tcpfd = tcpfd;
Simon Kelley832af0b2007-01-21 20:01:28 +0000351 l->tftpfd = tftpfd;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100352 l->next = l6;
353
354 return l;
Simon Kelley44a2a312004-03-10 20:04:35 +0000355}
356
Simon Kelley5aabfc72007-08-29 11:24:47 +0100357struct listener *create_bound_listeners(void)
Simon Kelley44a2a312004-03-10 20:04:35 +0000358{
Simon Kelley44a2a312004-03-10 20:04:35 +0000359 struct listener *listeners = NULL;
360 struct irec *iface;
Simon Kelley7cebd202006-05-06 14:13:33 +0100361 int opt = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100362
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100363 for (iface = daemon->interfaces; iface; iface = iface->next)
Simon Kelley26128d22004-11-14 16:43:54 +0000364 {
365 struct listener *new = safe_malloc(sizeof(struct listener));
366 new->family = iface->addr.sa.sa_family;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000367 new->iface = iface;
Simon Kelley26128d22004-11-14 16:43:54 +0000368 new->next = listeners;
Simon Kelley832af0b2007-01-21 20:01:28 +0000369 new->tftpfd = -1;
370
Simon Kelley26128d22004-11-14 16:43:54 +0000371 if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
372 (new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
373 setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
374 setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100375 !fix_fd(new->tcpfd) ||
376 !fix_fd(new->fd))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100377 die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
Simon Kelley26128d22004-11-14 16:43:54 +0000378
379#ifdef HAVE_IPV6
380 if (iface->addr.sa.sa_family == AF_INET6)
381 {
382 if (setsockopt(new->fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
383 setsockopt(new->tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100384 die(_("failed to set IPV6 options on listening socket: %s"), NULL, EC_BADNET);
Simon Kelley26128d22004-11-14 16:43:54 +0000385 }
386#endif
387
388 if (bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
Simon Kelley59353a62004-11-21 19:34:28 +0000389 bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
390 {
391#ifdef HAVE_IPV6
392 if (iface->addr.sa.sa_family == AF_INET6 && errno == ENODEV)
393 {
394 close(new->tcpfd);
395 close(new->fd);
396 free(new);
397 }
398 else
399#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100400 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100401 prettyprint_addr(&iface->addr, daemon->namebuff);
402 die(_("failed to bind listening socket for %s: %s"),
Simon Kelley5aabfc72007-08-29 11:24:47 +0100403 daemon->namebuff, EC_BADNET);
Simon Kelley3d8df262005-08-29 12:19:27 +0100404 }
Simon Kelley59353a62004-11-21 19:34:28 +0000405 }
406 else
407 {
408 listeners = new;
409 if (listen(new->tcpfd, 5) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100410 die(_("failed to listen on socket: %s"), NULL, EC_BADNET);
Simon Kelley59353a62004-11-21 19:34:28 +0000411 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000412
413 if ((daemon->options & OPT_TFTP) && iface->addr.sa.sa_family == AF_INET && iface->dhcp_ok)
414 {
415 short save = iface->addr.in.sin_port;
416 iface->addr.in.sin_port = htons(TFTP_PORT);
417 if ((new->tftpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ||
418 setsockopt(new->tftpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
419 !fix_fd(new->tftpfd) ||
420 bind(new->tftpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100421 die(_("failed to create TFTP socket: %s"), NULL, EC_BADNET);
Simon Kelley832af0b2007-01-21 20:01:28 +0000422 iface->addr.in.sin_port = save;
423 }
Simon Kelley26128d22004-11-14 16:43:54 +0000424 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000425
Simon Kelley44a2a312004-03-10 20:04:35 +0000426 return listeners;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000427}
428
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100429struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000430{
431 struct serverfd *sfd;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100432
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000433 /* may have a suitable one already */
434 for (sfd = *sfds; sfd; sfd = sfd->next )
435 if (sockaddr_isequal(&sfd->source_addr, addr))
436 return sfd;
437
438 /* need to make a new one. */
439 errno = ENOMEM; /* in case malloc fails. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100440 if (!(sfd = whine_malloc(sizeof(struct serverfd))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000441 return NULL;
442
443 if ((sfd->fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
444 {
445 free(sfd);
446 return NULL;
447 }
448
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100449 if (bind(sfd->fd, (struct sockaddr *)addr, sa_len(addr)) == -1 ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100450 !fix_fd(sfd->fd))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000451 {
452 int errsave = errno; /* save error from bind. */
453 close(sfd->fd);
454 free(sfd);
455 errno = errsave;
456 return NULL;
457 }
458
459 sfd->source_addr = *addr;
460 sfd->next = *sfds;
461 *sfds = sfd;
462
463 return sfd;
464}
465
Simon Kelley5aabfc72007-08-29 11:24:47 +0100466void check_servers(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000467{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000468 struct irec *iface;
Simon Kelley3be34542004-09-11 19:12:13 +0100469 struct server *new, *tmp, *ret = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000470 int port = 0;
471
Simon Kelley3be34542004-09-11 19:12:13 +0100472 for (new = daemon->servers; new; new = tmp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000473 {
474 tmp = new->next;
475
476 if (!(new->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)))
477 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100478 port = prettyprint_addr(&new->addr, daemon->namebuff);
479
Simon Kelley16972692006-10-16 20:04:18 +0100480 /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
481 if (new->addr.sa.sa_family == AF_INET &&
482 new->addr.in.sin_addr.s_addr == 0)
483 {
484 free(new);
485 continue;
486 }
487
Simon Kelley3d8df262005-08-29 12:19:27 +0100488 for (iface = daemon->interfaces; iface; iface = iface->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000489 if (sockaddr_isequal(&new->addr, &iface->addr))
490 break;
491 if (iface)
492 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100493 my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000494 free(new);
495 continue;
496 }
497
498 /* Do we need a socket set? */
Simon Kelley3be34542004-09-11 19:12:13 +0100499 if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, &daemon->sfds)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000500 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100501 my_syslog(LOG_WARNING,
502 _("ignoring nameserver %s - cannot make/bind socket: %s"),
503 daemon->namebuff, strerror(errno));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000504 free(new);
505 continue;
506 }
507 }
508
509 /* reverse order - gets it right. */
510 new->next = ret;
511 ret = new;
512
513 if (new->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS))
514 {
515 char *s1, *s2;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100516 if (!(new->flags & SERV_HAS_DOMAIN))
517 s1 = _("unqualified"), s2 = _("names");
518 else if (strlen(new->domain) == 0)
519 s1 = _("default"), s2 = "";
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000520 else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100521 s1 = _("domain"), s2 = new->domain;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000522
523 if (new->flags & SERV_NO_ADDR)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100524 my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000525 else if (!(new->flags & SERV_LITERAL_ADDRESS))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100526 my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000527 }
528 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100529 my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000530 }
531
Simon Kelley3be34542004-09-11 19:12:13 +0100532 daemon->servers = ret;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000533}
Simon Kelley849a8352006-06-09 21:02:31 +0100534
535/* Return zero if no servers found, in that case we keep polling.
536 This is a protection against an update-time/write race on resolv.conf */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100537int reload_servers(char *fname)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000538{
539 FILE *f;
540 char *line;
541 struct server *old_servers = NULL;
542 struct server *new_servers = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +0100543 struct server *serv;
544 int gotone = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000545
Simon Kelley849a8352006-06-09 21:02:31 +0100546 /* buff happens to be MAXDNAME long... */
547 if (!(f = fopen(fname, "r")))
548 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100549 my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));
Simon Kelley849a8352006-06-09 21:02:31 +0100550 return 0;
551 }
552
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000553 /* move old servers to free list - we can reuse the memory
554 and not risk malloc if there are the same or fewer new servers.
555 Servers which were specced on the command line go to the new list. */
Simon Kelley849a8352006-06-09 21:02:31 +0100556 for (serv = daemon->servers; serv;)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000557 {
558 struct server *tmp = serv->next;
559 if (serv->flags & SERV_FROM_RESOLV)
560 {
561 serv->next = old_servers;
Simon Kelley849a8352006-06-09 21:02:31 +0100562 old_servers = serv;
563 /* forward table rules reference servers, so have to blow them away */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100564 server_gone(serv);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000565 }
566 else
567 {
568 serv->next = new_servers;
569 new_servers = serv;
570 }
571 serv = tmp;
572 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000573
Simon Kelley849a8352006-06-09 21:02:31 +0100574 while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
575 {
576 union mysockaddr addr, source_addr;
577 char *token = strtok(line, " \t\n\r");
578
Simon Kelley5aabfc72007-08-29 11:24:47 +0100579 if (!token)
580 continue;
581 if (strcmp(token, "nameserver") != 0 && strcmp(token, "server") != 0)
Simon Kelley849a8352006-06-09 21:02:31 +0100582 continue;
583 if (!(token = strtok(NULL, " \t\n\r")))
584 continue;
585
586 memset(&addr, 0, sizeof(addr));
587 memset(&source_addr, 0, sizeof(source_addr));
588
589 if ((addr.in.sin_addr.s_addr = inet_addr(token)) != (in_addr_t) -1)
590 {
591#ifdef HAVE_SOCKADDR_SA_LEN
592 source_addr.in.sin_len = addr.in.sin_len = sizeof(source_addr.in);
593#endif
594 source_addr.in.sin_family = addr.in.sin_family = AF_INET;
595 addr.in.sin_port = htons(NAMESERVER_PORT);
596 source_addr.in.sin_addr.s_addr = INADDR_ANY;
597 source_addr.in.sin_port = htons(daemon->query_port);
598 }
599#ifdef HAVE_IPV6
600 else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
601 {
602#ifdef HAVE_SOCKADDR_SA_LEN
603 source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
604#endif
605 source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
606 addr.in6.sin6_port = htons(NAMESERVER_PORT);
607 source_addr.in6.sin6_addr = in6addr_any;
608 source_addr.in6.sin6_port = htons(daemon->query_port);
609 }
610#endif /* IPV6 */
611 else
612 continue;
613
614 if (old_servers)
615 {
616 serv = old_servers;
617 old_servers = old_servers->next;
618 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100619 else if (!(serv = whine_malloc(sizeof (struct server))))
Simon Kelley849a8352006-06-09 21:02:31 +0100620 continue;
621
622 /* this list is reverse ordered:
623 it gets reversed again in check_servers */
624 serv->next = new_servers;
625 new_servers = serv;
626 serv->addr = addr;
627 serv->source_addr = source_addr;
628 serv->domain = NULL;
629 serv->sfd = NULL;
630 serv->flags = SERV_FROM_RESOLV;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000631
Simon Kelley849a8352006-06-09 21:02:31 +0100632 gotone = 1;
633 }
634
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000635 /* Free any memory not used. */
Simon Kelley849a8352006-06-09 21:02:31 +0100636 while (old_servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000637 {
638 struct server *tmp = old_servers->next;
639 free(old_servers);
640 old_servers = tmp;
641 }
642
Simon Kelley3be34542004-09-11 19:12:13 +0100643 daemon->servers = new_servers;
Simon Kelley849a8352006-06-09 21:02:31 +0100644 fclose(f);
645
646 return gotone;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000647}
648
649
Simon Kelleyf2621c72007-04-29 19:47:21 +0100650/* Use an IPv4 listener socket for ioctling */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100651struct in_addr get_ifaddr(char *intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100652{
653 struct listener *l;
654 struct ifreq ifr;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000655
Simon Kelleyf2621c72007-04-29 19:47:21 +0100656 for (l = daemon->listeners; l && l->family != AF_INET; l = l->next);
657
658 strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
659 ifr.ifr_addr.sa_family = AF_INET;
660
661 if (!l || ioctl(l->fd, SIOCGIFADDR, &ifr) == -1)
662 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = -1;
663
664 return ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
665}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000666
667
668