blob: e500bc2fbb88d7d174576a8952e48946b0243268 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* dnsmasq is Copyright (c) 2000-2021 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, or
6 (at your option) version 3 dated 29 June, 2007.
7
8 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.
12
13 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/>.
15*/
16
17#include "dnsmasq.h"
18
19#ifdef HAVE_DHCP
20
21struct iface_param {
22 struct dhcp_context *current;
23 struct dhcp_relay *relay;
24 struct in_addr relay_local;
25 int ind;
26};
27
28struct match_param {
29 int ind, matched;
30 struct in_addr netmask, broadcast, addr;
31};
32
33static int complete_context(struct in_addr local, int if_index, char *label,
34 struct in_addr netmask, struct in_addr broadcast, void *vparam);
35static int check_listen_addrs(struct in_addr local, int if_index, char *label,
36 struct in_addr netmask, struct in_addr broadcast, void *vparam);
37static 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);
39
40static int make_fd(int port)
41{
42 int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
43 struct sockaddr_in saddr;
44 int oneopt = 1;
45#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
46 int mtu = IP_PMTUDISC_DONT;
47#endif
48#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
49 int tos = IPTOS_CLASS_CS6;
50#endif
51
52 if (fd == -1)
53 die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
54
55 if (!fix_fd(fd) ||
56#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
57 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 ||
61#endif
62#if defined(HAVE_LINUX_NETWORK)
63 setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
64#else
65 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
66#endif
67 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
68 die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET);
69
70 /* When bind-interfaces is set, there might be more than one dnsmasq
71 instance binding port 67. That's OK if they serve different networks.
72 Need to set REUSEADDR|REUSEPORT to make this possible.
73 Handle the case that REUSEPORT is defined, but the kernel doesn't
74 support it. This handles the introduction of REUSEPORT on Linux. */
75 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
76 {
77 int rc = 0;
78
79#ifdef SO_REUSEPORT
80 if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
81 errno == ENOPROTOOPT)
82 rc = 0;
83#endif
84
85 if (rc != -1)
86 rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
87
88 if (rc == -1)
89 die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
90 }
91
92 memset(&saddr, 0, sizeof(saddr));
93 saddr.sin_family = AF_INET;
94 saddr.sin_port = htons(port);
95 saddr.sin_addr.s_addr = INADDR_ANY;
96#ifdef HAVE_SOCKADDR_SA_LEN
97 saddr.sin_len = sizeof(struct sockaddr_in);
98#endif
99
100 if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
101 die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
102
103 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;
117
118#if defined(HAVE_BSD_NETWORK)
119 /* 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 */
122
123 if (option_bool(OPT_NO_PING))
124 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 )
127 die(_("cannot create ICMP raw socket: %s."), NULL, EC_BADNET);
128
129 /* Make BPF raw send socket */
130 init_bpf();
131#endif
132}
133
134void dhcp_packet(time_t now, int pxe_fd)
135{
136 int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
137 struct dhcp_packet *mess;
138 struct dhcp_context *context;
139 struct dhcp_relay *relay;
140 int is_relay_reply = 0;
141 struct iname *tmp;
142 struct ifreq ifr;
143 struct msghdr msg;
144 struct sockaddr_in dest;
145 struct cmsghdr *cmptr;
146 struct iovec iov;
147 ssize_t sz;
148 int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
149 int rcvd_iface_index;
150 struct in_addr iface_addr;
151 struct iface_param parm;
152 time_t recvtime = now;
153#ifdef HAVE_LINUX_NETWORK
154 struct arpreq arp_req;
155 struct timeval tv;
156#endif
157
158 union {
159 struct cmsghdr align; /* this ensures alignment */
160#if defined(HAVE_LINUX_NETWORK)
161 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
162#elif defined(HAVE_SOLARIS_NETWORK)
163 char control[CMSG_SPACE(sizeof(unsigned int))];
164#elif defined(HAVE_BSD_NETWORK)
165 char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
166#endif
167 } control_u;
168 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);
174 msg.msg_iov = &daemon->dhcp_packet;
175 msg.msg_iovlen = 1;
176
177 if ((sz = recv_dhcp_packet(fd, &msg)) == -1 ||
178 (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
179 return;
180
181 #if defined (HAVE_LINUX_NETWORK)
182 if (ioctl(fd, SIOCGSTAMP, &tv) == 0)
183 recvtime = tv.tv_sec;
184
185 if (msg.msg_controllen >= sizeof(struct cmsghdr))
186 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
187 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
188 {
189 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)
196 unicast_dest = 1;
197 }
198
199#elif defined(HAVE_BSD_NETWORK)
200 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)
203 {
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 }
211
212#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)
216 {
217 union {
218 unsigned char *c;
219 unsigned int *i;
220 } p;
221 p.c = CMSG_DATA(cmptr);
222 iface_index = *(p.i);
223 }
224#endif
225
226 if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name) ||
227 ioctl(daemon->dhcpfd, SIOCGIFFLAGS, &ifr) != 0)
228 return;
229
230 mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
231 loopback = !mess->giaddr.s_addr && (ifr.ifr_flags & IFF_LOOPBACK);
232
233#ifdef HAVE_LINUX_NETWORK
234 /* ARP fiddling uses original interface even if we pretend to use a different one. */
235 safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
236#endif
237
238 /* 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. */
243 rcvd_iface_index = iface_index;
244 for (bridge = daemon->bridges; bridge; bridge = bridge->next)
245 {
246 for (alias = bridge->alias; alias; alias = alias->next)
247 if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
248 {
249 if (!(iface_index = if_nametoindex(bridge->iface)))
250 {
251 my_syslog(MS_DHCP | LOG_WARNING,
252 _("unknown interface %s in bridge-interface"),
253 bridge->iface);
254 return;
255 }
256 else
257 {
258 safe_strncpy(ifr.ifr_name, bridge->iface, sizeof(ifr.ifr_name));
259 break;
260 }
261 }
262
263 if (alias)
264 break;
265 }
266
267#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
272
273 if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
274 {
275 /* Reply from server, using us as relay. */
276 rcvd_iface_index = relay->iface_index;
277 if (!indextoname(daemon->dhcpfd, rcvd_iface_index, ifr.ifr_name))
278 return;
279 is_relay_reply = 1;
280 iov.iov_len = sz;
281#ifdef HAVE_LINUX_NETWORK
282 safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
283#endif
284 }
285 else
286 {
287 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 {
292 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);
294 return;
295 }
296
297 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
298 if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
299 return;
300
301 /* 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, (union 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))
334 return;
335
336 /* We're relaying this request */
337 if (parm.relay_local.s_addr != 0 &&
338 relay_upstream4(parm.relay, mess, (size_t)sz, iface_index))
339 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,
347 now, unicast_dest, loopback, &is_inform, pxe_fd, iface_addr, recvtime);
348 lease_update_file(now);
349 lease_update_dns(0);
350
351 if (iov.iov_len == 0)
352 return;
353 }
354
355 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 */
363 mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
364
365#ifdef HAVE_SOCKADDR_SA_LEN
366 dest.sin_len = sizeof(struct sockaddr_in);
367#endif
368
369 if (pxe_fd)
370 {
371 if (mess->ciaddr.s_addr != 0)
372 dest.sin_addr = mess->ciaddr;
373 }
374 else if (mess->giaddr.s_addr && !is_relay_reply)
375 {
376 /* Send to BOOTP relay */
377 dest.sin_port = htons(daemon->dhcp_server_port);
378 dest.sin_addr = mess->giaddr;
379 }
380 else if (mess->ciaddr.s_addr)
381 {
382 /* If the client's idea of its own address tallys with
383 the source address in the request packet, we believe the
384 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) ||
387 dest.sin_port == 0 || dest.sin_addr.s_addr == 0 || is_relay_reply)
388 {
389 dest.sin_port = htons(daemon->dhcp_client_port);
390 dest.sin_addr = mess->ciaddr;
391 }
392 }
393#if defined(HAVE_LINUX_NETWORK)
394 else
395 {
396 /* fill cmsg for outbound interface (both broadcast & unicast) */
397 struct in_pktinfo *pkt;
398 msg.msg_control = control_u.control;
399 msg.msg_controllen = sizeof(control_u);
400 cmptr = CMSG_FIRSTHDR(&msg);
401 pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
402 pkt->ipi_ifindex = rcvd_iface_index;
403 pkt->ipi_spec_dst.s_addr = 0;
404 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
405 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
406 cmptr->cmsg_level = IPPROTO_IP;
407 cmptr->cmsg_type = IP_PKTINFO;
408
409 if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
410 mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
411 {
412 /* broadcast to 255.255.255.255 (or mac address invalid) */
413 dest.sin_addr.s_addr = INADDR_BROADCAST;
414 dest.sin_port = htons(daemon->dhcp_client_port);
415 }
416 else
417 {
418 /* unicast to unconfigured client. Inject mac address direct into ARP cache.
419 struct sockaddr limits size to 14 bytes. */
420 dest.sin_addr = mess->yiaddr;
421 dest.sin_port = htons(daemon->dhcp_client_port);
422 memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
423 arp_req.arp_ha.sa_family = mess->htype;
424 memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
425 /* interface name already copied in */
426 arp_req.arp_flags = ATF_COM;
427 if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
428 my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
429 }
430 }
431#elif defined(HAVE_SOLARIS_NETWORK)
432 else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
433 {
434 /* broadcast to 255.255.255.255 (or mac address invalid) */
435 dest.sin_addr.s_addr = INADDR_BROADCAST;
436 dest.sin_port = htons(daemon->dhcp_client_port);
437 /* note that we don't specify the interface here: that's done by the
438 IP_BOUND_IF sockopt lower down. */
439 }
440 else
441 {
442 /* unicast to unconfigured client. Inject mac address direct into ARP cache.
443 Note that this only works for ethernet on solaris, because we use SIOCSARP
444 and not SIOCSXARP, which would be perfect, except that it returns ENXIO
445 mysteriously. Bah. Fall back to broadcast for other net types. */
446 struct arpreq req;
447 dest.sin_addr = mess->yiaddr;
448 dest.sin_port = htons(daemon->dhcp_client_port);
449 *((struct sockaddr_in *)&req.arp_pa) = dest;
450 req.arp_ha.sa_family = AF_UNSPEC;
451 memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
452 req.arp_flags = ATF_COM;
453 ioctl(daemon->dhcpfd, SIOCSARP, &req);
454 }
455#elif defined(HAVE_BSD_NETWORK)
456 else
457 {
458 send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
459 return;
460 }
461#endif
462
463#ifdef HAVE_SOLARIS_NETWORK
464 setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
465#endif
466
467 while(retry_send(sendmsg(fd, &msg, 0)));
468
469 /* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
470 if (errno != 0)
471 {
472 inet_ntop(AF_INET, &dest.sin_addr, daemon->addrbuff, ADDRSTRLEN);
473 my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
474 daemon->addrbuff, strerror(errno));
475 }
476}
477
478/* check against secondary interface addresses */
479static int check_listen_addrs(struct in_addr local, int if_index, char *label,
480 struct in_addr netmask, struct in_addr broadcast, void *vparam)
481{
482 struct match_param *param = vparam;
483 struct iname *tmp;
484
485 (void) label;
486
487 if (if_index == param->ind)
488 {
489 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
490 if ( tmp->addr.sa.sa_family == AF_INET &&
491 tmp->addr.in.sin_addr.s_addr == local.s_addr)
492 {
493 param->matched = 1;
494 param->addr = local;
495 param->netmask = netmask;
496 param->broadcast = broadcast;
497 break;
498 }
499 }
500
501 return 1;
502}
503
504/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
505 of each interface (and any relay address) and does the following things:
506
507 1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
508 2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
509 3) Fills in local (this host) and router (this host or relay) addresses.
510 4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
511
512 Note that the current chain may be superseded later for configured hosts or those coming via gateways. */
513
514static void guess_range_netmask(struct in_addr addr, struct in_addr netmask)
515{
516 struct dhcp_context *context;
517
518 for (context = daemon->dhcp; context; context = context->next)
519 if (!(context->flags & CONTEXT_NETMASK) &&
520 (is_same_net(addr, context->start, netmask) ||
521 is_same_net(addr, context->end, netmask)))
522 {
523 if (context->netmask.s_addr != netmask.s_addr &&
524 !(is_same_net(addr, context->start, netmask) &&
525 is_same_net(addr, context->end, netmask)))
526 {
527 inet_ntop(AF_INET, &context->start, daemon->dhcp_buff, DHCP_BUFF_SZ);
528 inet_ntop(AF_INET, &context->end, daemon->dhcp_buff2, DHCP_BUFF_SZ);
529 inet_ntop(AF_INET, &netmask, daemon->addrbuff, ADDRSTRLEN);
530 my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
531 daemon->dhcp_buff, daemon->dhcp_buff2, daemon->addrbuff);
532 }
533 context->netmask = netmask;
534 }
535}
536
537static int complete_context(struct in_addr local, int if_index, char *label,
538 struct in_addr netmask, struct in_addr broadcast, void *vparam)
539{
540 struct dhcp_context *context;
541 struct dhcp_relay *relay;
542 struct iface_param *param = vparam;
543 struct shared_network *share;
544
545 (void)label;
546
547 for (share = daemon->shared_networks; share; share = share->next)
548 {
549
550#ifdef HAVE_DHCP6
551 if (share->shared_addr.s_addr == 0)
552 continue;
553#endif
554
555 if (share->if_index != 0)
556 {
557 if (share->if_index != if_index)
558 continue;
559 }
560 else
561 {
562 if (share->match_addr.s_addr != local.s_addr)
563 continue;
564 }
565
566 for (context = daemon->dhcp; context; context = context->next)
567 {
568 if (context->netmask.s_addr != 0 &&
569 is_same_net(share->shared_addr, context->start, context->netmask) &&
570 is_same_net(share->shared_addr, context->end, context->netmask))
571 {
572 /* link it onto the current chain if we've not seen it before */
573 if (context->current == context)
574 {
575 /* For a shared network, we have no way to guess what the default route should be. */
576 context->router.s_addr = 0;
577 context->local = local; /* Use configured address for Server Identifier */
578 context->current = param->current;
579 param->current = context;
580 }
581
582 if (!(context->flags & CONTEXT_BRDCAST))
583 context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
584 }
585 }
586 }
587
588 guess_range_netmask(local, netmask);
589
590 for (context = daemon->dhcp; context; context = context->next)
591 {
592 if (context->netmask.s_addr != 0 &&
593 is_same_net(local, context->start, context->netmask) &&
594 is_same_net(local, context->end, context->netmask))
595 {
596 /* link it onto the current chain if we've not seen it before */
597 if (if_index == param->ind && context->current == context)
598 {
599 context->router = local;
600 context->local = local;
601 context->current = param->current;
602 param->current = context;
603 }
604
605 if (!(context->flags & CONTEXT_BRDCAST))
606 {
607 if (is_same_net(broadcast, context->start, context->netmask))
608 context->broadcast = broadcast;
609 else
610 context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
611 }
612 }
613 }
614
615 for (relay = daemon->relay4; relay; relay = relay->next)
616 if (if_index == param->ind && relay->local.addr4.s_addr == local.s_addr && relay->current == relay &&
617 (param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr))
618 {
619 relay->current = param->relay;
620 param->relay = relay;
621 param->relay_local = local;
622 }
623
624 return 1;
625}
626
627struct dhcp_context *address_available(struct dhcp_context *context,
628 struct in_addr taddr,
629 struct dhcp_netid *netids)
630{
631 /* Check is an address is OK for this network, check all
632 possible ranges. Make sure that the address isn't in use
633 by the server itself. */
634
635 unsigned int start, end, addr = ntohl(taddr.s_addr);
636 struct dhcp_context *tmp;
637
638 for (tmp = context; tmp; tmp = tmp->current)
639 if (taddr.s_addr == context->router.s_addr)
640 return NULL;
641
642 for (tmp = context; tmp; tmp = tmp->current)
643 {
644 start = ntohl(tmp->start.s_addr);
645 end = ntohl(tmp->end.s_addr);
646
647 if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
648 addr >= start &&
649 addr <= end &&
650 match_netid(tmp->filter, netids, 1))
651 return tmp;
652 }
653
654 return NULL;
655}
656
657struct dhcp_context *narrow_context(struct dhcp_context *context,
658 struct in_addr taddr,
659 struct dhcp_netid *netids)
660{
661 /* We start of with a set of possible contexts, all on the current physical interface.
662 These are chained on ->current.
663 Here we have an address, and return the actual context corresponding to that
664 address. Note that none may fit, if the address came a dhcp-host and is outside
665 any dhcp-range. In that case we return a static range if possible, or failing that,
666 any context on the correct subnet. (If there's more than one, this is a dodgy
667 configuration: maybe there should be a warning.) */
668
669 struct dhcp_context *tmp;
670
671 if (!(tmp = address_available(context, taddr, netids)))
672 {
673 for (tmp = context; tmp; tmp = tmp->current)
674 if (match_netid(tmp->filter, netids, 1) &&
675 is_same_net(taddr, tmp->start, tmp->netmask) &&
676 (tmp->flags & CONTEXT_STATIC))
677 break;
678
679 if (!tmp)
680 for (tmp = context; tmp; tmp = tmp->current)
681 if (match_netid(tmp->filter, netids, 1) &&
682 is_same_net(taddr, tmp->start, tmp->netmask) &&
683 !(tmp->flags & CONTEXT_PROXY))
684 break;
685 }
686
687 /* Only one context allowed now */
688 if (tmp)
689 tmp->current = NULL;
690
691 return tmp;
692}
693
694struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
695{
696 struct dhcp_config *config;
697
698 for (config = configs; config; config = config->next)
699 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
700 return config;
701
702 return NULL;
703}
704
705/* Check if and address is in use by sending ICMP ping.
706 This wrapper handles a cache and load-limiting.
707 Return is NULL is address in use, or a pointer to a cache entry
708 recording that it isn't. */
709struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash, int loopback)
710{
711 static struct ping_result dummy;
712 struct ping_result *r, *victim = NULL;
713 int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
714 ((float)PING_WAIT)));
715
716 /* check if we failed to ping addr sometime in the last
717 PING_CACHE_TIME seconds. If so, assume the same situation still exists.
718 This avoids problems when a stupid client bangs
719 on us repeatedly. As a final check, if we did more
720 than 60% of the possible ping checks in the last
721 PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
722 for (count = 0, r = daemon->ping_results; r; r = r->next)
723 if (difftime(now, r->time) > (float)PING_CACHE_TIME)
724 victim = r; /* old record */
725 else
726 {
727 count++;
728 if (r->addr.s_addr == addr.s_addr)
729 return r;
730 }
731
732 /* didn't find cached entry */
733 if ((count >= max) || option_bool(OPT_NO_PING) || loopback)
734 {
735 /* overloaded, or configured not to check, loopback interface, return "not in use" */
736 dummy.hash = hash;
737 return &dummy;
738 }
739 else if (icmp_ping(addr))
740 return NULL; /* address in use. */
741 else
742 {
743 /* at this point victim may hold an expired record */
744 if (!victim)
745 {
746 if ((victim = whine_malloc(sizeof(struct ping_result))))
747 {
748 victim->next = daemon->ping_results;
749 daemon->ping_results = victim;
750 }
751 }
752
753 /* record that this address is OK for 30s
754 without more ping checks */
755 if (victim)
756 {
757 victim->addr = addr;
758 victim->time = now;
759 victim->hash = hash;
760 }
761 return victim;
762 }
763}
764
765int address_allocate(struct dhcp_context *context,
766 struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
767 struct dhcp_netid *netids, time_t now, int loopback)
768{
769 /* Find a free address: exclude anything in use and anything allocated to
770 a particular hwaddr/clientid/hostname in our configuration.
771 Try to return from contexts which match netids first. */
772
773 struct in_addr start, addr;
774 struct dhcp_context *c, *d;
775 int i, pass;
776 unsigned int j;
777
778 /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good
779 dispersal even with similarly-valued "strings". */
780 for (j = 0, i = 0; i < hw_len; i++)
781 j = hwaddr[i] + (j << 6) + (j << 16) - j;
782
783 /* j == 0 is marker */
784 if (j == 0)
785 j = 1;
786
787 for (pass = 0; pass <= 1; pass++)
788 for (c = context; c; c = c->current)
789 if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
790 continue;
791 else if (!match_netid(c->filter, netids, pass))
792 continue;
793 else
794 {
795 if (option_bool(OPT_CONSEC_ADDR))
796 /* seed is largest extant lease addr in this context */
797 start = lease_find_max_addr(c);
798 else
799 /* pick a seed based on hwaddr */
800 start.s_addr = htonl(ntohl(c->start.s_addr) +
801 ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
802
803 /* iterate until we find a free address. */
804 addr = start;
805
806 do {
807 /* eliminate addresses in use by the server. */
808 for (d = context; d; d = d->current)
809 if (addr.s_addr == d->router.s_addr)
810 break;
811
812 /* Addresses which end in .255 and .0 are broken in Windows even when using
813 supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
814 then 192.168.0.255 is a valid IP address, but not for Windows as it's
815 in the class C range. See KB281579. We therefore don't allocate these
816 addresses to avoid hard-to-diagnose problems. Thanks Bill. */
817 if (!d &&
818 !lease_find_by_addr(addr) &&
819 !config_find_by_address(daemon->dhcp_conf, addr) &&
820 (!IN_CLASSC(ntohl(addr.s_addr)) ||
821 ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
822 {
823 /* in consec-ip mode, skip addresses equal to
824 the number of addresses rejected by clients. This
825 should avoid the same client being offered the same
826 address after it has rjected it. */
827 if (option_bool(OPT_CONSEC_ADDR) && c->addr_epoch)
828 c->addr_epoch--;
829 else
830 {
831 struct ping_result *r;
832
833 if ((r = do_icmp_ping(now, addr, j, loopback)))
834 {
835 /* consec-ip mode: we offered this address for another client
836 (different hash) recently, don't offer it to this one. */
837 if (!option_bool(OPT_CONSEC_ADDR) || r->hash == j)
838 {
839 *addrp = addr;
840 return 1;
841 }
842 }
843 else
844 {
845 /* address in use: perturb address selection so that we are
846 less likely to try this address again. */
847 if (!option_bool(OPT_CONSEC_ADDR))
848 c->addr_epoch++;
849 }
850 }
851 }
852
853 addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
854
855 if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
856 addr = c->start;
857
858 } while (addr.s_addr != start.s_addr);
859 }
860
861 return 0;
862}
863
864void dhcp_read_ethers(void)
865{
866 FILE *f = fopen(ETHERSFILE, "r");
867 unsigned int flags;
868 char *buff = daemon->namebuff;
869 char *ip, *cp;
870 struct in_addr addr;
871 unsigned char hwaddr[ETHER_ADDR_LEN];
872 struct dhcp_config **up, *tmp;
873 struct dhcp_config *config;
874 int count = 0, lineno = 0;
875
876 addr.s_addr = 0; /* eliminate warning */
877
878 if (!f)
879 {
880 my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
881 return;
882 }
883
884 /* This can be called again on SIGHUP, so remove entries created last time round. */
885 for (up = &daemon->dhcp_conf, config = daemon->dhcp_conf; config; config = tmp)
886 {
887 tmp = config->next;
888 if (config->flags & CONFIG_FROM_ETHERS)
889 {
890 *up = tmp;
891 /* cannot have a clid */
892 if (config->flags & CONFIG_NAME)
893 free(config->hostname);
894 free(config->hwaddr);
895 free(config);
896 }
897 else
898 up = &config->next;
899 }
900
901 while (fgets(buff, MAXDNAME, f))
902 {
903 char *host = NULL;
904
905 lineno++;
906
907 while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
908 buff[strlen(buff)-1] = 0;
909
910 if ((*buff == '#') || (*buff == '+') || (*buff == 0))
911 continue;
912
913 for (ip = buff; *ip && !isspace((int)*ip); ip++);
914 for(; *ip && isspace((int)*ip); ip++)
915 *ip = 0;
916 if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
917 {
918 my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
919 continue;
920 }
921
922 /* check for name or dotted-quad */
923 for (cp = ip; *cp; cp++)
924 if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
925 break;
926
927 if (!*cp)
928 {
929 if (inet_pton(AF_INET, ip, &addr.s_addr) < 1)
930 {
931 my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
932 continue;
933 }
934
935 flags = CONFIG_ADDR;
936
937 for (config = daemon->dhcp_conf; config; config = config->next)
938 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
939 break;
940 }
941 else
942 {
943 int nomem;
944 if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host))
945 {
946 if (!nomem)
947 my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
948 free(host);
949 continue;
950 }
951
952 flags = CONFIG_NAME;
953
954 for (config = daemon->dhcp_conf; config; config = config->next)
955 if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host))
956 break;
957 }
958
959 if (config && (config->flags & CONFIG_FROM_ETHERS))
960 {
961 my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno);
962 continue;
963 }
964
965 if (!config)
966 {
967 for (config = daemon->dhcp_conf; config; config = config->next)
968 {
969 struct hwaddr_config *conf_addr = config->hwaddr;
970 if (conf_addr &&
971 conf_addr->next == NULL &&
972 conf_addr->wildcard_mask == 0 &&
973 conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
974 (conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
975 memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
976 break;
977 }
978
979 if (!config)
980 {
981 if (!(config = whine_malloc(sizeof(struct dhcp_config))))
982 continue;
983 config->flags = CONFIG_FROM_ETHERS;
984 config->hwaddr = NULL;
985 config->domain = NULL;
986 config->netid = NULL;
987 config->next = daemon->dhcp_conf;
988 daemon->dhcp_conf = config;
989 }
990
991 config->flags |= flags;
992
993 if (flags & CONFIG_NAME)
994 {
995 config->hostname = host;
996 host = NULL;
997 }
998
999 if (flags & CONFIG_ADDR)
1000 config->addr = addr;
1001 }
1002
1003 config->flags |= CONFIG_NOCLID;
1004 if (!config->hwaddr)
1005 config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
1006 if (config->hwaddr)
1007 {
1008 memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
1009 config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
1010 config->hwaddr->hwaddr_type = ARPHRD_ETHER;
1011 config->hwaddr->wildcard_mask = 0;
1012 config->hwaddr->next = NULL;
1013 }
1014 count++;
1015
1016 free(host);
1017
1018 }
1019
1020 fclose(f);
1021
1022 my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
1023}
1024
1025
1026/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
1027 for this address. If it has a domain part, that must match the set domain and
1028 it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
1029 so check here that the domain name is legal as a hostname.
1030 NOTE: we're only allowed to overwrite daemon->dhcp_buff if we succeed. */
1031char *host_from_dns(struct in_addr addr)
1032{
1033 struct crec *lookup;
1034
1035 if (daemon->port == 0)
1036 return NULL; /* DNS disabled. */
1037
1038 lookup = cache_find_by_addr(NULL, (union all_addr *)&addr, 0, F_IPV4);
1039
1040 if (lookup && (lookup->flags & F_HOSTS))
1041 {
1042 char *dot, *hostname = cache_get_name(lookup);
1043 dot = strchr(hostname, '.');
1044
1045 if (dot && strlen(dot+1) != 0)
1046 {
1047 char *d2 = get_domain(addr);
1048 if (!d2 || !hostname_isequal(dot+1, d2))
1049 return NULL; /* wrong domain */
1050 }
1051
1052 if (!legal_hostname(hostname))
1053 return NULL;
1054
1055 safe_strncpy(daemon->dhcp_buff, hostname, 256);
1056 strip_hostname(daemon->dhcp_buff);
1057
1058 return daemon->dhcp_buff;
1059 }
1060
1061 return NULL;
1062}
1063
1064static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
1065{
1066 /* ->local is same value for all relays on ->current chain */
1067 union all_addr from;
1068
1069 if (mess->op != BOOTREQUEST)
1070 return 0;
1071
1072 /* source address == relay address */
1073 from.addr4 = relay->local.addr4;
1074
1075 /* already gatewayed ? */
1076 if (mess->giaddr.s_addr)
1077 {
1078 /* if so check if by us, to stomp on loops. */
1079 if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
1080 return 1;
1081 }
1082 else
1083 {
1084 /* plug in our address */
1085 mess->giaddr.s_addr = relay->local.addr4.s_addr;
1086 }
1087
1088 if ((mess->hops++) > 20)
1089 return 1;
1090
1091 for (; relay; relay = relay->current)
1092 {
1093 union mysockaddr to;
1094
1095 to.sa.sa_family = AF_INET;
1096 to.in.sin_addr = relay->server.addr4;
1097 to.in.sin_port = htons(daemon->dhcp_server_port);
1098
1099 send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
1100
1101 if (option_bool(OPT_LOG_OPTS))
1102 {
1103 inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
1104 inet_ntop(AF_INET, &relay->server.addr4, daemon->dhcp_buff2, DHCP_BUFF_SZ);
1105 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->dhcp_buff2);
1106 }
1107
1108 /* Save this for replies */
1109 relay->iface_index = iface_index;
1110 }
1111
1112 return 1;
1113}
1114
1115
1116static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
1117{
1118 struct dhcp_relay *relay;
1119
1120 if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
1121 return NULL;
1122
1123 for (relay = daemon->relay4; relay; relay = relay->next)
1124 {
1125 if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
1126 {
1127 if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
1128 return relay->iface_index != 0 ? relay : NULL;
1129 }
1130 }
1131
1132 return NULL;
1133}
1134
1135#endif