blob: 5a8daec98b7ee87195bb390f86e31b1df6a66e4d [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 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_DHCP
20
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010021struct iface_param {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010022 struct dhcp_context *current;
Simon Kelleyff7eea22013-09-04 18:01:38 +010023 struct dhcp_relay *relay;
24 struct in_addr relay_local;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010025 int ind;
26};
27
Simon Kelleyc72daea2012-01-05 21:33:27 +000028struct match_param {
29 int ind, matched;
30 struct in_addr netmask, broadcast, addr;
31};
32
Simon Kelley3f2873d2013-05-14 11:28:47 +010033static int complete_context(struct in_addr local, int if_index, char *label,
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010034 struct in_addr netmask, struct in_addr broadcast, void *vparam);
Simon Kelley3f2873d2013-05-14 11:28:47 +010035static int check_listen_addrs(struct in_addr local, int if_index, char *label,
Simon Kelleyc72daea2012-01-05 21:33:27 +000036 struct in_addr netmask, struct in_addr broadcast, void *vparam);
Simon Kelleyff7eea22013-09-04 18:01:38 +010037static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index);
38static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010039
Simon Kelley316e2732010-01-22 20:16:09 +000040static int make_fd(int port)
Simon Kelley44a2a312004-03-10 20:04:35 +000041{
42 int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
43 struct sockaddr_in saddr;
Simon Kelley7cebd202006-05-06 14:13:33 +010044 int oneopt = 1;
Simon Kelley824af852008-02-12 20:43:05 +000045#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
46 int mtu = IP_PMTUDISC_DONT;
47#endif
Simon Kelleyc72daea2012-01-05 21:33:27 +000048#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
49 int tos = IPTOS_CLASS_CS6;
50#endif
Simon Kelleydfa666f2004-08-02 18:27:27 +010051
Simon Kelley44a2a312004-03-10 20:04:35 +000052 if (fd == -1)
Simon Kelley7622fc02009-06-04 20:32:05 +010053 die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
Simon Kelley44a2a312004-03-10 20:04:35 +000054
Simon Kelley824af852008-02-12 20:43:05 +000055 if (!fix_fd(fd) ||
56#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
Simon Kelleyc72daea2012-01-05 21:33:27 +000057 setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
58#endif
59#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
60 setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1 ||
Simon Kelley824af852008-02-12 20:43:05 +000061#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010062#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc72daea2012-01-05 21:33:27 +000063 setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
Simon Kelley7622fc02009-06-04 20:32:05 +010064#else
Simon Kelley3be34542004-09-11 19:12:13 +010065 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
Simon Kelley44a2a312004-03-10 20:04:35 +000066#endif
Simon Kelley3be34542004-09-11 19:12:13 +010067 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +010068 die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET);
Simon Kelley44a2a312004-03-10 20:04:35 +000069
Josh Soref730c6742017-02-06 16:14:04 +000070 /* When bind-interfaces is set, there might be more than one dnsmasq
Simon Kelley4011c4e2006-10-28 16:26:19 +010071 instance binding port 67. That's OK if they serve different networks.
Josh Soref730c6742017-02-06 16:14:04 +000072 Need to set REUSEADDR|REUSEPORT to make this possible.
Simon Kelley56a11422013-04-02 17:02:58 +010073 Handle the case that REUSEPORT is defined, but the kernel doesn't
74 support it. This handles the introduction of REUSEPORT on Linux. */
Simon Kelley54dd3932012-06-20 11:23:38 +010075 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley4011c4e2006-10-28 16:26:19 +010076 {
Simon Kelleyffbad342013-08-14 15:53:57 +010077 int rc = 0;
Simon Kelley56a11422013-04-02 17:02:58 +010078
Simon Kelley4011c4e2006-10-28 16:26:19 +010079#ifdef SO_REUSEPORT
Simon Kelley56a11422013-04-02 17:02:58 +010080 if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
Simon Kelleyffbad342013-08-14 15:53:57 +010081 errno == ENOPROTOOPT)
82 rc = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +010083#endif
Simon Kelley56a11422013-04-02 17:02:58 +010084
Simon Kelleyffbad342013-08-14 15:53:57 +010085 if (rc != -1)
Simon Kelley56a11422013-04-02 17:02:58 +010086 rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
87
Simon Kelley4011c4e2006-10-28 16:26:19 +010088 if (rc == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +010089 die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
Simon Kelley4011c4e2006-10-28 16:26:19 +010090 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +000091
Simon Kelley849a8352006-06-09 21:02:31 +010092 memset(&saddr, 0, sizeof(saddr));
Simon Kelley44a2a312004-03-10 20:04:35 +000093 saddr.sin_family = AF_INET;
Simon Kelley316e2732010-01-22 20:16:09 +000094 saddr.sin_port = htons(port);
Simon Kelley44a2a312004-03-10 20:04:35 +000095 saddr.sin_addr.s_addr = INADDR_ANY;
Simon Kelley3be34542004-09-11 19:12:13 +010096#ifdef HAVE_SOCKADDR_SA_LEN
97 saddr.sin_len = sizeof(struct sockaddr_in);
98#endif
99
Simon Kelley44a2a312004-03-10 20:04:35 +0000100 if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100101 die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
Simon Kelley44a2a312004-03-10 20:04:35 +0000102
Simon Kelley316e2732010-01-22 20:16:09 +0000103 return fd;
104}
105
106void dhcp_init(void)
107{
108#if defined(HAVE_BSD_NETWORK)
109 int oneopt = 1;
110#endif
111
112 daemon->dhcpfd = make_fd(daemon->dhcp_server_port);
113 if (daemon->enable_pxe)
114 daemon->pxefd = make_fd(PXE_PORT);
115 else
116 daemon->pxefd = -1;
Simon Kelley3be34542004-09-11 19:12:13 +0100117
Simon Kelley824af852008-02-12 20:43:05 +0000118#if defined(HAVE_BSD_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100119 /* When we're not using capabilities, we need to do this here before
120 we drop root. Also, set buffer size small, to avoid wasting
121 kernel buffers */
Simon Kelley44a2a312004-03-10 20:04:35 +0000122
Simon Kelley28866e92011-02-14 20:19:14 +0000123 if (option_bool(OPT_NO_PING))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100124 daemon->dhcp_icmp_fd = -1;
125 else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 ||
126 setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 )
Simon Kelley5aabfc72007-08-29 11:24:47 +0100127 die(_("cannot create ICMP raw socket: %s."), NULL, EC_BADNET);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100128
129 /* Make BPF raw send socket */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100130 init_bpf();
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100131#endif
Simon Kelleyc72daea2012-01-05 21:33:27 +0000132}
133
Simon Kelley316e2732010-01-22 20:16:09 +0000134void dhcp_packet(time_t now, int pxe_fd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000135{
Simon Kelley316e2732010-01-22 20:16:09 +0000136 int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100137 struct dhcp_packet *mess;
Simon Kelley44a2a312004-03-10 20:04:35 +0000138 struct dhcp_context *context;
Simon Kelleyff7eea22013-09-04 18:01:38 +0100139 struct dhcp_relay *relay;
140 int is_relay_reply = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +0000141 struct iname *tmp;
142 struct ifreq ifr;
143 struct msghdr msg;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100144 struct sockaddr_in dest;
Simon Kelley44a2a312004-03-10 20:04:35 +0000145 struct cmsghdr *cmptr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100146 struct iovec iov;
147 ssize_t sz;
Simon Kelleyc7be0162017-05-10 22:21:53 +0100148 int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
Neil Jerramff325642016-05-03 22:45:14 +0100149 int rcvd_iface_index;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000150 struct in_addr iface_addr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100151 struct iface_param parm;
Floris Bos503c6092017-04-09 23:07:13 +0100152 time_t recvtime = now;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100153#ifdef HAVE_LINUX_NETWORK
154 struct arpreq arp_req;
Floris Bos503c6092017-04-09 23:07:13 +0100155 struct timeval tv;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100156#endif
157
Simon Kelley44a2a312004-03-10 20:04:35 +0000158 union {
159 struct cmsghdr align; /* this ensures alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000160#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +0000161 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +0000162#elif defined(HAVE_SOLARIS_NETWORK)
163 char control[CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley7622fc02009-06-04 20:32:05 +0100164#elif defined(HAVE_BSD_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +0000165 char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
166#endif
167 } control_u;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000168 struct dhcp_bridge *bridge, *alias;
169
170 msg.msg_controllen = sizeof(control_u);
171 msg.msg_control = control_u.control;
172 msg.msg_name = &dest;
173 msg.msg_namelen = sizeof(dest);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100174 msg.msg_iov = &daemon->dhcp_packet;
Simon Kelley44a2a312004-03-10 20:04:35 +0000175 msg.msg_iovlen = 1;
176
Simon Kelleyc72daea2012-01-05 21:33:27 +0000177 if ((sz = recv_dhcp_packet(fd, &msg)) == -1 ||
178 (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
Simon Kelley44a2a312004-03-10 20:04:35 +0000179 return;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000180
181 #if defined (HAVE_LINUX_NETWORK)
Floris Bos503c6092017-04-09 23:07:13 +0100182 if (ioctl(fd, SIOCGSTAMP, &tv) == 0)
183 recvtime = tv.tv_sec;
184
Simon Kelley4011c4e2006-10-28 16:26:19 +0100185 if (msg.msg_controllen >= sizeof(struct cmsghdr))
186 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000187 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley4011c4e2006-10-28 16:26:19 +0100188 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100189 union {
190 unsigned char *c;
191 struct in_pktinfo *p;
192 } p;
193 p.c = CMSG_DATA(cmptr);
194 iface_index = p.p->ipi_ifindex;
195 if (p.p->ipi_addr.s_addr != INADDR_BROADCAST)
Simon Kelley4011c4e2006-10-28 16:26:19 +0100196 unicast_dest = 1;
197 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100198
199#elif defined(HAVE_BSD_NETWORK)
Simon Kelley4011c4e2006-10-28 16:26:19 +0100200 if (msg.msg_controllen >= sizeof(struct cmsghdr))
201 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
202 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100203 {
204 union {
205 unsigned char *c;
206 struct sockaddr_dl *s;
207 } p;
208 p.c = CMSG_DATA(cmptr);
209 iface_index = p.s->sdl_index;
210 }
Simon Kelley4011c4e2006-10-28 16:26:19 +0100211
Simon Kelley7622fc02009-06-04 20:32:05 +0100212#elif defined(HAVE_SOLARIS_NETWORK)
213 if (msg.msg_controllen >= sizeof(struct cmsghdr))
214 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
215 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100216 {
217 union {
218 unsigned char *c;
219 unsigned int *i;
220 } p;
221 p.c = CMSG_DATA(cmptr);
222 iface_index = *(p.i);
223 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100224#endif
225
Simon Kelleyc7be0162017-05-10 22:21:53 +0100226 if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name) ||
Simon Kelley7ab78b92017-05-11 20:33:21 +0100227 ioctl(daemon->dhcpfd, SIOCGIFFLAGS, &ifr) != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +0100228 return;
Simon Kelleyc7be0162017-05-10 22:21:53 +0100229
230 mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
231 loopback = !mess->giaddr.s_addr && (ifr.ifr_flags & IFF_LOOPBACK);
232
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100233#ifdef HAVE_LINUX_NETWORK
234 /* ARP fiddling uses original interface even if we pretend to use a different one. */
235 strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
236#endif
237
Neil Jerram4918bd52015-06-10 22:23:20 +0100238 /* If the interface on which the DHCP request was received is an
239 alias of some other interface (as specified by the
240 --bridge-interface option), change ifr.ifr_name so that we look
241 for DHCP contexts associated with the aliased interface instead
242 of with the aliasing one. */
Neil Jerramff325642016-05-03 22:45:14 +0100243 rcvd_iface_index = iface_index;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000244 for (bridge = daemon->bridges; bridge; bridge = bridge->next)
245 {
246 for (alias = bridge->alias; alias; alias = alias->next)
Neil Jerram70772c92014-06-11 21:22:40 +0100247 if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000248 {
249 if (!(iface_index = if_nametoindex(bridge->iface)))
250 {
Neil Jerram654f59e2015-06-10 22:06:33 +0100251 my_syslog(MS_DHCP | LOG_WARNING,
252 _("unknown interface %s in bridge-interface"),
253 bridge->iface);
Simon Kelleyc72daea2012-01-05 21:33:27 +0000254 return;
255 }
256 else
257 {
258 strncpy(ifr.ifr_name, bridge->iface, IF_NAMESIZE);
259 break;
260 }
261 }
262
263 if (alias)
264 break;
265 }
266
Simon Kelley4011c4e2006-10-28 16:26:19 +0100267#ifdef MSG_BCAST
268 /* OpenBSD tells us when a packet was broadcast */
269 if (!(msg.msg_flags & MSG_BCAST))
270 unicast_dest = 1;
271#endif
Simon Kelleyc72daea2012-01-05 21:33:27 +0000272
Simon Kelleyff7eea22013-09-04 18:01:38 +0100273 if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
274 {
275 /* Reply from server, using us as relay. */
Simon Kelley1649f702017-06-25 21:19:30 +0100276 rcvd_iface_index = relay->iface_index;
277 if (!indextoname(daemon->dhcpfd, rcvd_iface_index, ifr.ifr_name))
Simon Kelleyff7eea22013-09-04 18:01:38 +0100278 return;
279 is_relay_reply = 1;
280 iov.iov_len = sz;
281#ifdef HAVE_LINUX_NETWORK
282 strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
283#endif
284 }
Simon Kelleyc72daea2012-01-05 21:33:27 +0000285 else
Simon Kelley832af0b2007-01-21 20:01:28 +0000286 {
Simon Kelleyff7eea22013-09-04 18:01:38 +0100287 ifr.ifr_addr.sa_family = AF_INET;
288 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
289 iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
290 else
291 {
Simon Kelleye94ad0f2016-08-28 18:09:17 +0100292 if (iface_check(AF_INET, NULL, ifr.ifr_name, NULL))
293 my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
Simon Kelleyff7eea22013-09-04 18:01:38 +0100294 return;
295 }
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100296
Simon Kelleyff7eea22013-09-04 18:01:38 +0100297 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
298 if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
299 return;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000300
Simon Kelleyff7eea22013-09-04 18:01:38 +0100301 /* unlinked contexts/relays are marked by context->current == context */
302 for (context = daemon->dhcp; context; context = context->next)
303 context->current = context;
304
305 for (relay = daemon->relay4; relay; relay = relay->next)
306 relay->current = relay;
307
308 parm.current = NULL;
309 parm.relay = NULL;
310 parm.relay_local.s_addr = 0;
311 parm.ind = iface_index;
312
313 if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
314 {
315 /* If we failed to match the primary address of the interface, see if we've got a --listen-address
316 for a secondary */
317 struct match_param match;
318
319 match.matched = 0;
320 match.ind = iface_index;
321
322 if (!daemon->if_addrs ||
323 !iface_enumerate(AF_INET, &match, check_listen_addrs) ||
324 !match.matched)
325 return;
326
327 iface_addr = match.addr;
328 /* make sure secondary address gets priority in case
329 there is more than one address on the interface in the same subnet */
330 complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
331 }
332
333 if (!iface_enumerate(AF_INET, &parm, complete_context))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000334 return;
335
Simon Kelleyff7eea22013-09-04 18:01:38 +0100336 /* We're relaying this request */
337 if (parm.relay_local.s_addr != 0 &&
Simon Kelleyc7be0162017-05-10 22:21:53 +0100338 relay_upstream4(parm.relay, mess, (size_t)sz, iface_index))
Simon Kelleyff7eea22013-09-04 18:01:38 +0100339 return;
340
341 /* May have configured relay, but not DHCP server */
342 if (!daemon->dhcp)
343 return;
344
345 lease_prune(NULL, now); /* lose any expired leases */
346 iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
Simon Kelleyc7be0162017-05-10 22:21:53 +0100347 now, unicast_dest, loopback, &is_inform, pxe_fd, iface_addr, recvtime);
Simon Kelleyff7eea22013-09-04 18:01:38 +0100348 lease_update_file(now);
349 lease_update_dns(0);
Simon Kelleyc72daea2012-01-05 21:33:27 +0000350
Simon Kelleyff7eea22013-09-04 18:01:38 +0100351 if (iov.iov_len == 0)
352 return;
353 }
Floris Bos503c6092017-04-09 23:07:13 +0100354
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100355 msg.msg_name = &dest;
356 msg.msg_namelen = sizeof(dest);
357 msg.msg_control = NULL;
358 msg.msg_controllen = 0;
359 msg.msg_iov = &iov;
360 iov.iov_base = daemon->dhcp_packet.iov_base;
361
362 /* packet buffer may have moved */
Simon Kelley824af852008-02-12 20:43:05 +0000363 mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100364
Simon Kelley3be34542004-09-11 19:12:13 +0100365#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100366 dest.sin_len = sizeof(struct sockaddr_in);
Simon Kelley3be34542004-09-11 19:12:13 +0100367#endif
Simon Kelleyc72daea2012-01-05 21:33:27 +0000368
Simon Kelley316e2732010-01-22 20:16:09 +0000369 if (pxe_fd)
370 {
371 if (mess->ciaddr.s_addr != 0)
372 dest.sin_addr = mess->ciaddr;
373 }
Simon Kelleyff7eea22013-09-04 18:01:38 +0100374 else if (mess->giaddr.s_addr && !is_relay_reply)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100375 {
376 /* Send to BOOTP relay */
Simon Kelley9e038942008-05-30 20:06:34 +0100377 dest.sin_port = htons(daemon->dhcp_server_port);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100378 dest.sin_addr = mess->giaddr;
379 }
380 else if (mess->ciaddr.s_addr)
381 {
Simon Kelley208b65c2006-08-05 21:41:37 +0100382 /* If the client's idea of its own address tallys with
383 the source address in the request packet, we believe the
Simon Kelley5aabfc72007-08-29 11:24:47 +0100384 source port too, and send back to that. If we're replying
385 to a DHCPINFORM, trust the source address always. */
386 if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
Simon Kelleyff7eea22013-09-04 18:01:38 +0100387 dest.sin_port == 0 || dest.sin_addr.s_addr == 0 || is_relay_reply)
Simon Kelley208b65c2006-08-05 21:41:37 +0100388 {
Simon Kelley9e038942008-05-30 20:06:34 +0100389 dest.sin_port = htons(daemon->dhcp_client_port);
Simon Kelley208b65c2006-08-05 21:41:37 +0100390 dest.sin_addr = mess->ciaddr;
391 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100392 }
Simon Kelley824af852008-02-12 20:43:05 +0000393#if defined(HAVE_LINUX_NETWORK)
Lung-Pin Chang65c72122015-03-19 23:22:21 +0000394 else
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100395 {
Lung-Pin Chang65c72122015-03-19 23:22:21 +0000396 /* fill cmsg for outbound interface (both broadcast & unicast) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100397 struct in_pktinfo *pkt;
Simon Kelley26d0dba2006-04-23 20:00:42 +0100398 msg.msg_control = control_u.control;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100399 msg.msg_controllen = sizeof(control_u);
400 cmptr = CMSG_FIRSTHDR(&msg);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100401 pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
Neil Jerramff325642016-05-03 22:45:14 +0100402 pkt->ipi_ifindex = rcvd_iface_index;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100403 pkt->ipi_spec_dst.s_addr = 0;
404 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
Simon Kelleyc72daea2012-01-05 21:33:27 +0000405 cmptr->cmsg_level = IPPROTO_IP;
Lung-Pin Chang65c72122015-03-19 23:22:21 +0000406 cmptr->cmsg_type = IP_PKTINFO;
407
408 if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
409 mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
410 {
411 /* broadcast to 255.255.255.255 (or mac address invalid) */
412 dest.sin_addr.s_addr = INADDR_BROADCAST;
413 dest.sin_port = htons(daemon->dhcp_client_port);
414 }
415 else
416 {
417 /* unicast to unconfigured client. Inject mac address direct into ARP cache.
418 struct sockaddr limits size to 14 bytes. */
419 dest.sin_addr = mess->yiaddr;
420 dest.sin_port = htons(daemon->dhcp_client_port);
421 memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
422 arp_req.arp_ha.sa_family = mess->htype;
423 memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
424 /* interface name already copied in */
425 arp_req.arp_flags = ATF_COM;
426 if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
427 my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
428 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000429 }
Simon Kelley824af852008-02-12 20:43:05 +0000430#elif defined(HAVE_SOLARIS_NETWORK)
431 else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
432 {
433 /* broadcast to 255.255.255.255 (or mac address invalid) */
434 dest.sin_addr.s_addr = INADDR_BROADCAST;
Simon Kelley9e038942008-05-30 20:06:34 +0100435 dest.sin_port = htons(daemon->dhcp_client_port);
Simon Kelley824af852008-02-12 20:43:05 +0000436 /* note that we don't specify the interface here: that's done by the
Simon Kelley7622fc02009-06-04 20:32:05 +0100437 IP_BOUND_IF sockopt lower down. */
Simon Kelley824af852008-02-12 20:43:05 +0000438 }
439 else
440 {
441 /* unicast to unconfigured client. Inject mac address direct into ARP cache.
442 Note that this only works for ethernet on solaris, because we use SIOCSARP
443 and not SIOCSXARP, which would be perfect, except that it returns ENXIO
444 mysteriously. Bah. Fall back to broadcast for other net types. */
445 struct arpreq req;
446 dest.sin_addr = mess->yiaddr;
Simon Kelley9e038942008-05-30 20:06:34 +0100447 dest.sin_port = htons(daemon->dhcp_client_port);
Simon Kelley824af852008-02-12 20:43:05 +0000448 *((struct sockaddr_in *)&req.arp_pa) = dest;
449 req.arp_ha.sa_family = AF_UNSPEC;
450 memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
451 req.arp_flags = ATF_COM;
452 ioctl(daemon->dhcpfd, SIOCSARP, &req);
453 }
454#elif defined(HAVE_BSD_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100455 else
456 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100457 send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100458 return;
459 }
460#endif
461
Simon Kelley824af852008-02-12 20:43:05 +0000462#ifdef HAVE_SOLARIS_NETWORK
Simon Kelley316e2732010-01-22 20:16:09 +0000463 setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
Simon Kelley824af852008-02-12 20:43:05 +0000464#endif
465
Simon Kelleyff841eb2015-03-11 21:36:30 +0000466 while(retry_send(sendmsg(fd, &msg, 0)));
Simon Kelley98079ea2015-10-13 20:30:32 +0100467
468 /* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
469 if (errno != 0)
470 my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
471 inet_ntoa(dest.sin_addr), strerror(errno));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000472}
Simon Kelley98079ea2015-10-13 20:30:32 +0100473
Simon Kelleyc72daea2012-01-05 21:33:27 +0000474/* check against secondary interface addresses */
Simon Kelley3f2873d2013-05-14 11:28:47 +0100475static int check_listen_addrs(struct in_addr local, int if_index, char *label,
Simon Kelleyc72daea2012-01-05 21:33:27 +0000476 struct in_addr netmask, struct in_addr broadcast, void *vparam)
477{
478 struct match_param *param = vparam;
479 struct iname *tmp;
480
Simon Kelley3f2873d2013-05-14 11:28:47 +0100481 (void) label;
482
Simon Kelleyc72daea2012-01-05 21:33:27 +0000483 if (if_index == param->ind)
484 {
485 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
486 if ( tmp->addr.sa.sa_family == AF_INET &&
487 tmp->addr.in.sin_addr.s_addr == local.s_addr)
488 {
489 param->matched = 1;
490 param->addr = local;
491 param->netmask = netmask;
492 param->broadcast = broadcast;
493 break;
494 }
495 }
496
497 return 1;
498}
499
Simon Kelley0a852542005-03-23 20:28:59 +0000500/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100501 of each interface (and any relay address) and does the following things:
502
503 1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
504 2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
505 3) Fills in local (this host) and router (this host or relay) addresses.
506 4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
507
klemens43517fc2017-02-19 15:53:37 +0000508 Note that the current chain may be superseded later for configured hosts or those coming via gateways. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100509
Simon Kelley3f2873d2013-05-14 11:28:47 +0100510static int complete_context(struct in_addr local, int if_index, char *label,
Simon Kelley5aabfc72007-08-29 11:24:47 +0100511 struct in_addr netmask, struct in_addr broadcast, void *vparam)
Simon Kelley0a852542005-03-23 20:28:59 +0000512{
513 struct dhcp_context *context;
Simon Kelleyff7eea22013-09-04 18:01:38 +0100514 struct dhcp_relay *relay;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100515 struct iface_param *param = vparam;
Simon Kelley3f2873d2013-05-14 11:28:47 +0100516
517 (void)label;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100518
Simon Kelley0a852542005-03-23 20:28:59 +0000519 for (context = daemon->dhcp; context; context = context->next)
520 {
521 if (!(context->flags & CONTEXT_NETMASK) &&
522 (is_same_net(local, context->start, netmask) ||
523 is_same_net(local, context->end, netmask)))
524 {
525 if (context->netmask.s_addr != netmask.s_addr &&
526 !(is_same_net(local, context->start, netmask) &&
527 is_same_net(local, context->end, netmask)))
528 {
529 strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
530 strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
Simon Kelley7622fc02009-06-04 20:32:05 +0100531 my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
Simon Kelleyf2621c72007-04-29 19:47:21 +0100532 daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
Simon Kelley0a852542005-03-23 20:28:59 +0000533 }
534 context->netmask = netmask;
535 }
536
Simon Kelley7de060b2011-08-26 17:24:52 +0100537 if (context->netmask.s_addr != 0 &&
538 is_same_net(local, context->start, context->netmask) &&
539 is_same_net(local, context->end, context->netmask))
Simon Kelley0a852542005-03-23 20:28:59 +0000540 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100541 /* link it onto the current chain if we've not seen it before */
542 if (if_index == param->ind && context->current == context)
Simon Kelley0a852542005-03-23 20:28:59 +0000543 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100544 context->router = local;
545 context->local = local;
546 context->current = param->current;
547 param->current = context;
548 }
549
550 if (!(context->flags & CONTEXT_BRDCAST))
Simon Kelley0a852542005-03-23 20:28:59 +0000551 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100552 if (is_same_net(broadcast, context->start, context->netmask))
553 context->broadcast = broadcast;
554 else
Simon Kelley0a852542005-03-23 20:28:59 +0000555 context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
556 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100557 }
Simon Kelley0a852542005-03-23 20:28:59 +0000558 }
559
Simon Kelleyff7eea22013-09-04 18:01:38 +0100560 for (relay = daemon->relay4; relay; relay = relay->next)
561 if (if_index == param->ind && relay->local.addr.addr4.s_addr == local.s_addr && relay->current == relay &&
562 (param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr))
563 {
564 relay->current = param->relay;
565 param->relay = relay;
566 param->relay_local = local;
567 }
568
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100569 return 1;
Simon Kelley0a852542005-03-23 20:28:59 +0000570}
571
Simon Kelley824af852008-02-12 20:43:05 +0000572struct dhcp_context *address_available(struct dhcp_context *context,
573 struct in_addr taddr,
574 struct dhcp_netid *netids)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000575{
Simon Kelley36717ee2004-09-20 19:20:58 +0100576 /* Check is an address is OK for this network, check all
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100577 possible ranges. Make sure that the address isn't in use
578 by the server itself. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000579
Simon Kelley36717ee2004-09-20 19:20:58 +0100580 unsigned int start, end, addr = ntohl(taddr.s_addr);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100581 struct dhcp_context *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +0100582
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100583 for (tmp = context; tmp; tmp = tmp->current)
Simon Kelley849a8352006-06-09 21:02:31 +0100584 if (taddr.s_addr == context->router.s_addr)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100585 return NULL;
586
587 for (tmp = context; tmp; tmp = tmp->current)
588 {
589 start = ntohl(tmp->start.s_addr);
590 end = ntohl(tmp->end.s_addr);
591
Simon Kelley7de060b2011-08-26 17:24:52 +0100592 if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
Simon Kelley36717ee2004-09-20 19:20:58 +0100593 addr >= start &&
Simon Kelley824af852008-02-12 20:43:05 +0000594 addr <= end &&
595 match_netid(tmp->filter, netids, 1))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100596 return tmp;
Simon Kelley36717ee2004-09-20 19:20:58 +0100597 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000598
Simon Kelley59353a62004-11-21 19:34:28 +0000599 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000600}
Simon Kelley59353a62004-11-21 19:34:28 +0000601
Simon Kelley824af852008-02-12 20:43:05 +0000602struct dhcp_context *narrow_context(struct dhcp_context *context,
603 struct in_addr taddr,
604 struct dhcp_netid *netids)
Simon Kelley59353a62004-11-21 19:34:28 +0000605{
Simon Kelleye17fb622006-01-14 20:33:46 +0000606 /* We start of with a set of possible contexts, all on the current physical interface.
Simon Kelley59353a62004-11-21 19:34:28 +0000607 These are chained on ->current.
Josh Soref730c6742017-02-06 16:14:04 +0000608 Here we have an address, and return the actual context corresponding to that
Simon Kelley59353a62004-11-21 19:34:28 +0000609 address. Note that none may fit, if the address came a dhcp-host and is outside
Simon Kelleye17fb622006-01-14 20:33:46 +0000610 any dhcp-range. In that case we return a static range if possible, or failing that,
611 any context on the correct subnet. (If there's more than one, this is a dodgy
612 configuration: maybe there should be a warning.) */
Simon Kelley59353a62004-11-21 19:34:28 +0000613
Simon Kelleye17fb622006-01-14 20:33:46 +0000614 struct dhcp_context *tmp;
Simon Kelley59353a62004-11-21 19:34:28 +0000615
Simon Kelley824af852008-02-12 20:43:05 +0000616 if (!(tmp = address_available(context, taddr, netids)))
617 {
618 for (tmp = context; tmp; tmp = tmp->current)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100619 if (match_netid(tmp->filter, netids, 1) &&
620 is_same_net(taddr, tmp->start, tmp->netmask) &&
Simon Kelley7622fc02009-06-04 20:32:05 +0100621 (tmp->flags & CONTEXT_STATIC))
622 break;
Simon Kelley824af852008-02-12 20:43:05 +0000623
624 if (!tmp)
625 for (tmp = context; tmp; tmp = tmp->current)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100626 if (match_netid(tmp->filter, netids, 1) &&
Simon Kelley7de060b2011-08-26 17:24:52 +0100627 is_same_net(taddr, tmp->start, tmp->netmask) &&
628 !(tmp->flags & CONTEXT_PROXY))
Simon Kelley824af852008-02-12 20:43:05 +0000629 break;
630 }
Simon Kelley59353a62004-11-21 19:34:28 +0000631
Simon Kelley824af852008-02-12 20:43:05 +0000632 /* Only one context allowed now */
633 if (tmp)
634 tmp->current = NULL;
635
636 return tmp;
Simon Kelley59353a62004-11-21 19:34:28 +0000637}
638
Simon Kelleydfa666f2004-08-02 18:27:27 +0100639struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
640{
641 struct dhcp_config *config;
642
643 for (config = configs; config; config = config->next)
644 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
645 return config;
646
647 return NULL;
648}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000649
Simon Kelley5ce3e762017-04-28 22:14:20 +0100650/* Check if and address is in use by sending ICMP ping.
651 This wrapper handles a cache and load-limiting.
652 Return is NULL is address in use, or a pointer to a cache entry
653 recording that it isn't. */
Simon Kelleyc7be0162017-05-10 22:21:53 +0100654struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash, int loopback)
Simon Kelley5ce3e762017-04-28 22:14:20 +0100655{
656 static struct ping_result dummy;
657 struct ping_result *r, *victim = NULL;
658 int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
659 ((float)PING_WAIT)));
660
661 /* check if we failed to ping addr sometime in the last
662 PING_CACHE_TIME seconds. If so, assume the same situation still exists.
663 This avoids problems when a stupid client bangs
664 on us repeatedly. As a final check, if we did more
665 than 60% of the possible ping checks in the last
666 PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
667 for (count = 0, r = daemon->ping_results; r; r = r->next)
668 if (difftime(now, r->time) > (float)PING_CACHE_TIME)
669 victim = r; /* old record */
670 else
671 {
672 count++;
673 if (r->addr.s_addr == addr.s_addr)
674 return r;
675 }
676
677 /* didn't find cached entry */
Simon Kelleyc7be0162017-05-10 22:21:53 +0100678 if ((count >= max) || option_bool(OPT_NO_PING) || loopback)
Simon Kelley5ce3e762017-04-28 22:14:20 +0100679 {
Simon Kelleyc7be0162017-05-10 22:21:53 +0100680 /* overloaded, or configured not to check, loopback interface, return "not in use" */
Simon Kelley5ce3e762017-04-28 22:14:20 +0100681 dummy.hash = 0;
682 return &dummy;
683 }
684 else if (icmp_ping(addr))
685 return NULL; /* address in use. */
686 else
687 {
688 /* at this point victim may hold an expired record */
689 if (!victim)
690 {
691 if ((victim = whine_malloc(sizeof(struct ping_result))))
692 {
693 victim->next = daemon->ping_results;
694 daemon->ping_results = victim;
695 }
696 }
697
698 /* record that this address is OK for 30s
699 without more ping checks */
700 if (victim)
701 {
702 victim->addr = addr;
703 victim->time = now;
704 victim->hash = hash;
705 }
706 return victim;
707 }
708}
709
Simon Kelley5aabfc72007-08-29 11:24:47 +0100710int address_allocate(struct dhcp_context *context,
Simon Kelleycdeda282006-03-16 20:16:06 +0000711 struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
Simon Kelleyc7be0162017-05-10 22:21:53 +0100712 struct dhcp_netid *netids, time_t now, int loopback)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000713{
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100714 /* Find a free address: exclude anything in use and anything allocated to
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000715 a particular hwaddr/clientid/hostname in our configuration.
Simon Kelleycdeda282006-03-16 20:16:06 +0000716 Try to return from contexts which match netids first. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000717
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100718 struct in_addr start, addr;
719 struct dhcp_context *c, *d;
Simon Kelleycdeda282006-03-16 20:16:06 +0000720 int i, pass;
721 unsigned int j;
Simon Kelley3d8df262005-08-29 12:19:27 +0100722
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100723 /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good
724 dispersal even with similarly-valued "strings". */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100725 for (j = 0, i = 0; i < hw_len; i++)
Simon Kelleyd6b749a2016-04-25 17:05:15 +0100726 j = hwaddr[i] + (j << 6) + (j << 16) - j;
Simon Kelley5ce3e762017-04-28 22:14:20 +0100727
728 /* j == 0 is marker */
729 if (j == 0)
730 j = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100731
Simon Kelleycdeda282006-03-16 20:16:06 +0000732 for (pass = 0; pass <= 1; pass++)
733 for (c = context; c; c = c->current)
Simon Kelley7de060b2011-08-26 17:24:52 +0100734 if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
Simon Kelleycdeda282006-03-16 20:16:06 +0000735 continue;
736 else if (!match_netid(c->filter, netids, pass))
737 continue;
738 else
739 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100740 if (option_bool(OPT_CONSEC_ADDR))
741 /* seed is largest extant lease addr in this context */
742 start = lease_find_max_addr(c);
743 else
744 /* pick a seed based on hwaddr */
745 start.s_addr = htonl(ntohl(c->start.s_addr) +
746 ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
747
748 /* iterate until we find a free address. */
749 addr = start;
Simon Kelleycdeda282006-03-16 20:16:06 +0000750
751 do {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100752 /* eliminate addresses in use by the server. */
753 for (d = context; d; d = d->current)
Simon Kelley849a8352006-06-09 21:02:31 +0100754 if (addr.s_addr == d->router.s_addr)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100755 break;
756
Simon Kelley73a08a22009-02-05 20:28:08 +0000757 /* Addresses which end in .255 and .0 are broken in Windows even when using
758 supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
759 then 192.168.0.255 is a valid IP address, but not for Windows as it's
760 in the class C range. See KB281579. We therefore don't allocate these
761 addresses to avoid hard-to-diagnose problems. Thanks Bill. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100762 if (!d &&
763 !lease_find_by_addr(addr) &&
Simon Kelley73a08a22009-02-05 20:28:08 +0000764 !config_find_by_address(daemon->dhcp_conf, addr) &&
765 (!IN_CLASSC(ntohl(addr.s_addr)) ||
766 ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
Simon Kelleycdeda282006-03-16 20:16:06 +0000767 {
Simon Kelley5ce3e762017-04-28 22:14:20 +0100768 struct ping_result *r;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100769
Simon Kelleyc7be0162017-05-10 22:21:53 +0100770 if ((r = do_icmp_ping(now, addr, j, loopback)))
Simon Kelley5ce3e762017-04-28 22:14:20 +0100771 {
772 /* consec-ip mode: we offered this address for another client
773 (different hash) recently, don't offer it to this one. */
774 if (!option_bool(OPT_CONSEC_ADDR) || r->hash == j)
Simon Kelleycdeda282006-03-16 20:16:06 +0000775 {
Simon Kelley5ce3e762017-04-28 22:14:20 +0100776 *addrp = addr;
Simon Kelley7de060b2011-08-26 17:24:52 +0100777 return 1;
Simon Kelleycdeda282006-03-16 20:16:06 +0000778 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100779 }
Simon Kelley5ce3e762017-04-28 22:14:20 +0100780 else
781 {
782 /* address in use: perturb address selection so that we are
783 less likely to try this address again. */
784 if (!option_bool(OPT_CONSEC_ADDR))
785 c->addr_epoch++;
786 }
Simon Kelleycdeda282006-03-16 20:16:06 +0000787 }
Simon Kelley5ce3e762017-04-28 22:14:20 +0100788
Simon Kelleycdeda282006-03-16 20:16:06 +0000789 addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
790
791 if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
792 addr = c->start;
793
794 } while (addr.s_addr != start.s_addr);
795 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100796
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000797 return 0;
798}
799
Simon Kelley5aabfc72007-08-29 11:24:47 +0100800void dhcp_read_ethers(void)
Simon Kelley1ab84e22004-01-29 16:48:35 +0000801{
Simon Kelley44a2a312004-03-10 20:04:35 +0000802 FILE *f = fopen(ETHERSFILE, "r");
Simon Kelley0a852542005-03-23 20:28:59 +0000803 unsigned int flags;
Simon Kelley3be34542004-09-11 19:12:13 +0100804 char *buff = daemon->namebuff;
Simon Kelley33820b72004-04-03 21:10:00 +0100805 char *ip, *cp;
Simon Kelley44a2a312004-03-10 20:04:35 +0000806 struct in_addr addr;
Simon Kelley33820b72004-04-03 21:10:00 +0100807 unsigned char hwaddr[ETHER_ADDR_LEN];
Simon Kelley849a8352006-06-09 21:02:31 +0100808 struct dhcp_config **up, *tmp;
Simon Kelley16972692006-10-16 20:04:18 +0100809 struct dhcp_config *config;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000810 int count = 0, lineno = 0;
Simon Kelley3d8df262005-08-29 12:19:27 +0100811
812 addr.s_addr = 0; /* eliminate warning */
Simon Kelley44a2a312004-03-10 20:04:35 +0000813
814 if (!f)
Simon Kelley33820b72004-04-03 21:10:00 +0100815 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100816 my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
Simon Kelley3be34542004-09-11 19:12:13 +0100817 return;
Simon Kelley33820b72004-04-03 21:10:00 +0100818 }
819
Simon Kelley849a8352006-06-09 21:02:31 +0100820 /* This can be called again on SIGHUP, so remove entries created last time round. */
Simon Kelley16972692006-10-16 20:04:18 +0100821 for (up = &daemon->dhcp_conf, config = daemon->dhcp_conf; config; config = tmp)
Simon Kelley849a8352006-06-09 21:02:31 +0100822 {
823 tmp = config->next;
824 if (config->flags & CONFIG_FROM_ETHERS)
825 {
826 *up = tmp;
827 /* cannot have a clid */
828 if (config->flags & CONFIG_NAME)
829 free(config->hostname);
Simon Kelley9009d742008-11-14 20:04:27 +0000830 free(config->hwaddr);
Simon Kelley849a8352006-06-09 21:02:31 +0100831 free(config);
832 }
833 else
834 up = &config->next;
835 }
836
Simon Kelley44a2a312004-03-10 20:04:35 +0000837 while (fgets(buff, MAXDNAME, f))
838 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100839 char *host = NULL;
840
Simon Kelleyb8187c82005-11-26 21:46:27 +0000841 lineno++;
842
Simon Kelley824af852008-02-12 20:43:05 +0000843 while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
Simon Kelley44a2a312004-03-10 20:04:35 +0000844 buff[strlen(buff)-1] = 0;
845
Simon Kelley73a08a22009-02-05 20:28:08 +0000846 if ((*buff == '#') || (*buff == '+') || (*buff == 0))
Simon Kelley44a2a312004-03-10 20:04:35 +0000847 continue;
848
Simon Kelley824af852008-02-12 20:43:05 +0000849 for (ip = buff; *ip && !isspace((int)*ip); ip++);
850 for(; *ip && isspace((int)*ip); ip++)
Simon Kelley44a2a312004-03-10 20:04:35 +0000851 *ip = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +0000852 if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000853 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100854 my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000855 continue;
856 }
Simon Kelley44a2a312004-03-10 20:04:35 +0000857
858 /* check for name or dotted-quad */
859 for (cp = ip; *cp; cp++)
860 if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
861 break;
862
863 if (!*cp)
864 {
Simon Kelley44a2a312004-03-10 20:04:35 +0000865 if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000866 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100867 my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000868 continue;
869 }
870
Simon Kelley33820b72004-04-03 21:10:00 +0100871 flags = CONFIG_ADDR;
Simon Kelley1cff1662004-03-12 08:12:58 +0000872
Simon Kelley16972692006-10-16 20:04:18 +0100873 for (config = daemon->dhcp_conf; config; config = config->next)
Simon Kelley33820b72004-04-03 21:10:00 +0100874 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
Simon Kelley1cff1662004-03-12 08:12:58 +0000875 break;
Simon Kelley44a2a312004-03-10 20:04:35 +0000876 }
877 else
878 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100879 int nomem;
880 if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host))
Simon Kelleyb8187c82005-11-26 21:46:27 +0000881 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100882 if (!nomem)
883 my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
884 free(host);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000885 continue;
886 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100887
Simon Kelley33820b72004-04-03 21:10:00 +0100888 flags = CONFIG_NAME;
Simon Kelley1cff1662004-03-12 08:12:58 +0000889
Simon Kelley16972692006-10-16 20:04:18 +0100890 for (config = daemon->dhcp_conf; config; config = config->next)
Simon Kelley1f15b812009-10-13 17:49:32 +0100891 if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host))
Simon Kelley1cff1662004-03-12 08:12:58 +0000892 break;
Simon Kelley44a2a312004-03-10 20:04:35 +0000893 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100894
895 if (config && (config->flags & CONFIG_FROM_ETHERS))
896 {
897 my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno);
898 continue;
899 }
900
Simon Kelley1cff1662004-03-12 08:12:58 +0000901 if (!config)
902 {
Simon Kelley16972692006-10-16 20:04:18 +0100903 for (config = daemon->dhcp_conf; config; config = config->next)
Simon Kelley9009d742008-11-14 20:04:27 +0000904 {
905 struct hwaddr_config *conf_addr = config->hwaddr;
906 if (conf_addr &&
907 conf_addr->next == NULL &&
908 conf_addr->wildcard_mask == 0 &&
909 conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
910 (conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
911 memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
912 break;
913 }
Simon Kelley33820b72004-04-03 21:10:00 +0100914
915 if (!config)
916 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100917 if (!(config = whine_malloc(sizeof(struct dhcp_config))))
Simon Kelley33820b72004-04-03 21:10:00 +0100918 continue;
Simon Kelley849a8352006-06-09 21:02:31 +0100919 config->flags = CONFIG_FROM_ETHERS;
Simon Kelley9009d742008-11-14 20:04:27 +0000920 config->hwaddr = NULL;
921 config->domain = NULL;
Simon Kelleyc52e1892010-06-07 22:01:39 +0100922 config->netid = NULL;
Simon Kelley16972692006-10-16 20:04:18 +0100923 config->next = daemon->dhcp_conf;
924 daemon->dhcp_conf = config;
Simon Kelley33820b72004-04-03 21:10:00 +0100925 }
926
927 config->flags |= flags;
928
929 if (flags & CONFIG_NAME)
930 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100931 config->hostname = host;
932 host = NULL;
Simon Kelley33820b72004-04-03 21:10:00 +0100933 }
934
935 if (flags & CONFIG_ADDR)
936 config->addr = addr;
Simon Kelley1cff1662004-03-12 08:12:58 +0000937 }
Simon Kelley33820b72004-04-03 21:10:00 +0100938
Simon Kelley9009d742008-11-14 20:04:27 +0000939 config->flags |= CONFIG_NOCLID;
940 if (!config->hwaddr)
941 config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
942 if (config->hwaddr)
943 {
944 memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
945 config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
946 config->hwaddr->hwaddr_type = ARPHRD_ETHER;
947 config->hwaddr->wildcard_mask = 0;
948 config->hwaddr->next = NULL;
949 }
Simon Kelley33820b72004-04-03 21:10:00 +0100950 count++;
Simon Kelley1f15b812009-10-13 17:49:32 +0100951
952 free(host);
953
Simon Kelley44a2a312004-03-10 20:04:35 +0000954 }
955
956 fclose(f);
Simon Kelley33820b72004-04-03 21:10:00 +0100957
Simon Kelley7622fc02009-06-04 20:32:05 +0100958 my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
Simon Kelley44a2a312004-03-10 20:04:35 +0000959}
960
Simon Kelley44a2a312004-03-10 20:04:35 +0000961
Simon Kelleybb01cb92004-12-13 20:56:23 +0000962/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
963 for this address. If it has a domain part, that must match the set domain and
Simon Kelley1f15b812009-10-13 17:49:32 +0100964 it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100965 so check here that the domain name is legal as a hostname.
966 NOTE: we're only allowed to overwrite daemon->dhcp_buff if we succeed. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100967char *host_from_dns(struct in_addr addr)
Simon Kelleybb01cb92004-12-13 20:56:23 +0000968{
Simon Kelley824af852008-02-12 20:43:05 +0000969 struct crec *lookup;
Simon Kelley824af852008-02-12 20:43:05 +0000970
971 if (daemon->port == 0)
972 return NULL; /* DNS disabled. */
Simon Kelleybb01cb92004-12-13 20:56:23 +0000973
Simon Kelley824af852008-02-12 20:43:05 +0000974 lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100975
Simon Kelleybb01cb92004-12-13 20:56:23 +0000976 if (lookup && (lookup->flags & F_HOSTS))
977 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100978 char *dot, *hostname = cache_get_name(lookup);
979 dot = strchr(hostname, '.');
980
981 if (dot && strlen(dot+1) != 0)
982 {
983 char *d2 = get_domain(addr);
984 if (!d2 || !hostname_isequal(dot+1, d2))
985 return NULL; /* wrong domain */
986 }
987
988 if (!legal_hostname(hostname))
989 return NULL;
990
991 strncpy(daemon->dhcp_buff, hostname, 256);
992 daemon->dhcp_buff[255] = 0;
993 strip_hostname(daemon->dhcp_buff);
994
995 return daemon->dhcp_buff;
Simon Kelleybb01cb92004-12-13 20:56:23 +0000996 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100997
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100998 return NULL;
Simon Kelleybb01cb92004-12-13 20:56:23 +0000999}
1000
Simon Kelleyff7eea22013-09-04 18:01:38 +01001001static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
1002{
1003 /* ->local is same value for all relays on ->current chain */
1004 struct all_addr from;
1005
1006 if (mess->op != BOOTREQUEST)
1007 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +00001008
Simon Kelleyff7eea22013-09-04 18:01:38 +01001009 /* source address == relay address */
1010 from.addr.addr4 = relay->local.addr.addr4;
1011
1012 /* already gatewayed ? */
1013 if (mess->giaddr.s_addr)
1014 {
1015 /* if so check if by us, to stomp on loops. */
1016 if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
1017 return 1;
1018 }
1019 else
1020 {
1021 /* plug in our address */
1022 mess->giaddr.s_addr = relay->local.addr.addr4.s_addr;
1023 }
1024
1025 if ((mess->hops++) > 20)
1026 return 1;
1027
1028 for (; relay; relay = relay->current)
1029 {
1030 union mysockaddr to;
1031
1032 to.sa.sa_family = AF_INET;
1033 to.in.sin_addr = relay->server.addr.addr4;
1034 to.in.sin_port = htons(daemon->dhcp_server_port);
1035
1036 send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
1037
1038 if (option_bool(OPT_LOG_OPTS))
1039 {
1040 inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
1041 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, inet_ntoa(relay->server.addr.addr4));
1042 }
1043
1044 /* Save this for replies */
1045 relay->iface_index = iface_index;
1046 }
1047
1048 return 1;
1049}
1050
1051
1052static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
1053{
1054 struct dhcp_relay *relay;
1055
1056 if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
1057 return NULL;
1058
1059 for (relay = daemon->relay4; relay; relay = relay->next)
1060 {
1061 if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
1062 {
1063 if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
1064 return relay->iface_index != 0 ? relay : NULL;
1065 }
1066 }
1067
1068 return NULL;
1069}
1070
1071#endif