• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; version 2 dated June, 1991, or
6    (at your option) version 3 dated 29 June, 2007.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 */
16 
17 #include "dnsmasq.h"
18 
19 #ifdef HAVE_DHCP
20 
21 struct iface_param {
22   struct in_addr relay, primary;
23   struct dhcp_context *current;
24   int ind;
25 };
26 
27 static int complete_context(struct in_addr local, int if_index,
28 			    struct in_addr netmask, struct in_addr broadcast, void *vparam);
29 
dhcp_init(void)30 void dhcp_init(void)
31 {
32   int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
33   struct sockaddr_in saddr;
34   int oneopt = 1;
35 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
36   int mtu = IP_PMTUDISC_DONT;
37 #endif
38 
39   if (fd == -1)
40     die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
41 
42   if (!fix_fd(fd) ||
43 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
44       setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
45 #endif
46 #if defined(HAVE_LINUX_NETWORK)
47       setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
48 #else
49       setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
50 #endif
51       setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
52     die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET);
53 
54   /* When bind-interfaces is set, there might be more than one dnmsasq
55      instance binding port 67. That's OK if they serve different networks.
56      Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
57   if (daemon->options & OPT_NOWILD)
58     {
59 #ifdef SO_REUSEPORT
60       int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
61 #else
62       int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
63 #endif
64       if (rc == -1)
65 	die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
66     }
67 
68   memset(&saddr, 0, sizeof(saddr));
69   saddr.sin_family = AF_INET;
70   saddr.sin_port = htons(daemon->dhcp_server_port);
71   saddr.sin_addr.s_addr = INADDR_ANY;
72 #ifdef HAVE_SOCKADDR_SA_LEN
73   saddr.sin_len = sizeof(struct sockaddr_in);
74 #endif
75 
76   if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
77     die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
78 
79   daemon->dhcpfd = fd;
80 
81 #if defined(HAVE_BSD_NETWORK)
82   /* When we're not using capabilities, we need to do this here before
83      we drop root. Also, set buffer size small, to avoid wasting
84      kernel buffers */
85 
86   if (daemon->options & OPT_NO_PING)
87     daemon->dhcp_icmp_fd = -1;
88   else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 ||
89 	   setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 )
90     die(_("cannot create ICMP raw socket: %s."), NULL, EC_BADNET);
91 
92   /* Make BPF raw send socket */
93   init_bpf();
94 #endif
95 
96   check_dhcp_hosts(1);
97 
98   daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
99   daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
100 }
101 
dhcp_packet(time_t now)102 void dhcp_packet(time_t now)
103 {
104   struct dhcp_packet *mess;
105   struct dhcp_context *context;
106   struct iname *tmp;
107   struct ifreq ifr;
108   struct msghdr msg;
109   struct sockaddr_in dest;
110   struct cmsghdr *cmptr;
111   struct iovec iov;
112   ssize_t sz;
113   int iface_index = 0, unicast_dest = 0, is_inform = 0;
114   struct in_addr iface_addr, *addrp = NULL;
115   struct iface_param parm;
116 
117   union {
118     struct cmsghdr align; /* this ensures alignment */
119 #if defined(HAVE_LINUX_NETWORK)
120     char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
121 #elif defined(HAVE_SOLARIS_NETWORK)
122     char control[CMSG_SPACE(sizeof(unsigned int))];
123 #elif defined(HAVE_BSD_NETWORK)
124     char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
125 #endif
126   } control_u;
127 
128   msg.msg_control = NULL;
129   msg.msg_controllen = 0;
130   msg.msg_name = NULL;
131   msg.msg_namelen = 0;
132   msg.msg_iov = &daemon->dhcp_packet;
133   msg.msg_iovlen = 1;
134 
135   while (1)
136     {
137       msg.msg_flags = 0;
138       while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
139 
140       if (sz == -1)
141 	return;
142 
143       if (!(msg.msg_flags & MSG_TRUNC))
144 	break;
145 
146       /* Very new Linux kernels return the actual size needed,
147 	 older ones always return truncated size */
148       if ((size_t)sz == daemon->dhcp_packet.iov_len)
149 	{
150 	  if (!expand_buf(&daemon->dhcp_packet, sz + 100))
151 	    return;
152 	}
153       else
154 	{
155 	  expand_buf(&daemon->dhcp_packet, sz);
156 	  break;
157 	}
158     }
159 
160   /* expand_buf may have moved buffer */
161   mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
162   msg.msg_controllen = sizeof(control_u);
163   msg.msg_control = control_u.control;
164   msg.msg_flags = 0;
165   msg.msg_name = &dest;
166   msg.msg_namelen = sizeof(dest);
167 
168   while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR);
169 
170   if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
171     return;
172 
173 #if defined (HAVE_LINUX_NETWORK)
174   if (msg.msg_controllen >= sizeof(struct cmsghdr))
175     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
176       if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
177 	{
178 	  iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
179 	  if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
180 	    unicast_dest = 1;
181 	}
182 
183 #elif defined(HAVE_BSD_NETWORK)
184   if (msg.msg_controllen >= sizeof(struct cmsghdr))
185     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
186       if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
187         iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
188 
189 
190 #elif defined(HAVE_SOLARIS_NETWORK)
191   if (msg.msg_controllen >= sizeof(struct cmsghdr))
192     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
193       if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
194 	iface_index = *((unsigned int *)CMSG_DATA(cmptr));
195 
196 #endif
197 
198   if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
199     return;
200 
201 #ifdef MSG_BCAST
202   /* OpenBSD tells us when a packet was broadcast */
203   if (!(msg.msg_flags & MSG_BCAST))
204     unicast_dest = 1;
205 #endif
206 
207   ifr.ifr_addr.sa_family = AF_INET;
208   if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
209     {
210       addrp = &iface_addr;
211       iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
212     }
213 
214   if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
215     return;
216 
217   for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
218     if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
219       return;
220 
221   /* interface may have been changed by alias in iface_check */
222   if (!addrp)
223     {
224       if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
225 	{
226 	  my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
227 	  return;
228 	}
229       else
230 	iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
231     }
232 
233   /* unlinked contexts are marked by context->current == context */
234   for (context = daemon->dhcp; context; context = context->next)
235     context->current = context;
236 
237   parm.relay = mess->giaddr;
238   parm.primary = iface_addr;
239   parm.current = NULL;
240   parm.ind = iface_index;
241 
242   if (!iface_enumerate(&parm, complete_context, NULL))
243     return;
244   lease_prune(NULL, now); /* lose any expired leases */
245   iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
246 			   now, unicast_dest, &is_inform);
247   lease_update_file(now);
248   lease_update_dns();
249 
250   if (iov.iov_len == 0)
251     return;
252 
253   msg.msg_name = &dest;
254   msg.msg_namelen = sizeof(dest);
255   msg.msg_control = NULL;
256   msg.msg_controllen = 0;
257   msg.msg_iov = &iov;
258   iov.iov_base = daemon->dhcp_packet.iov_base;
259 
260   /* packet buffer may have moved */
261   mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
262 
263 #ifdef HAVE_SOCKADDR_SA_LEN
264   dest.sin_len = sizeof(struct sockaddr_in);
265 #endif
266 
267   if (mess->giaddr.s_addr)
268     {
269       /* Send to BOOTP relay  */
270       dest.sin_port = htons(daemon->dhcp_server_port);
271       dest.sin_addr = mess->giaddr;
272     }
273   else if (mess->ciaddr.s_addr)
274     {
275       /* If the client's idea of its own address tallys with
276 	 the source address in the request packet, we believe the
277 	 source port too, and send back to that.  If we're replying
278 	 to a DHCPINFORM, trust the source address always. */
279       if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
280 	  dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
281 	{
282 	  dest.sin_port = htons(daemon->dhcp_client_port);
283 	  dest.sin_addr = mess->ciaddr;
284 	}
285     }
286 #if defined(HAVE_LINUX_NETWORK)
287   else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
288 	   mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
289     {
290       /* broadcast to 255.255.255.255 (or mac address invalid) */
291       struct in_pktinfo *pkt;
292       msg.msg_control = control_u.control;
293       msg.msg_controllen = sizeof(control_u);
294       cmptr = CMSG_FIRSTHDR(&msg);
295       pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
296       pkt->ipi_ifindex = iface_index;
297       pkt->ipi_spec_dst.s_addr = 0;
298       msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
299       cmptr->cmsg_level = SOL_IP;
300       cmptr->cmsg_type = IP_PKTINFO;
301       dest.sin_addr.s_addr = INADDR_BROADCAST;
302       dest.sin_port = htons(daemon->dhcp_client_port);
303     }
304   else
305     {
306       /* unicast to unconfigured client. Inject mac address direct into ARP cache.
307 	 struct sockaddr limits size to 14 bytes. */
308       struct arpreq req;
309       dest.sin_addr = mess->yiaddr;
310       dest.sin_port = htons(daemon->dhcp_client_port);
311       *((struct sockaddr_in *)&req.arp_pa) = dest;
312       req.arp_ha.sa_family = mess->htype;
313       memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
314       strncpy(req.arp_dev, ifr.ifr_name, 16);
315       req.arp_flags = ATF_COM;
316       ioctl(daemon->dhcpfd, SIOCSARP, &req);
317     }
318 #elif defined(HAVE_SOLARIS_NETWORK)
319   else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
320     {
321       /* broadcast to 255.255.255.255 (or mac address invalid) */
322       dest.sin_addr.s_addr = INADDR_BROADCAST;
323       dest.sin_port = htons(daemon->dhcp_client_port);
324       /* note that we don't specify the interface here: that's done by the
325 	 IP_BOUND_IF sockopt lower down. */
326     }
327   else
328     {
329       /* unicast to unconfigured client. Inject mac address direct into ARP cache.
330 	 Note that this only works for ethernet on solaris, because we use SIOCSARP
331 	 and not SIOCSXARP, which would be perfect, except that it returns ENXIO
332 	 mysteriously. Bah. Fall back to broadcast for other net types. */
333       struct arpreq req;
334       dest.sin_addr = mess->yiaddr;
335       dest.sin_port = htons(daemon->dhcp_client_port);
336       *((struct sockaddr_in *)&req.arp_pa) = dest;
337       req.arp_ha.sa_family = AF_UNSPEC;
338       memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
339       req.arp_flags = ATF_COM;
340       ioctl(daemon->dhcpfd, SIOCSARP, &req);
341     }
342 #elif defined(HAVE_BSD_NETWORK)
343   else
344     {
345       send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
346       return;
347     }
348 #endif
349 
350 #ifdef HAVE_SOLARIS_NETWORK
351   setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
352 #endif
353 
354   while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send());
355 }
356 
357 /* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
358    of each interface (and any relay address) and does the  following things:
359 
360    1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
361    2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
362    3) Fills in local (this host) and router (this host or relay) addresses.
363    4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
364 
365    Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
366 
complete_context(struct in_addr local,int if_index,struct in_addr netmask,struct in_addr broadcast,void * vparam)367 static int complete_context(struct in_addr local, int if_index,
368 			    struct in_addr netmask, struct in_addr broadcast, void *vparam)
369 {
370   struct dhcp_context *context;
371   struct iface_param *param = vparam;
372 
373   for (context = daemon->dhcp; context; context = context->next)
374     {
375       if (!(context->flags & CONTEXT_NETMASK) &&
376 	  (is_same_net(local, context->start, netmask) ||
377 	   is_same_net(local, context->end, netmask)))
378       {
379 	if (context->netmask.s_addr != netmask.s_addr &&
380 	    !(is_same_net(local, context->start, netmask) &&
381 	      is_same_net(local, context->end, netmask)))
382 	  {
383 	    strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
384 	    strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
385 	    my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
386 		      daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
387 	  }
388  	context->netmask = netmask;
389       }
390 
391       if (context->netmask.s_addr)
392 	{
393 	  if (is_same_net(local, context->start, context->netmask) &&
394 	      is_same_net(local, context->end, context->netmask))
395 	    {
396 	      /* link it onto the current chain if we've not seen it before */
397 	      if (if_index == param->ind && context->current == context)
398 		{
399 		  context->router = local;
400 		  context->local = local;
401 		  context->current = param->current;
402 		  param->current = context;
403 		}
404 
405 	      if (!(context->flags & CONTEXT_BRDCAST))
406 		{
407 		  if (is_same_net(broadcast, context->start, context->netmask))
408 		    context->broadcast = broadcast;
409 		  else
410 		    context->broadcast.s_addr  = context->start.s_addr | ~context->netmask.s_addr;
411 		}
412 	    }
413 	  else if (param->relay.s_addr && is_same_net(param->relay, context->start, context->netmask))
414 	    {
415 	      context->router = param->relay;
416 	      context->local = param->primary;
417 	      /* fill in missing broadcast addresses for relayed ranges */
418 	      if (!(context->flags & CONTEXT_BRDCAST))
419 		context->broadcast.s_addr  = context->start.s_addr | ~context->netmask.s_addr;
420 	    }
421 
422 	}
423     }
424 
425   return 1;
426 }
427 
address_available(struct dhcp_context * context,struct in_addr taddr,struct dhcp_netid * netids)428 struct dhcp_context *address_available(struct dhcp_context *context,
429 				       struct in_addr taddr,
430 				       struct dhcp_netid *netids)
431 {
432   /* Check is an address is OK for this network, check all
433      possible ranges. Make sure that the address isn't in use
434      by the server itself. */
435 
436   unsigned int start, end, addr = ntohl(taddr.s_addr);
437   struct dhcp_context *tmp;
438 
439   for (tmp = context; tmp; tmp = tmp->current)
440     if (taddr.s_addr == context->router.s_addr)
441       return NULL;
442 
443   for (tmp = context; tmp; tmp = tmp->current)
444     {
445       start = ntohl(tmp->start.s_addr);
446       end = ntohl(tmp->end.s_addr);
447 
448       if (!(tmp->flags & CONTEXT_STATIC) &&
449 	  addr >= start &&
450 	  addr <= end &&
451 	  match_netid(tmp->filter, netids, 1))
452 	return tmp;
453     }
454 
455   return NULL;
456 }
457 
narrow_context(struct dhcp_context * context,struct in_addr taddr,struct dhcp_netid * netids)458 struct dhcp_context *narrow_context(struct dhcp_context *context,
459 				    struct in_addr taddr,
460 				    struct dhcp_netid *netids)
461 {
462   /* We start of with a set of possible contexts, all on the current physical interface.
463      These are chained on ->current.
464      Here we have an address, and return the actual context correponding to that
465      address. Note that none may fit, if the address came a dhcp-host and is outside
466      any dhcp-range. In that case we return a static range if possible, or failing that,
467      any context on the correct subnet. (If there's more than one, this is a dodgy
468      configuration: maybe there should be a warning.) */
469 
470   struct dhcp_context *tmp;
471 
472   if (!(tmp = address_available(context, taddr, netids)))
473     {
474       for (tmp = context; tmp; tmp = tmp->current)
475 	if (is_same_net(taddr, tmp->start, tmp->netmask) &&
476 	    (tmp->flags & CONTEXT_STATIC))
477 	  break;
478 
479       if (!tmp)
480 	for (tmp = context; tmp; tmp = tmp->current)
481 	  if (is_same_net(taddr, tmp->start, tmp->netmask))
482 	    break;
483     }
484 
485   /* Only one context allowed now */
486   if (tmp)
487     tmp->current = NULL;
488 
489   return tmp;
490 }
491 
config_find_by_address(struct dhcp_config * configs,struct in_addr addr)492 struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
493 {
494   struct dhcp_config *config;
495 
496   for (config = configs; config; config = config->next)
497     if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
498       return config;
499 
500   return NULL;
501 }
502 
503 /* Is every member of check matched by a member of pool?
504    If tagnotneeded, untagged is OK */
match_netid(struct dhcp_netid * check,struct dhcp_netid * pool,int tagnotneeded)505 int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
506 {
507   struct dhcp_netid *tmp1;
508 
509   if (!check && !tagnotneeded)
510     return 0;
511 
512   for (; check; check = check->next)
513     {
514       if (check->net[0] != '#')
515 	{
516 	  for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
517 	    if (strcmp(check->net, tmp1->net) == 0)
518 	      break;
519 	  if (!tmp1)
520 	    return 0;
521 	}
522       else
523 	for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
524 	  if (strcmp((check->net)+1, tmp1->net) == 0)
525 	    return 0;
526     }
527   return 1;
528 }
529 
address_allocate(struct dhcp_context * context,struct in_addr * addrp,unsigned char * hwaddr,int hw_len,struct dhcp_netid * netids,time_t now)530 int address_allocate(struct dhcp_context *context,
531 		     struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
532 		     struct dhcp_netid *netids, time_t now)
533 {
534   /* Find a free address: exclude anything in use and anything allocated to
535      a particular hwaddr/clientid/hostname in our configuration.
536      Try to return from contexts which match netids first. */
537 
538   struct in_addr start, addr;
539   struct dhcp_context *c, *d;
540   int i, pass;
541   unsigned int j;
542 
543   /* hash hwaddr */
544   for (j = 0, i = 0; i < hw_len; i++)
545     j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
546 
547   for (pass = 0; pass <= 1; pass++)
548     for (c = context; c; c = c->current)
549       if (c->flags & CONTEXT_STATIC)
550 	continue;
551       else if (!match_netid(c->filter, netids, pass))
552 	continue;
553       else
554 	{
555 	  /* pick a seed based on hwaddr then iterate until we find a free address. */
556 	  start.s_addr = addr.s_addr =
557 	    htonl(ntohl(c->start.s_addr) +
558 		  ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
559 
560 	  do {
561 	    /* eliminate addresses in use by the server. */
562 	    for (d = context; d; d = d->current)
563 	      if (addr.s_addr == d->router.s_addr)
564 		break;
565 
566 	    /* Addresses which end in .255 and .0 are broken in Windows even when using
567 	       supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
568 	       then 192.168.0.255 is a valid IP address, but not for Windows as it's
569 	       in the class C range. See  KB281579. We therefore don't allocate these
570 	       addresses to avoid hard-to-diagnose problems. Thanks Bill. */
571 	    if (!d &&
572 		!lease_find_by_addr(addr) &&
573 		!config_find_by_address(daemon->dhcp_conf, addr) &&
574 		(!IN_CLASSC(ntohl(addr.s_addr)) ||
575 		 ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
576 	      {
577 		struct ping_result *r, *victim = NULL;
578 		int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
579 					      ((float)PING_WAIT)));
580 
581 		*addrp = addr;
582 
583 		if (daemon->options & OPT_NO_PING)
584 		  return 1;
585 
586 		/* check if we failed to ping addr sometime in the last
587 		   PING_CACHE_TIME seconds. If so, assume the same situation still exists.
588 		   This avoids problems when a stupid client bangs
589 		   on us repeatedly. As a final check, if we did more
590 		   than 60% of the possible ping checks in the last
591 		   PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
592 		for (count = 0, r = daemon->ping_results; r; r = r->next)
593 		  if (difftime(now, r->time) >  (float)PING_CACHE_TIME)
594 		    victim = r; /* old record */
595 		  else if (++count == max || r->addr.s_addr == addr.s_addr)
596 		    return 1;
597 
598 		if (icmp_ping(addr))
599 		  /* address in use: perturb address selection so that we are
600 		     less likely to try this address again. */
601 		  c->addr_epoch++;
602 		else
603 		  {
604 		    /* at this point victim may hold an expired record */
605 		    if (!victim)
606 		      {
607 			if ((victim = whine_malloc(sizeof(struct ping_result))))
608 			  {
609 			    victim->next = daemon->ping_results;
610 			    daemon->ping_results = victim;
611 			  }
612 		      }
613 
614 		    /* record that this address is OK for 30s
615 		       without more ping checks */
616 		    if (victim)
617 		      {
618 			victim->addr = addr;
619 			victim->time = now;
620 		      }
621 		    return 1;
622 		  }
623 	      }
624 
625 	    addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
626 
627 	    if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
628 	      addr = c->start;
629 
630 	  } while (addr.s_addr != start.s_addr);
631 	}
632   return 0;
633 }
634 
is_addr_in_context(struct dhcp_context * context,struct dhcp_config * config)635 static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config)
636 {
637   if (!context) /* called via find_config() from lease_update_from_configs() */
638     return 1;
639   if (!(config->flags & CONFIG_ADDR))
640     return 1;
641   for (; context; context = context->current)
642     if (is_same_net(config->addr, context->start, context->netmask))
643       return 1;
644 
645   return 0;
646 }
647 
config_has_mac(struct dhcp_config * config,unsigned char * hwaddr,int len,int type)648 int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
649 {
650   struct hwaddr_config *conf_addr;
651 
652   for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
653     if (conf_addr->wildcard_mask == 0 &&
654 	conf_addr->hwaddr_len == len &&
655 	(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
656 	memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
657       return 1;
658 
659   return 0;
660 }
661 
find_config(struct dhcp_config * configs,struct dhcp_context * context,unsigned char * clid,int clid_len,unsigned char * hwaddr,int hw_len,int hw_type,char * hostname)662 struct dhcp_config *find_config(struct dhcp_config *configs,
663 				struct dhcp_context *context,
664 				unsigned char *clid, int clid_len,
665 				unsigned char *hwaddr, int hw_len,
666 				int hw_type, char *hostname)
667 {
668   int count, new;
669   struct dhcp_config *config, *candidate;
670   struct hwaddr_config *conf_addr;
671 
672   if (clid)
673     for (config = configs; config; config = config->next)
674       if (config->flags & CONFIG_CLID)
675 	{
676 	  if (config->clid_len == clid_len &&
677 	      memcmp(config->clid, clid, clid_len) == 0 &&
678 	      is_addr_in_context(context, config))
679 	    return config;
680 
681 	  /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
682 	     cope with that here */
683 	  if (*clid == 0 && config->clid_len == clid_len-1  &&
684 	      memcmp(config->clid, clid+1, clid_len-1) == 0 &&
685 	      is_addr_in_context(context, config))
686 	    return config;
687 	}
688 
689 
690   for (config = configs; config; config = config->next)
691     if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
692 	is_addr_in_context(context, config))
693       return config;
694 
695   if (hostname && context)
696     for (config = configs; config; config = config->next)
697       if ((config->flags & CONFIG_NAME) &&
698 	  hostname_isequal(config->hostname, hostname) &&
699 	  is_addr_in_context(context, config))
700 	return config;
701 
702   /* use match with fewest wildcast octets */
703   for (candidate = NULL, count = 0, config = configs; config; config = config->next)
704     if (is_addr_in_context(context, config))
705       for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
706 	if (conf_addr->wildcard_mask != 0 &&
707 	    conf_addr->hwaddr_len == hw_len &&
708 	    (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
709 	    (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
710 	  {
711 	    count = new;
712 	    candidate = config;
713 	  }
714 
715   return candidate;
716 }
717 
dhcp_read_ethers(void)718 void dhcp_read_ethers(void)
719 {
720   FILE *f = fopen(ETHERSFILE, "r");
721   unsigned int flags;
722   char *buff = daemon->namebuff;
723   char *ip, *cp;
724   struct in_addr addr;
725   unsigned char hwaddr[ETHER_ADDR_LEN];
726   struct dhcp_config **up, *tmp;
727   struct dhcp_config *config;
728   int count = 0, lineno = 0;
729 
730   addr.s_addr = 0; /* eliminate warning */
731 
732   if (!f)
733     {
734       my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
735       return;
736     }
737 
738   /* This can be called again on SIGHUP, so remove entries created last time round. */
739   for (up = &daemon->dhcp_conf, config = daemon->dhcp_conf; config; config = tmp)
740     {
741       tmp = config->next;
742       if (config->flags & CONFIG_FROM_ETHERS)
743 	{
744 	  *up = tmp;
745 	  /* cannot have a clid */
746 	  if (config->flags & CONFIG_NAME)
747 	    free(config->hostname);
748 	  free(config->hwaddr);
749 	  free(config);
750 	}
751       else
752 	up = &config->next;
753     }
754 
755   while (fgets(buff, MAXDNAME, f))
756     {
757       char *host = NULL;
758 
759       lineno++;
760 
761       while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
762 	buff[strlen(buff)-1] = 0;
763 
764       if ((*buff == '#') || (*buff == '+') || (*buff == 0))
765 	continue;
766 
767       for (ip = buff; *ip && !isspace((int)*ip); ip++);
768       for(; *ip && isspace((int)*ip); ip++)
769 	*ip = 0;
770       if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
771 	{
772 	  my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
773 	  continue;
774 	}
775 
776       /* check for name or dotted-quad */
777       for (cp = ip; *cp; cp++)
778 	if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
779 	  break;
780 
781       if (!*cp)
782 	{
783 	  if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
784 	    {
785 	      my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
786 	      continue;
787 	    }
788 
789 	  flags = CONFIG_ADDR;
790 
791 	  for (config = daemon->dhcp_conf; config; config = config->next)
792 	    if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
793 	      break;
794 	}
795       else
796 	{
797 	  int nomem;
798 	  if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host))
799 	    {
800 	      if (!nomem)
801 		my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
802 	      free(host);
803 	      continue;
804 	    }
805 
806 	  flags = CONFIG_NAME;
807 
808 	  for (config = daemon->dhcp_conf; config; config = config->next)
809 	    if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host))
810 	      break;
811 	}
812 
813       if (config && (config->flags & CONFIG_FROM_ETHERS))
814 	{
815 	  my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno);
816 	  continue;
817 	}
818 
819       if (!config)
820 	{
821 	  for (config = daemon->dhcp_conf; config; config = config->next)
822 	    {
823 	      struct hwaddr_config *conf_addr = config->hwaddr;
824 	      if (conf_addr &&
825 		  conf_addr->next == NULL &&
826 		  conf_addr->wildcard_mask == 0 &&
827 		  conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
828 		  (conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
829 		  memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
830 		break;
831 	    }
832 
833 	  if (!config)
834 	    {
835 	      if (!(config = whine_malloc(sizeof(struct dhcp_config))))
836 		continue;
837 	      config->flags = CONFIG_FROM_ETHERS;
838 	      config->hwaddr = NULL;
839 	      config->domain = NULL;
840 	      config->next = daemon->dhcp_conf;
841 	      daemon->dhcp_conf = config;
842 	    }
843 
844 	  config->flags |= flags;
845 
846 	  if (flags & CONFIG_NAME)
847 	    {
848 	      config->hostname = host;
849 	      host = NULL;
850 	    }
851 
852 	  if (flags & CONFIG_ADDR)
853 	    config->addr = addr;
854 	}
855 
856       config->flags |= CONFIG_NOCLID;
857       if (!config->hwaddr)
858 	config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
859       if (config->hwaddr)
860 	{
861 	  memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
862 	  config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
863 	  config->hwaddr->hwaddr_type = ARPHRD_ETHER;
864 	  config->hwaddr->wildcard_mask = 0;
865 	  config->hwaddr->next = NULL;
866 	}
867       count++;
868 
869       free(host);
870 
871     }
872 
873   fclose(f);
874 
875   my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
876 }
877 
check_dhcp_hosts(int fatal)878 void check_dhcp_hosts(int fatal)
879 {
880   /* If the same IP appears in more than one host config, then DISCOVER
881      for one of the hosts will get the address, but REQUEST will be NAKed,
882      since the address is reserved by the other one -> protocol loop.
883      Also check that FQDNs match the domain we are using. */
884 
885   struct dhcp_config *configs, *cp;
886 
887   for (configs = daemon->dhcp_conf; configs; configs = configs->next)
888     {
889       char *domain;
890 
891       if ((configs->flags & DHOPT_BANK) || fatal)
892        {
893 	 for (cp = configs->next; cp; cp = cp->next)
894 	   if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
895 	     {
896 	       if (fatal)
897 		 die(_("duplicate IP address %s in dhcp-config directive."),
898 		     inet_ntoa(cp->addr), EC_BADCONF);
899 	       else
900 		 my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
901 			   inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
902 	       configs->flags &= ~CONFIG_ADDR;
903 	     }
904 
905 	 /* split off domain part */
906 	 if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
907 	   configs->domain = domain;
908        }
909     }
910 }
911 
dhcp_update_configs(struct dhcp_config * configs)912 void dhcp_update_configs(struct dhcp_config *configs)
913 {
914   /* Some people like to keep all static IP addresses in /etc/hosts.
915      This goes through /etc/hosts and sets static addresses for any DHCP config
916      records which don't have an address and whose name matches.
917      We take care to maintain the invariant that any IP address can appear
918      in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
919      restore the status-quo ante first. */
920 
921   struct dhcp_config *config;
922   struct crec *crec;
923 
924   for (config = configs; config; config = config->next)
925     if (config->flags & CONFIG_ADDR_HOSTS)
926       config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
927 
928 
929   if (daemon->port != 0)
930     for (config = configs; config; config = config->next)
931       if (!(config->flags & CONFIG_ADDR) &&
932 	  (config->flags & CONFIG_NAME) &&
933 	  (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
934 	  (crec->flags & F_HOSTS))
935 	{
936 	  if (cache_find_by_name(crec, config->hostname, 0, F_IPV4))
937 	    {
938 	      /* use primary (first) address */
939 	      while (crec && !(crec->flags & F_REVERSE))
940 		crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
941 	      if (!crec)
942 		continue; /* should be never */
943 	      my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
944 			config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
945 	    }
946 
947 	  if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
948 	    my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
949 		      inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
950 	  else
951 	    {
952 	      config->addr = crec->addr.addr.addr.addr4;
953 	      config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
954 	    }
955 	}
956 }
957 
958 /* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
959    for this address. If it has a domain part, that must match the set domain and
960    it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
961    so check here that the domain name is legal as a hostname. */
host_from_dns(struct in_addr addr)962 char *host_from_dns(struct in_addr addr)
963 {
964   struct crec *lookup;
965   char *hostname = NULL;
966   char *d1, *d2;
967 
968   if (daemon->port == 0)
969     return NULL; /* DNS disabled. */
970 
971   lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
972   if (lookup && (lookup->flags & F_HOSTS))
973     {
974       hostname = daemon->dhcp_buff;
975       strncpy(hostname, cache_get_name(lookup), 256);
976       hostname[255] = 0;
977       d1 = strip_hostname(hostname);
978       d2 = get_domain(addr);
979       if (!legal_hostname(hostname) || (d1 && (!d2 || !hostname_isequal(d1, d2))))
980 	hostname = NULL;
981     }
982 
983   return hostname;
984 }
985 
986 /* return domain or NULL if none. */
strip_hostname(char * hostname)987 char *strip_hostname(char *hostname)
988 {
989   char *dot = strchr(hostname, '.');
990 
991   if (!dot)
992     return NULL;
993 
994   *dot = 0; /* truncate */
995   if (strlen(dot+1) != 0)
996     return dot+1;
997 
998   return NULL;
999 }
1000 
1001 #endif
1002 
1003