Annotation of embedaddon/dnsmasq/src/dhcp.c, revision 1.1.1.3
1.1.1.3 ! misho 1: /* dnsmasq is Copyright (c) 2000-2016 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:
70: /* When bind-interfaces is set, there might be more than one dnmsasq
71: instance binding port 67. That's OK if they serve different networks.
72: Need to set REUSEADDR|REUSEPORT to make this posible.
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;
148: int iface_index = 0, unicast_dest = 0, is_inform = 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;
152: #ifdef HAVE_LINUX_NETWORK
153: struct arpreq arp_req;
154: #endif
155:
156: union {
157: struct cmsghdr align; /* this ensures alignment */
158: #if defined(HAVE_LINUX_NETWORK)
159: char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
160: #elif defined(HAVE_SOLARIS_NETWORK)
161: char control[CMSG_SPACE(sizeof(unsigned int))];
162: #elif defined(HAVE_BSD_NETWORK)
163: char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
164: #endif
165: } control_u;
166: struct dhcp_bridge *bridge, *alias;
167:
168: msg.msg_controllen = sizeof(control_u);
169: msg.msg_control = control_u.control;
170: msg.msg_name = &dest;
171: msg.msg_namelen = sizeof(dest);
172: msg.msg_iov = &daemon->dhcp_packet;
173: msg.msg_iovlen = 1;
174:
175: if ((sz = recv_dhcp_packet(fd, &msg)) == -1 ||
176: (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
177: return;
178:
179: #if defined (HAVE_LINUX_NETWORK)
180: if (msg.msg_controllen >= sizeof(struct cmsghdr))
181: for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
182: if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
183: {
184: union {
185: unsigned char *c;
186: struct in_pktinfo *p;
187: } p;
188: p.c = CMSG_DATA(cmptr);
189: iface_index = p.p->ipi_ifindex;
190: if (p.p->ipi_addr.s_addr != INADDR_BROADCAST)
191: unicast_dest = 1;
192: }
193:
194: #elif defined(HAVE_BSD_NETWORK)
195: if (msg.msg_controllen >= sizeof(struct cmsghdr))
196: for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
197: if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
198: {
199: union {
200: unsigned char *c;
201: struct sockaddr_dl *s;
202: } p;
203: p.c = CMSG_DATA(cmptr);
204: iface_index = p.s->sdl_index;
205: }
206:
207: #elif defined(HAVE_SOLARIS_NETWORK)
208: if (msg.msg_controllen >= sizeof(struct cmsghdr))
209: for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
210: if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
211: {
212: union {
213: unsigned char *c;
214: unsigned int *i;
215: } p;
216: p.c = CMSG_DATA(cmptr);
217: iface_index = *(p.i);
218: }
219: #endif
220:
221: if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
222: return;
223:
224: #ifdef HAVE_LINUX_NETWORK
225: /* ARP fiddling uses original interface even if we pretend to use a different one. */
226: strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
227: #endif
228:
1.1.1.3 ! misho 229: /* If the interface on which the DHCP request was received is an
! 230: alias of some other interface (as specified by the
! 231: --bridge-interface option), change ifr.ifr_name so that we look
! 232: for DHCP contexts associated with the aliased interface instead
! 233: of with the aliasing one. */
! 234: rcvd_iface_index = iface_index;
1.1 misho 235: for (bridge = daemon->bridges; bridge; bridge = bridge->next)
236: {
237: for (alias = bridge->alias; alias; alias = alias->next)
1.1.1.3 ! misho 238: if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
1.1 misho 239: {
240: if (!(iface_index = if_nametoindex(bridge->iface)))
241: {
1.1.1.3 ! misho 242: my_syslog(MS_DHCP | LOG_WARNING,
! 243: _("unknown interface %s in bridge-interface"),
! 244: bridge->iface);
1.1 misho 245: return;
246: }
247: else
248: {
249: strncpy(ifr.ifr_name, bridge->iface, IF_NAMESIZE);
250: break;
251: }
252: }
253:
254: if (alias)
255: break;
256: }
257:
258: #ifdef MSG_BCAST
259: /* OpenBSD tells us when a packet was broadcast */
260: if (!(msg.msg_flags & MSG_BCAST))
261: unicast_dest = 1;
262: #endif
263:
1.1.1.2 misho 264: if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
1.1 misho 265: {
1.1.1.2 misho 266: /* Reply from server, using us as relay. */
267: iface_index = relay->iface_index;
268: if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
269: return;
270: is_relay_reply = 1;
271: iov.iov_len = sz;
272: #ifdef HAVE_LINUX_NETWORK
273: strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
274: #endif
1.1 misho 275: }
1.1.1.2 misho 276: else
1.1 misho 277: {
1.1.1.2 misho 278: ifr.ifr_addr.sa_family = AF_INET;
279: if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
280: iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
281: else
282: {
283: my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
284: return;
285: }
286:
287: for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
288: if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
289: return;
290:
291: /* unlinked contexts/relays are marked by context->current == context */
292: for (context = daemon->dhcp; context; context = context->next)
293: context->current = context;
294:
295: for (relay = daemon->relay4; relay; relay = relay->next)
296: relay->current = relay;
1.1 misho 297:
1.1.1.2 misho 298: parm.current = NULL;
299: parm.relay = NULL;
300: parm.relay_local.s_addr = 0;
301: parm.ind = iface_index;
1.1 misho 302:
1.1.1.2 misho 303: if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
304: {
305: /* If we failed to match the primary address of the interface, see if we've got a --listen-address
306: for a secondary */
307: struct match_param match;
308:
309: match.matched = 0;
310: match.ind = iface_index;
311:
312: if (!daemon->if_addrs ||
313: !iface_enumerate(AF_INET, &match, check_listen_addrs) ||
314: !match.matched)
315: return;
316:
317: iface_addr = match.addr;
318: /* make sure secondary address gets priority in case
319: there is more than one address on the interface in the same subnet */
320: complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
321: }
322:
323: if (!iface_enumerate(AF_INET, &parm, complete_context))
324: return;
325:
326: /* We're relaying this request */
327: if (parm.relay_local.s_addr != 0 &&
328: relay_upstream4(parm.relay, (struct dhcp_packet *)daemon->dhcp_packet.iov_base, (size_t)sz, iface_index))
329: return;
330:
331: /* May have configured relay, but not DHCP server */
332: if (!daemon->dhcp)
1.1 misho 333: return;
334:
1.1.1.2 misho 335: lease_prune(NULL, now); /* lose any expired leases */
336: iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
337: now, unicast_dest, &is_inform, pxe_fd, iface_addr);
338: lease_update_file(now);
339: lease_update_dns(0);
1.1 misho 340:
1.1.1.2 misho 341: if (iov.iov_len == 0)
342: return;
343: }
1.1 misho 344:
345: msg.msg_name = &dest;
346: msg.msg_namelen = sizeof(dest);
347: msg.msg_control = NULL;
348: msg.msg_controllen = 0;
349: msg.msg_iov = &iov;
350: iov.iov_base = daemon->dhcp_packet.iov_base;
351:
352: /* packet buffer may have moved */
353: mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
354:
355: #ifdef HAVE_SOCKADDR_SA_LEN
356: dest.sin_len = sizeof(struct sockaddr_in);
357: #endif
358:
359: if (pxe_fd)
360: {
361: if (mess->ciaddr.s_addr != 0)
362: dest.sin_addr = mess->ciaddr;
363: }
1.1.1.2 misho 364: else if (mess->giaddr.s_addr && !is_relay_reply)
1.1 misho 365: {
366: /* Send to BOOTP relay */
367: dest.sin_port = htons(daemon->dhcp_server_port);
368: dest.sin_addr = mess->giaddr;
369: }
370: else if (mess->ciaddr.s_addr)
371: {
372: /* If the client's idea of its own address tallys with
373: the source address in the request packet, we believe the
374: source port too, and send back to that. If we're replying
375: to a DHCPINFORM, trust the source address always. */
376: if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
1.1.1.2 misho 377: dest.sin_port == 0 || dest.sin_addr.s_addr == 0 || is_relay_reply)
1.1 misho 378: {
379: dest.sin_port = htons(daemon->dhcp_client_port);
380: dest.sin_addr = mess->ciaddr;
381: }
382: }
383: #if defined(HAVE_LINUX_NETWORK)
1.1.1.3 ! misho 384: else
1.1 misho 385: {
1.1.1.3 ! misho 386: /* fill cmsg for outbound interface (both broadcast & unicast) */
1.1 misho 387: struct in_pktinfo *pkt;
388: msg.msg_control = control_u.control;
389: msg.msg_controllen = sizeof(control_u);
390: cmptr = CMSG_FIRSTHDR(&msg);
391: pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
1.1.1.3 ! misho 392: pkt->ipi_ifindex = rcvd_iface_index;
1.1 misho 393: pkt->ipi_spec_dst.s_addr = 0;
394: msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
395: cmptr->cmsg_level = IPPROTO_IP;
1.1.1.3 ! misho 396: cmptr->cmsg_type = IP_PKTINFO;
! 397:
! 398: if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
! 399: mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
! 400: {
! 401: /* broadcast to 255.255.255.255 (or mac address invalid) */
! 402: dest.sin_addr.s_addr = INADDR_BROADCAST;
! 403: dest.sin_port = htons(daemon->dhcp_client_port);
! 404: }
! 405: else
! 406: {
! 407: /* unicast to unconfigured client. Inject mac address direct into ARP cache.
! 408: struct sockaddr limits size to 14 bytes. */
! 409: dest.sin_addr = mess->yiaddr;
! 410: dest.sin_port = htons(daemon->dhcp_client_port);
! 411: memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
! 412: arp_req.arp_ha.sa_family = mess->htype;
! 413: memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
! 414: /* interface name already copied in */
! 415: arp_req.arp_flags = ATF_COM;
! 416: if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
! 417: my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
! 418: }
1.1 misho 419: }
420: #elif defined(HAVE_SOLARIS_NETWORK)
421: else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
422: {
423: /* broadcast to 255.255.255.255 (or mac address invalid) */
424: dest.sin_addr.s_addr = INADDR_BROADCAST;
425: dest.sin_port = htons(daemon->dhcp_client_port);
426: /* note that we don't specify the interface here: that's done by the
427: IP_BOUND_IF sockopt lower down. */
428: }
429: else
430: {
431: /* unicast to unconfigured client. Inject mac address direct into ARP cache.
432: Note that this only works for ethernet on solaris, because we use SIOCSARP
433: and not SIOCSXARP, which would be perfect, except that it returns ENXIO
434: mysteriously. Bah. Fall back to broadcast for other net types. */
435: struct arpreq req;
436: dest.sin_addr = mess->yiaddr;
437: dest.sin_port = htons(daemon->dhcp_client_port);
438: *((struct sockaddr_in *)&req.arp_pa) = dest;
439: req.arp_ha.sa_family = AF_UNSPEC;
440: memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
441: req.arp_flags = ATF_COM;
442: ioctl(daemon->dhcpfd, SIOCSARP, &req);
443: }
444: #elif defined(HAVE_BSD_NETWORK)
445: else
446: {
447: send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
448: return;
449: }
450: #endif
451:
452: #ifdef HAVE_SOLARIS_NETWORK
453: setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
454: #endif
455:
1.1.1.3 ! misho 456: while(retry_send(sendmsg(fd, &msg, 0)));
! 457:
! 458: /* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
! 459: if (errno != 0)
! 460: my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
! 461: inet_ntoa(dest.sin_addr), strerror(errno));
1.1 misho 462: }
1.1.1.3 ! misho 463:
1.1 misho 464: /* check against secondary interface addresses */
1.1.1.2 misho 465: static int check_listen_addrs(struct in_addr local, int if_index, char *label,
1.1 misho 466: struct in_addr netmask, struct in_addr broadcast, void *vparam)
467: {
468: struct match_param *param = vparam;
469: struct iname *tmp;
470:
1.1.1.2 misho 471: (void) label;
472:
1.1 misho 473: if (if_index == param->ind)
474: {
475: for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
476: if ( tmp->addr.sa.sa_family == AF_INET &&
477: tmp->addr.in.sin_addr.s_addr == local.s_addr)
478: {
479: param->matched = 1;
480: param->addr = local;
481: param->netmask = netmask;
482: param->broadcast = broadcast;
483: break;
484: }
485: }
486:
487: return 1;
488: }
489:
490: /* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
491: of each interface (and any relay address) and does the following things:
492:
493: 1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
494: 2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
495: 3) Fills in local (this host) and router (this host or relay) addresses.
496: 4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
497:
498: Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
499:
1.1.1.2 misho 500: static int complete_context(struct in_addr local, int if_index, char *label,
1.1 misho 501: struct in_addr netmask, struct in_addr broadcast, void *vparam)
502: {
503: struct dhcp_context *context;
1.1.1.2 misho 504: struct dhcp_relay *relay;
1.1 misho 505: struct iface_param *param = vparam;
1.1.1.2 misho 506:
507: (void)label;
1.1 misho 508:
509: for (context = daemon->dhcp; context; context = context->next)
510: {
511: if (!(context->flags & CONTEXT_NETMASK) &&
512: (is_same_net(local, context->start, netmask) ||
513: is_same_net(local, context->end, netmask)))
514: {
515: if (context->netmask.s_addr != netmask.s_addr &&
516: !(is_same_net(local, context->start, netmask) &&
517: is_same_net(local, context->end, netmask)))
518: {
519: strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
520: strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
521: my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
522: daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
523: }
524: context->netmask = netmask;
525: }
526:
527: if (context->netmask.s_addr != 0 &&
528: is_same_net(local, context->start, context->netmask) &&
529: is_same_net(local, context->end, context->netmask))
530: {
531: /* link it onto the current chain if we've not seen it before */
532: if (if_index == param->ind && context->current == context)
533: {
534: context->router = local;
535: context->local = local;
536: context->current = param->current;
537: param->current = context;
538: }
539:
540: if (!(context->flags & CONTEXT_BRDCAST))
541: {
542: if (is_same_net(broadcast, context->start, context->netmask))
543: context->broadcast = broadcast;
544: else
545: context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
546: }
547: }
548: }
549:
1.1.1.2 misho 550: for (relay = daemon->relay4; relay; relay = relay->next)
551: if (if_index == param->ind && relay->local.addr.addr4.s_addr == local.s_addr && relay->current == relay &&
552: (param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr))
553: {
554: relay->current = param->relay;
555: param->relay = relay;
556: param->relay_local = local;
557: }
558:
1.1 misho 559: return 1;
560: }
561:
562: struct dhcp_context *address_available(struct dhcp_context *context,
563: struct in_addr taddr,
564: struct dhcp_netid *netids)
565: {
566: /* Check is an address is OK for this network, check all
567: possible ranges. Make sure that the address isn't in use
568: by the server itself. */
569:
570: unsigned int start, end, addr = ntohl(taddr.s_addr);
571: struct dhcp_context *tmp;
572:
573: for (tmp = context; tmp; tmp = tmp->current)
574: if (taddr.s_addr == context->router.s_addr)
575: return NULL;
576:
577: for (tmp = context; tmp; tmp = tmp->current)
578: {
579: start = ntohl(tmp->start.s_addr);
580: end = ntohl(tmp->end.s_addr);
581:
582: if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
583: addr >= start &&
584: addr <= end &&
585: match_netid(tmp->filter, netids, 1))
586: return tmp;
587: }
588:
589: return NULL;
590: }
591:
592: struct dhcp_context *narrow_context(struct dhcp_context *context,
593: struct in_addr taddr,
594: struct dhcp_netid *netids)
595: {
596: /* We start of with a set of possible contexts, all on the current physical interface.
597: These are chained on ->current.
598: Here we have an address, and return the actual context correponding to that
599: address. Note that none may fit, if the address came a dhcp-host and is outside
600: any dhcp-range. In that case we return a static range if possible, or failing that,
601: any context on the correct subnet. (If there's more than one, this is a dodgy
602: configuration: maybe there should be a warning.) */
603:
604: struct dhcp_context *tmp;
605:
606: if (!(tmp = address_available(context, taddr, netids)))
607: {
608: for (tmp = context; tmp; tmp = tmp->current)
609: if (match_netid(tmp->filter, netids, 1) &&
610: is_same_net(taddr, tmp->start, tmp->netmask) &&
611: (tmp->flags & CONTEXT_STATIC))
612: break;
613:
614: if (!tmp)
615: for (tmp = context; tmp; tmp = tmp->current)
616: if (match_netid(tmp->filter, netids, 1) &&
617: is_same_net(taddr, tmp->start, tmp->netmask) &&
618: !(tmp->flags & CONTEXT_PROXY))
619: break;
620: }
621:
622: /* Only one context allowed now */
623: if (tmp)
624: tmp->current = NULL;
625:
626: return tmp;
627: }
628:
629: struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
630: {
631: struct dhcp_config *config;
632:
633: for (config = configs; config; config = config->next)
634: if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
635: return config;
636:
637: return NULL;
638: }
639:
640: int address_allocate(struct dhcp_context *context,
641: struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
642: struct dhcp_netid *netids, time_t now)
643: {
644: /* Find a free address: exclude anything in use and anything allocated to
645: a particular hwaddr/clientid/hostname in our configuration.
646: Try to return from contexts which match netids first. */
647:
648: struct in_addr start, addr;
649: struct dhcp_context *c, *d;
650: int i, pass;
651: unsigned int j;
652:
653: /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good
654: dispersal even with similarly-valued "strings". */
655: for (j = 0, i = 0; i < hw_len; i++)
1.1.1.3 ! misho 656: j = hwaddr[i] + (j << 6) + (j << 16) - j;
1.1 misho 657:
658: for (pass = 0; pass <= 1; pass++)
659: for (c = context; c; c = c->current)
660: if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
661: continue;
662: else if (!match_netid(c->filter, netids, pass))
663: continue;
664: else
665: {
666: if (option_bool(OPT_CONSEC_ADDR))
667: /* seed is largest extant lease addr in this context */
668: start = lease_find_max_addr(c);
669: else
670: /* pick a seed based on hwaddr */
671: start.s_addr = htonl(ntohl(c->start.s_addr) +
672: ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
673:
674: /* iterate until we find a free address. */
675: addr = start;
676:
677: do {
678: /* eliminate addresses in use by the server. */
679: for (d = context; d; d = d->current)
680: if (addr.s_addr == d->router.s_addr)
681: break;
682:
683: /* Addresses which end in .255 and .0 are broken in Windows even when using
684: supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
685: then 192.168.0.255 is a valid IP address, but not for Windows as it's
686: in the class C range. See KB281579. We therefore don't allocate these
687: addresses to avoid hard-to-diagnose problems. Thanks Bill. */
688: if (!d &&
689: !lease_find_by_addr(addr) &&
690: !config_find_by_address(daemon->dhcp_conf, addr) &&
691: (!IN_CLASSC(ntohl(addr.s_addr)) ||
692: ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
693: {
694: struct ping_result *r, *victim = NULL;
695: int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
696: ((float)PING_WAIT)));
697:
698: *addrp = addr;
699:
700: /* check if we failed to ping addr sometime in the last
701: PING_CACHE_TIME seconds. If so, assume the same situation still exists.
702: This avoids problems when a stupid client bangs
703: on us repeatedly. As a final check, if we did more
704: than 60% of the possible ping checks in the last
705: PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
706: for (count = 0, r = daemon->ping_results; r; r = r->next)
707: if (difftime(now, r->time) > (float)PING_CACHE_TIME)
708: victim = r; /* old record */
709: else
710: {
711: count++;
712: if (r->addr.s_addr == addr.s_addr)
713: {
714: /* consec-ip mode: we offered this address for another client
715: (different hash) recently, don't offer it to this one. */
716: if (option_bool(OPT_CONSEC_ADDR) && r->hash != j)
717: break;
718:
719: return 1;
720: }
721: }
722:
723: if (!r)
724: {
725: if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
726: {
727: /* address in use: perturb address selection so that we are
728: less likely to try this address again. */
729: if (!option_bool(OPT_CONSEC_ADDR))
730: c->addr_epoch++;
731: }
732: else
733: {
734: /* at this point victim may hold an expired record */
735: if (!victim)
736: {
737: if ((victim = whine_malloc(sizeof(struct ping_result))))
738: {
739: victim->next = daemon->ping_results;
740: daemon->ping_results = victim;
741: }
742: }
743:
744: /* record that this address is OK for 30s
745: without more ping checks */
746: if (victim)
747: {
748: victim->addr = addr;
749: victim->time = now;
750: victim->hash = j;
751: }
752: return 1;
753: }
754: }
755: }
756:
757: addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
758:
759: if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
760: addr = c->start;
761:
762: } while (addr.s_addr != start.s_addr);
763: }
764:
765: return 0;
766: }
767:
768: void dhcp_read_ethers(void)
769: {
770: FILE *f = fopen(ETHERSFILE, "r");
771: unsigned int flags;
772: char *buff = daemon->namebuff;
773: char *ip, *cp;
774: struct in_addr addr;
775: unsigned char hwaddr[ETHER_ADDR_LEN];
776: struct dhcp_config **up, *tmp;
777: struct dhcp_config *config;
778: int count = 0, lineno = 0;
779:
780: addr.s_addr = 0; /* eliminate warning */
781:
782: if (!f)
783: {
784: my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
785: return;
786: }
787:
788: /* This can be called again on SIGHUP, so remove entries created last time round. */
789: for (up = &daemon->dhcp_conf, config = daemon->dhcp_conf; config; config = tmp)
790: {
791: tmp = config->next;
792: if (config->flags & CONFIG_FROM_ETHERS)
793: {
794: *up = tmp;
795: /* cannot have a clid */
796: if (config->flags & CONFIG_NAME)
797: free(config->hostname);
798: free(config->hwaddr);
799: free(config);
800: }
801: else
802: up = &config->next;
803: }
804:
805: while (fgets(buff, MAXDNAME, f))
806: {
807: char *host = NULL;
808:
809: lineno++;
810:
811: while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
812: buff[strlen(buff)-1] = 0;
813:
814: if ((*buff == '#') || (*buff == '+') || (*buff == 0))
815: continue;
816:
817: for (ip = buff; *ip && !isspace((int)*ip); ip++);
818: for(; *ip && isspace((int)*ip); ip++)
819: *ip = 0;
820: if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
821: {
822: my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
823: continue;
824: }
825:
826: /* check for name or dotted-quad */
827: for (cp = ip; *cp; cp++)
828: if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
829: break;
830:
831: if (!*cp)
832: {
833: if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
834: {
835: my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
836: continue;
837: }
838:
839: flags = CONFIG_ADDR;
840:
841: for (config = daemon->dhcp_conf; config; config = config->next)
842: if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
843: break;
844: }
845: else
846: {
847: int nomem;
848: if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host))
849: {
850: if (!nomem)
851: my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
852: free(host);
853: continue;
854: }
855:
856: flags = CONFIG_NAME;
857:
858: for (config = daemon->dhcp_conf; config; config = config->next)
859: if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host))
860: break;
861: }
862:
863: if (config && (config->flags & CONFIG_FROM_ETHERS))
864: {
865: my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno);
866: continue;
867: }
868:
869: if (!config)
870: {
871: for (config = daemon->dhcp_conf; config; config = config->next)
872: {
873: struct hwaddr_config *conf_addr = config->hwaddr;
874: if (conf_addr &&
875: conf_addr->next == NULL &&
876: conf_addr->wildcard_mask == 0 &&
877: conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
878: (conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
879: memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
880: break;
881: }
882:
883: if (!config)
884: {
885: if (!(config = whine_malloc(sizeof(struct dhcp_config))))
886: continue;
887: config->flags = CONFIG_FROM_ETHERS;
888: config->hwaddr = NULL;
889: config->domain = NULL;
890: config->netid = NULL;
891: config->next = daemon->dhcp_conf;
892: daemon->dhcp_conf = config;
893: }
894:
895: config->flags |= flags;
896:
897: if (flags & CONFIG_NAME)
898: {
899: config->hostname = host;
900: host = NULL;
901: }
902:
903: if (flags & CONFIG_ADDR)
904: config->addr = addr;
905: }
906:
907: config->flags |= CONFIG_NOCLID;
908: if (!config->hwaddr)
909: config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
910: if (config->hwaddr)
911: {
912: memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
913: config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
914: config->hwaddr->hwaddr_type = ARPHRD_ETHER;
915: config->hwaddr->wildcard_mask = 0;
916: config->hwaddr->next = NULL;
917: }
918: count++;
919:
920: free(host);
921:
922: }
923:
924: fclose(f);
925:
926: my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
927: }
928:
929:
930: /* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
931: for this address. If it has a domain part, that must match the set domain and
932: it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
933: so check here that the domain name is legal as a hostname.
934: NOTE: we're only allowed to overwrite daemon->dhcp_buff if we succeed. */
935: char *host_from_dns(struct in_addr addr)
936: {
937: struct crec *lookup;
938:
939: if (daemon->port == 0)
940: return NULL; /* DNS disabled. */
941:
942: lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
943:
944: if (lookup && (lookup->flags & F_HOSTS))
945: {
946: char *dot, *hostname = cache_get_name(lookup);
947: dot = strchr(hostname, '.');
948:
949: if (dot && strlen(dot+1) != 0)
950: {
951: char *d2 = get_domain(addr);
952: if (!d2 || !hostname_isequal(dot+1, d2))
953: return NULL; /* wrong domain */
954: }
955:
956: if (!legal_hostname(hostname))
957: return NULL;
958:
959: strncpy(daemon->dhcp_buff, hostname, 256);
960: daemon->dhcp_buff[255] = 0;
961: strip_hostname(daemon->dhcp_buff);
962:
963: return daemon->dhcp_buff;
964: }
965:
966: return NULL;
967: }
968:
1.1.1.2 misho 969: static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
970: {
971: /* ->local is same value for all relays on ->current chain */
972: struct all_addr from;
973:
974: if (mess->op != BOOTREQUEST)
975: return 0;
976:
977: /* source address == relay address */
978: from.addr.addr4 = relay->local.addr.addr4;
979:
980: /* already gatewayed ? */
981: if (mess->giaddr.s_addr)
982: {
983: /* if so check if by us, to stomp on loops. */
984: if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
985: return 1;
986: }
987: else
988: {
989: /* plug in our address */
990: mess->giaddr.s_addr = relay->local.addr.addr4.s_addr;
991: }
992:
993: if ((mess->hops++) > 20)
994: return 1;
1.1 misho 995:
1.1.1.2 misho 996: for (; relay; relay = relay->current)
997: {
998: union mysockaddr to;
999:
1000: to.sa.sa_family = AF_INET;
1001: to.in.sin_addr = relay->server.addr.addr4;
1002: to.in.sin_port = htons(daemon->dhcp_server_port);
1003:
1004: send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
1005:
1006: if (option_bool(OPT_LOG_OPTS))
1007: {
1008: inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
1009: my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, inet_ntoa(relay->server.addr.addr4));
1010: }
1011:
1012: /* Save this for replies */
1013: relay->iface_index = iface_index;
1014: }
1015:
1016: return 1;
1017: }
1018:
1019:
1020: static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
1021: {
1022: struct dhcp_relay *relay;
1023:
1024: if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
1025: return NULL;
1026:
1027: for (relay = daemon->relay4; relay; relay = relay->next)
1028: {
1029: if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
1030: {
1031: if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
1032: return relay->iface_index != 0 ? relay : NULL;
1033: }
1034: }
1035:
1036: return NULL;
1037: }
1038:
1039: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>