Annotation of embedaddon/dnsmasq/src/dhcp.c, revision 1.1.1.4
1.1.1.4 ! misho 1: /* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
1.1 misho 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:
21: struct iface_param {
22: struct dhcp_context *current;
1.1.1.2 misho 23: struct dhcp_relay *relay;
24: struct in_addr relay_local;
1.1 misho 25: int ind;
26: };
27:
28: struct match_param {
29: int ind, matched;
30: struct in_addr netmask, broadcast, addr;
31: };
32:
1.1.1.2 misho 33: static int complete_context(struct in_addr local, int if_index, char *label,
1.1 misho 34: struct in_addr netmask, struct in_addr broadcast, void *vparam);
1.1.1.2 misho 35: static int check_listen_addrs(struct in_addr local, int if_index, char *label,
1.1 misho 36: struct in_addr netmask, struct in_addr broadcast, void *vparam);
1.1.1.2 misho 37: static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index);
38: static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
1.1 misho 39:
40: static 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:
1.1.1.4 ! misho 70: /* When bind-interfaces is set, there might be more than one dnsmasq
1.1 misho 71: instance binding port 67. That's OK if they serve different networks.
1.1.1.4 ! misho 72: Need to set REUSEADDR|REUSEPORT to make this possible.
1.1 misho 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: {
1.1.1.2 misho 77: int rc = 0;
1.1 misho 78:
79: #ifdef SO_REUSEPORT
80: if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
1.1.1.2 misho 81: errno == ENOPROTOOPT)
82: rc = 0;
1.1 misho 83: #endif
84:
1.1.1.2 misho 85: if (rc != -1)
1.1 misho 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:
106: void 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:
134: void 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;
1.1.1.2 misho 139: struct dhcp_relay *relay;
140: int is_relay_reply = 0;
1.1 misho 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;
1.1.1.4 ! misho 148: int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
1.1.1.3 misho 149: int rcvd_iface_index;
1.1 misho 150: struct in_addr iface_addr;
151: struct iface_param parm;
1.1.1.4 ! misho 152: time_t recvtime = now;
1.1 misho 153: #ifdef HAVE_LINUX_NETWORK
154: struct arpreq arp_req;
1.1.1.4 ! misho 155: struct timeval tv;
1.1 misho 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)
1.1.1.4 ! misho 182: if (ioctl(fd, SIOCGSTAMP, &tv) == 0)
! 183: recvtime = tv.tv_sec;
! 184:
1.1 misho 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:
1.1.1.4 ! misho 226: if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name) ||
! 227: ioctl(daemon->dhcpfd, SIOCGIFFLAGS, &ifr) != 0)
1.1 misho 228: return;
1.1.1.4 ! misho 229:
! 230: mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
! 231: loopback = !mess->giaddr.s_addr && (ifr.ifr_flags & IFF_LOOPBACK);
! 232:
1.1 misho 233: #ifdef HAVE_LINUX_NETWORK
234: /* ARP fiddling uses original interface even if we pretend to use a different one. */
1.1.1.4 ! misho 235: safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
1.1 misho 236: #endif
237:
1.1.1.3 misho 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;
1.1 misho 244: for (bridge = daemon->bridges; bridge; bridge = bridge->next)
245: {
246: for (alias = bridge->alias; alias; alias = alias->next)
1.1.1.3 misho 247: if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
1.1 misho 248: {
249: if (!(iface_index = if_nametoindex(bridge->iface)))
250: {
1.1.1.3 misho 251: my_syslog(MS_DHCP | LOG_WARNING,
252: _("unknown interface %s in bridge-interface"),
253: bridge->iface);
1.1 misho 254: return;
255: }
256: else
257: {
1.1.1.4 ! misho 258: safe_strncpy(ifr.ifr_name, bridge->iface, sizeof(ifr.ifr_name));
1.1 misho 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:
1.1.1.2 misho 273: if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
1.1 misho 274: {
1.1.1.2 misho 275: /* Reply from server, using us as relay. */
1.1.1.4 ! misho 276: rcvd_iface_index = relay->iface_index;
! 277: if (!indextoname(daemon->dhcpfd, rcvd_iface_index, ifr.ifr_name))
1.1.1.2 misho 278: return;
279: is_relay_reply = 1;
280: iov.iov_len = sz;
281: #ifdef HAVE_LINUX_NETWORK
1.1.1.4 ! misho 282: safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
1.1.1.2 misho 283: #endif
1.1 misho 284: }
1.1.1.2 misho 285: else
1.1 misho 286: {
1.1.1.2 misho 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: {
1.1.1.4 ! misho 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);
1.1.1.2 misho 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;
1.1 misho 307:
1.1.1.2 misho 308: parm.current = NULL;
309: parm.relay = NULL;
310: parm.relay_local.s_addr = 0;
311: parm.ind = iface_index;
1.1 misho 312:
1.1.1.4 ! misho 313: if (!iface_check(AF_INET, (union all_addr *)&iface_addr, ifr.ifr_name, NULL))
1.1.1.2 misho 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 &&
1.1.1.4 ! misho 338: relay_upstream4(parm.relay, mess, (size_t)sz, iface_index))
1.1.1.2 misho 339: return;
340:
341: /* May have configured relay, but not DHCP server */
342: if (!daemon->dhcp)
1.1 misho 343: return;
344:
1.1.1.2 misho 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,
1.1.1.4 ! misho 347: now, unicast_dest, loopback, &is_inform, pxe_fd, iface_addr, recvtime);
1.1.1.2 misho 348: lease_update_file(now);
349: lease_update_dns(0);
1.1 misho 350:
1.1.1.2 misho 351: if (iov.iov_len == 0)
352: return;
353: }
1.1.1.4 ! misho 354:
1.1 misho 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: }
1.1.1.2 misho 374: else if (mess->giaddr.s_addr && !is_relay_reply)
1.1 misho 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) ||
1.1.1.2 misho 387: dest.sin_port == 0 || dest.sin_addr.s_addr == 0 || is_relay_reply)
1.1 misho 388: {
389: dest.sin_port = htons(daemon->dhcp_client_port);
390: dest.sin_addr = mess->ciaddr;
391: }
392: }
393: #if defined(HAVE_LINUX_NETWORK)
1.1.1.3 misho 394: else
1.1 misho 395: {
1.1.1.3 misho 396: /* fill cmsg for outbound interface (both broadcast & unicast) */
1.1 misho 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);
1.1.1.3 misho 402: pkt->ipi_ifindex = rcvd_iface_index;
1.1 misho 403: pkt->ipi_spec_dst.s_addr = 0;
1.1.1.4 ! misho 404: msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
! 405: cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
1.1 misho 406: cmptr->cmsg_level = IPPROTO_IP;
1.1.1.3 misho 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: }
1.1 misho 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:
1.1.1.3 misho 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: my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
472: inet_ntoa(dest.sin_addr), strerror(errno));
1.1 misho 473: }
1.1.1.3 misho 474:
1.1 misho 475: /* check against secondary interface addresses */
1.1.1.2 misho 476: static int check_listen_addrs(struct in_addr local, int if_index, char *label,
1.1 misho 477: struct in_addr netmask, struct in_addr broadcast, void *vparam)
478: {
479: struct match_param *param = vparam;
480: struct iname *tmp;
481:
1.1.1.2 misho 482: (void) label;
483:
1.1 misho 484: if (if_index == param->ind)
485: {
486: for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
487: if ( tmp->addr.sa.sa_family == AF_INET &&
488: tmp->addr.in.sin_addr.s_addr == local.s_addr)
489: {
490: param->matched = 1;
491: param->addr = local;
492: param->netmask = netmask;
493: param->broadcast = broadcast;
494: break;
495: }
496: }
497:
498: return 1;
499: }
500:
501: /* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
502: of each interface (and any relay address) and does the following things:
503:
504: 1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
505: 2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
506: 3) Fills in local (this host) and router (this host or relay) addresses.
507: 4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
508:
1.1.1.4 ! misho 509: Note that the current chain may be superseded later for configured hosts or those coming via gateways. */
1.1 misho 510:
1.1.1.4 ! misho 511: static void guess_range_netmask(struct in_addr addr, struct in_addr netmask)
1.1 misho 512: {
513: struct dhcp_context *context;
1.1.1.2 misho 514:
1.1 misho 515: for (context = daemon->dhcp; context; context = context->next)
1.1.1.4 ! misho 516: if (!(context->flags & CONTEXT_NETMASK) &&
! 517: (is_same_net(addr, context->start, netmask) ||
! 518: is_same_net(addr, context->end, netmask)))
1.1 misho 519: {
520: if (context->netmask.s_addr != netmask.s_addr &&
1.1.1.4 ! misho 521: !(is_same_net(addr, context->start, netmask) &&
! 522: is_same_net(addr, context->end, netmask)))
1.1 misho 523: {
524: strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
525: strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
526: my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
527: daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
528: }
1.1.1.4 ! misho 529: context->netmask = netmask;
1.1 misho 530: }
1.1.1.4 ! misho 531: }
! 532:
! 533: static int complete_context(struct in_addr local, int if_index, char *label,
! 534: struct in_addr netmask, struct in_addr broadcast, void *vparam)
! 535: {
! 536: struct dhcp_context *context;
! 537: struct dhcp_relay *relay;
! 538: struct iface_param *param = vparam;
! 539: struct shared_network *share;
! 540:
! 541: (void)label;
! 542:
! 543: for (share = daemon->shared_networks; share; share = share->next)
! 544: {
1.1 misho 545:
1.1.1.4 ! misho 546: #ifdef HAVE_DHCP6
! 547: if (share->shared_addr.s_addr == 0)
! 548: continue;
! 549: #endif
! 550:
! 551: if (share->if_index != 0)
! 552: {
! 553: if (share->if_index != if_index)
! 554: continue;
! 555: }
! 556: else
! 557: {
! 558: if (share->match_addr.s_addr != local.s_addr)
! 559: continue;
! 560: }
! 561:
! 562: for (context = daemon->dhcp; context; context = context->next)
! 563: {
! 564: if (context->netmask.s_addr != 0 &&
! 565: is_same_net(share->shared_addr, context->start, context->netmask) &&
! 566: is_same_net(share->shared_addr, context->end, context->netmask))
! 567: {
! 568: /* link it onto the current chain if we've not seen it before */
! 569: if (context->current == context)
! 570: {
! 571: /* For a shared network, we have no way to guess what the default route should be. */
! 572: context->router.s_addr = 0;
! 573: context->local = local; /* Use configured address for Server Identifier */
! 574: context->current = param->current;
! 575: param->current = context;
! 576: }
! 577:
! 578: if (!(context->flags & CONTEXT_BRDCAST))
! 579: context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
! 580: }
! 581: }
! 582: }
! 583:
! 584: guess_range_netmask(local, netmask);
! 585:
! 586: for (context = daemon->dhcp; context; context = context->next)
! 587: {
1.1 misho 588: if (context->netmask.s_addr != 0 &&
589: is_same_net(local, context->start, context->netmask) &&
590: is_same_net(local, context->end, context->netmask))
591: {
592: /* link it onto the current chain if we've not seen it before */
593: if (if_index == param->ind && context->current == context)
594: {
595: context->router = local;
596: context->local = local;
597: context->current = param->current;
598: param->current = context;
599: }
600:
601: if (!(context->flags & CONTEXT_BRDCAST))
602: {
603: if (is_same_net(broadcast, context->start, context->netmask))
604: context->broadcast = broadcast;
605: else
606: context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
607: }
608: }
609: }
610:
1.1.1.2 misho 611: for (relay = daemon->relay4; relay; relay = relay->next)
1.1.1.4 ! misho 612: if (if_index == param->ind && relay->local.addr4.s_addr == local.s_addr && relay->current == relay &&
1.1.1.2 misho 613: (param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr))
614: {
615: relay->current = param->relay;
616: param->relay = relay;
617: param->relay_local = local;
618: }
619:
1.1 misho 620: return 1;
621: }
622:
623: struct dhcp_context *address_available(struct dhcp_context *context,
624: struct in_addr taddr,
625: struct dhcp_netid *netids)
626: {
627: /* Check is an address is OK for this network, check all
628: possible ranges. Make sure that the address isn't in use
629: by the server itself. */
630:
631: unsigned int start, end, addr = ntohl(taddr.s_addr);
632: struct dhcp_context *tmp;
633:
634: for (tmp = context; tmp; tmp = tmp->current)
635: if (taddr.s_addr == context->router.s_addr)
636: return NULL;
637:
638: for (tmp = context; tmp; tmp = tmp->current)
639: {
640: start = ntohl(tmp->start.s_addr);
641: end = ntohl(tmp->end.s_addr);
642:
643: if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
644: addr >= start &&
645: addr <= end &&
646: match_netid(tmp->filter, netids, 1))
647: return tmp;
648: }
649:
650: return NULL;
651: }
652:
653: struct dhcp_context *narrow_context(struct dhcp_context *context,
654: struct in_addr taddr,
655: struct dhcp_netid *netids)
656: {
657: /* We start of with a set of possible contexts, all on the current physical interface.
658: These are chained on ->current.
1.1.1.4 ! misho 659: Here we have an address, and return the actual context corresponding to that
1.1 misho 660: address. Note that none may fit, if the address came a dhcp-host and is outside
661: any dhcp-range. In that case we return a static range if possible, or failing that,
662: any context on the correct subnet. (If there's more than one, this is a dodgy
663: configuration: maybe there should be a warning.) */
664:
665: struct dhcp_context *tmp;
666:
667: if (!(tmp = address_available(context, taddr, netids)))
668: {
669: for (tmp = context; tmp; tmp = tmp->current)
670: if (match_netid(tmp->filter, netids, 1) &&
671: is_same_net(taddr, tmp->start, tmp->netmask) &&
672: (tmp->flags & CONTEXT_STATIC))
673: break;
674:
675: if (!tmp)
676: for (tmp = context; tmp; tmp = tmp->current)
677: if (match_netid(tmp->filter, netids, 1) &&
678: is_same_net(taddr, tmp->start, tmp->netmask) &&
679: !(tmp->flags & CONTEXT_PROXY))
680: break;
681: }
682:
683: /* Only one context allowed now */
684: if (tmp)
685: tmp->current = NULL;
686:
687: return tmp;
688: }
689:
690: struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
691: {
692: struct dhcp_config *config;
693:
694: for (config = configs; config; config = config->next)
695: if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
696: return config;
697:
698: return NULL;
699: }
700:
1.1.1.4 ! misho 701: /* Check if and address is in use by sending ICMP ping.
! 702: This wrapper handles a cache and load-limiting.
! 703: Return is NULL is address in use, or a pointer to a cache entry
! 704: recording that it isn't. */
! 705: struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash, int loopback)
! 706: {
! 707: static struct ping_result dummy;
! 708: struct ping_result *r, *victim = NULL;
! 709: int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
! 710: ((float)PING_WAIT)));
! 711:
! 712: /* check if we failed to ping addr sometime in the last
! 713: PING_CACHE_TIME seconds. If so, assume the same situation still exists.
! 714: This avoids problems when a stupid client bangs
! 715: on us repeatedly. As a final check, if we did more
! 716: than 60% of the possible ping checks in the last
! 717: PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
! 718: for (count = 0, r = daemon->ping_results; r; r = r->next)
! 719: if (difftime(now, r->time) > (float)PING_CACHE_TIME)
! 720: victim = r; /* old record */
! 721: else
! 722: {
! 723: count++;
! 724: if (r->addr.s_addr == addr.s_addr)
! 725: return r;
! 726: }
! 727:
! 728: /* didn't find cached entry */
! 729: if ((count >= max) || option_bool(OPT_NO_PING) || loopback)
! 730: {
! 731: /* overloaded, or configured not to check, loopback interface, return "not in use" */
! 732: dummy.hash = hash;
! 733: return &dummy;
! 734: }
! 735: else if (icmp_ping(addr))
! 736: return NULL; /* address in use. */
! 737: else
! 738: {
! 739: /* at this point victim may hold an expired record */
! 740: if (!victim)
! 741: {
! 742: if ((victim = whine_malloc(sizeof(struct ping_result))))
! 743: {
! 744: victim->next = daemon->ping_results;
! 745: daemon->ping_results = victim;
! 746: }
! 747: }
! 748:
! 749: /* record that this address is OK for 30s
! 750: without more ping checks */
! 751: if (victim)
! 752: {
! 753: victim->addr = addr;
! 754: victim->time = now;
! 755: victim->hash = hash;
! 756: }
! 757: return victim;
! 758: }
! 759: }
! 760:
1.1 misho 761: int address_allocate(struct dhcp_context *context,
762: struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
1.1.1.4 ! misho 763: struct dhcp_netid *netids, time_t now, int loopback)
1.1 misho 764: {
765: /* Find a free address: exclude anything in use and anything allocated to
766: a particular hwaddr/clientid/hostname in our configuration.
767: Try to return from contexts which match netids first. */
768:
769: struct in_addr start, addr;
770: struct dhcp_context *c, *d;
771: int i, pass;
772: unsigned int j;
773:
774: /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good
775: dispersal even with similarly-valued "strings". */
776: for (j = 0, i = 0; i < hw_len; i++)
1.1.1.3 misho 777: j = hwaddr[i] + (j << 6) + (j << 16) - j;
1.1.1.4 ! misho 778:
! 779: /* j == 0 is marker */
! 780: if (j == 0)
! 781: j = 1;
1.1 misho 782:
783: for (pass = 0; pass <= 1; pass++)
784: for (c = context; c; c = c->current)
785: if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
786: continue;
787: else if (!match_netid(c->filter, netids, pass))
788: continue;
789: else
790: {
791: if (option_bool(OPT_CONSEC_ADDR))
792: /* seed is largest extant lease addr in this context */
793: start = lease_find_max_addr(c);
794: else
795: /* pick a seed based on hwaddr */
796: start.s_addr = htonl(ntohl(c->start.s_addr) +
797: ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
798:
799: /* iterate until we find a free address. */
800: addr = start;
801:
802: do {
803: /* eliminate addresses in use by the server. */
804: for (d = context; d; d = d->current)
805: if (addr.s_addr == d->router.s_addr)
806: break;
807:
808: /* Addresses which end in .255 and .0 are broken in Windows even when using
809: supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
810: then 192.168.0.255 is a valid IP address, but not for Windows as it's
811: in the class C range. See KB281579. We therefore don't allocate these
812: addresses to avoid hard-to-diagnose problems. Thanks Bill. */
813: if (!d &&
814: !lease_find_by_addr(addr) &&
815: !config_find_by_address(daemon->dhcp_conf, addr) &&
816: (!IN_CLASSC(ntohl(addr.s_addr)) ||
817: ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
818: {
1.1.1.4 ! misho 819: /* in consec-ip mode, skip addresses equal to
! 820: the number of addresses rejected by clients. This
! 821: should avoid the same client being offered the same
! 822: address after it has rjected it. */
! 823: if (option_bool(OPT_CONSEC_ADDR) && c->addr_epoch)
! 824: c->addr_epoch--;
! 825: else
1.1 misho 826: {
1.1.1.4 ! misho 827: struct ping_result *r;
! 828:
! 829: if ((r = do_icmp_ping(now, addr, j, loopback)))
! 830: {
! 831: /* consec-ip mode: we offered this address for another client
! 832: (different hash) recently, don't offer it to this one. */
! 833: if (!option_bool(OPT_CONSEC_ADDR) || r->hash == j)
! 834: {
! 835: *addrp = addr;
! 836: return 1;
! 837: }
! 838: }
! 839: else
1.1 misho 840: {
841: /* address in use: perturb address selection so that we are
842: less likely to try this address again. */
843: if (!option_bool(OPT_CONSEC_ADDR))
844: c->addr_epoch++;
845: }
846: }
847: }
1.1.1.4 ! misho 848:
1.1 misho 849: addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
850:
851: if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
852: addr = c->start;
853:
854: } while (addr.s_addr != start.s_addr);
855: }
856:
857: return 0;
858: }
859:
860: void dhcp_read_ethers(void)
861: {
862: FILE *f = fopen(ETHERSFILE, "r");
863: unsigned int flags;
864: char *buff = daemon->namebuff;
865: char *ip, *cp;
866: struct in_addr addr;
867: unsigned char hwaddr[ETHER_ADDR_LEN];
868: struct dhcp_config **up, *tmp;
869: struct dhcp_config *config;
870: int count = 0, lineno = 0;
871:
872: addr.s_addr = 0; /* eliminate warning */
873:
874: if (!f)
875: {
876: my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
877: return;
878: }
879:
880: /* This can be called again on SIGHUP, so remove entries created last time round. */
881: for (up = &daemon->dhcp_conf, config = daemon->dhcp_conf; config; config = tmp)
882: {
883: tmp = config->next;
884: if (config->flags & CONFIG_FROM_ETHERS)
885: {
886: *up = tmp;
887: /* cannot have a clid */
888: if (config->flags & CONFIG_NAME)
889: free(config->hostname);
890: free(config->hwaddr);
891: free(config);
892: }
893: else
894: up = &config->next;
895: }
896:
897: while (fgets(buff, MAXDNAME, f))
898: {
899: char *host = NULL;
900:
901: lineno++;
902:
903: while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
904: buff[strlen(buff)-1] = 0;
905:
906: if ((*buff == '#') || (*buff == '+') || (*buff == 0))
907: continue;
908:
909: for (ip = buff; *ip && !isspace((int)*ip); ip++);
910: for(; *ip && isspace((int)*ip); ip++)
911: *ip = 0;
912: if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
913: {
914: my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
915: continue;
916: }
917:
918: /* check for name or dotted-quad */
919: for (cp = ip; *cp; cp++)
920: if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
921: break;
922:
923: if (!*cp)
924: {
925: if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
926: {
927: my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
928: continue;
929: }
930:
931: flags = CONFIG_ADDR;
932:
933: for (config = daemon->dhcp_conf; config; config = config->next)
934: if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
935: break;
936: }
937: else
938: {
939: int nomem;
940: if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host))
941: {
942: if (!nomem)
943: my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
944: free(host);
945: continue;
946: }
947:
948: flags = CONFIG_NAME;
949:
950: for (config = daemon->dhcp_conf; config; config = config->next)
951: if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host))
952: break;
953: }
954:
955: if (config && (config->flags & CONFIG_FROM_ETHERS))
956: {
957: my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno);
958: continue;
959: }
960:
961: if (!config)
962: {
963: for (config = daemon->dhcp_conf; config; config = config->next)
964: {
965: struct hwaddr_config *conf_addr = config->hwaddr;
966: if (conf_addr &&
967: conf_addr->next == NULL &&
968: conf_addr->wildcard_mask == 0 &&
969: conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
970: (conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
971: memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
972: break;
973: }
974:
975: if (!config)
976: {
977: if (!(config = whine_malloc(sizeof(struct dhcp_config))))
978: continue;
979: config->flags = CONFIG_FROM_ETHERS;
980: config->hwaddr = NULL;
981: config->domain = NULL;
982: config->netid = NULL;
983: config->next = daemon->dhcp_conf;
984: daemon->dhcp_conf = config;
985: }
986:
987: config->flags |= flags;
988:
989: if (flags & CONFIG_NAME)
990: {
991: config->hostname = host;
992: host = NULL;
993: }
994:
995: if (flags & CONFIG_ADDR)
996: config->addr = addr;
997: }
998:
999: config->flags |= CONFIG_NOCLID;
1000: if (!config->hwaddr)
1001: config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
1002: if (config->hwaddr)
1003: {
1004: memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
1005: config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
1006: config->hwaddr->hwaddr_type = ARPHRD_ETHER;
1007: config->hwaddr->wildcard_mask = 0;
1008: config->hwaddr->next = NULL;
1009: }
1010: count++;
1011:
1012: free(host);
1013:
1014: }
1015:
1016: fclose(f);
1017:
1018: my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
1019: }
1020:
1021:
1022: /* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
1023: for this address. If it has a domain part, that must match the set domain and
1024: it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
1025: so check here that the domain name is legal as a hostname.
1026: NOTE: we're only allowed to overwrite daemon->dhcp_buff if we succeed. */
1027: char *host_from_dns(struct in_addr addr)
1028: {
1029: struct crec *lookup;
1030:
1031: if (daemon->port == 0)
1032: return NULL; /* DNS disabled. */
1033:
1.1.1.4 ! misho 1034: lookup = cache_find_by_addr(NULL, (union all_addr *)&addr, 0, F_IPV4);
1.1 misho 1035:
1036: if (lookup && (lookup->flags & F_HOSTS))
1037: {
1038: char *dot, *hostname = cache_get_name(lookup);
1039: dot = strchr(hostname, '.');
1040:
1041: if (dot && strlen(dot+1) != 0)
1042: {
1043: char *d2 = get_domain(addr);
1044: if (!d2 || !hostname_isequal(dot+1, d2))
1045: return NULL; /* wrong domain */
1046: }
1047:
1048: if (!legal_hostname(hostname))
1049: return NULL;
1050:
1.1.1.4 ! misho 1051: safe_strncpy(daemon->dhcp_buff, hostname, 256);
1.1 misho 1052: strip_hostname(daemon->dhcp_buff);
1053:
1054: return daemon->dhcp_buff;
1055: }
1056:
1057: return NULL;
1058: }
1059:
1.1.1.2 misho 1060: static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
1061: {
1062: /* ->local is same value for all relays on ->current chain */
1.1.1.4 ! misho 1063: union all_addr from;
1.1.1.2 misho 1064:
1065: if (mess->op != BOOTREQUEST)
1066: return 0;
1067:
1068: /* source address == relay address */
1.1.1.4 ! misho 1069: from.addr4 = relay->local.addr4;
1.1.1.2 misho 1070:
1071: /* already gatewayed ? */
1072: if (mess->giaddr.s_addr)
1073: {
1074: /* if so check if by us, to stomp on loops. */
1.1.1.4 ! misho 1075: if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
1.1.1.2 misho 1076: return 1;
1077: }
1078: else
1079: {
1080: /* plug in our address */
1.1.1.4 ! misho 1081: mess->giaddr.s_addr = relay->local.addr4.s_addr;
1.1.1.2 misho 1082: }
1083:
1084: if ((mess->hops++) > 20)
1085: return 1;
1.1 misho 1086:
1.1.1.2 misho 1087: for (; relay; relay = relay->current)
1088: {
1089: union mysockaddr to;
1090:
1091: to.sa.sa_family = AF_INET;
1.1.1.4 ! misho 1092: to.in.sin_addr = relay->server.addr4;
1.1.1.2 misho 1093: to.in.sin_port = htons(daemon->dhcp_server_port);
1094:
1095: send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
1096:
1097: if (option_bool(OPT_LOG_OPTS))
1098: {
1099: inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
1.1.1.4 ! misho 1100: my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, inet_ntoa(relay->server.addr4));
1.1.1.2 misho 1101: }
1102:
1103: /* Save this for replies */
1104: relay->iface_index = iface_index;
1105: }
1106:
1107: return 1;
1108: }
1109:
1110:
1111: static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
1112: {
1113: struct dhcp_relay *relay;
1114:
1115: if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
1116: return NULL;
1117:
1118: for (relay = daemon->relay4; relay; relay = relay->next)
1119: {
1.1.1.4 ! misho 1120: if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
1.1.1.2 misho 1121: {
1122: if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
1123: return relay->iface_index != 0 ? relay : NULL;
1124: }
1125: }
1126:
1127: return NULL;
1128: }
1129:
1130: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>