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