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