• 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   check_dhcp_hosts(1);
87 
88   daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
89   daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
90 }
91 
dhcp_packet(time_t now)92 void dhcp_packet(time_t now)
93 {
94   struct dhcp_packet *mess;
95   struct dhcp_context *context;
96   struct iname *tmp;
97   struct ifreq ifr;
98   struct msghdr msg;
99   struct sockaddr_in dest;
100   struct cmsghdr *cmptr;
101   struct iovec iov;
102   ssize_t sz;
103   int iface_index = 0, unicast_dest = 0, is_inform = 0;
104   struct in_addr iface_addr, *addrp = NULL;
105   struct iface_param parm;
106 
107   union {
108     struct cmsghdr align; /* this ensures alignment */
109 #if defined(HAVE_LINUX_NETWORK)
110     char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
111 #endif
112   } control_u;
113 
114   msg.msg_control = NULL;
115   msg.msg_controllen = 0;
116   msg.msg_name = NULL;
117   msg.msg_namelen = 0;
118   msg.msg_iov = &daemon->dhcp_packet;
119   msg.msg_iovlen = 1;
120 
121   while (1)
122     {
123       msg.msg_flags = 0;
124       while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
125 
126       if (sz == -1)
127 	return;
128 
129       if (!(msg.msg_flags & MSG_TRUNC))
130 	break;
131 
132       /* Very new Linux kernels return the actual size needed,
133 	 older ones always return truncated size */
134       if ((size_t)sz == daemon->dhcp_packet.iov_len)
135 	{
136 	  if (!expand_buf(&daemon->dhcp_packet, sz + 100))
137 	    return;
138 	}
139       else
140 	{
141 	  expand_buf(&daemon->dhcp_packet, sz);
142 	  break;
143 	}
144     }
145 
146   /* expand_buf may have moved buffer */
147   mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
148   msg.msg_controllen = sizeof(control_u);
149   msg.msg_control = control_u.control;
150   msg.msg_flags = 0;
151   msg.msg_name = &dest;
152   msg.msg_namelen = sizeof(dest);
153 
154   while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR);
155 
156   if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
157     return;
158 
159 #if defined (HAVE_LINUX_NETWORK)
160   if (msg.msg_controllen >= sizeof(struct cmsghdr))
161     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
162       if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
163 	{
164 	  iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
165 	  if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
166 	    unicast_dest = 1;
167 	}
168 #endif
169 
170   if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
171     return;
172 
173 #ifdef MSG_BCAST
174   /* OpenBSD tells us when a packet was broadcast */
175   if (!(msg.msg_flags & MSG_BCAST))
176     unicast_dest = 1;
177 #endif
178 
179   ifr.ifr_addr.sa_family = AF_INET;
180   if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
181     {
182       addrp = &iface_addr;
183       iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
184     }
185 
186   if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
187     return;
188 
189   for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
190     if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
191       return;
192 
193   /* interface may have been changed by alias in iface_check */
194   if (!addrp)
195     {
196       if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
197 	{
198 	  my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
199 	  return;
200 	}
201       else
202 	iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
203     }
204 
205   /* unlinked contexts are marked by context->current == context */
206   for (context = daemon->dhcp; context; context = context->next)
207     context->current = context;
208 
209   parm.relay = mess->giaddr;
210   parm.primary = iface_addr;
211   parm.current = NULL;
212   parm.ind = iface_index;
213 
214   if (!iface_enumerate(&parm, complete_context, NULL))
215     return;
216   lease_prune(NULL, now); /* lose any expired leases */
217   iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
218 			   now, unicast_dest, &is_inform);
219   lease_update_file(now);
220   lease_update_dns();
221 
222   if (iov.iov_len == 0)
223     return;
224 
225   msg.msg_name = &dest;
226   msg.msg_namelen = sizeof(dest);
227   msg.msg_control = NULL;
228   msg.msg_controllen = 0;
229   msg.msg_iov = &iov;
230   iov.iov_base = daemon->dhcp_packet.iov_base;
231 
232   /* packet buffer may have moved */
233   mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
234 
235 #ifdef HAVE_SOCKADDR_SA_LEN
236   dest.sin_len = sizeof(struct sockaddr_in);
237 #endif
238 
239   if (mess->giaddr.s_addr)
240     {
241       /* Send to BOOTP relay  */
242       dest.sin_port = htons(daemon->dhcp_server_port);
243       dest.sin_addr = mess->giaddr;
244     }
245   else if (mess->ciaddr.s_addr)
246     {
247       /* If the client's idea of its own address tallys with
248 	 the source address in the request packet, we believe the
249 	 source port too, and send back to that.  If we're replying
250 	 to a DHCPINFORM, trust the source address always. */
251       if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
252 	  dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
253 	{
254 	  dest.sin_port = htons(daemon->dhcp_client_port);
255 	  dest.sin_addr = mess->ciaddr;
256 	}
257     }
258 #if defined(HAVE_LINUX_NETWORK)
259   else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
260 	   mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
261     {
262       /* broadcast to 255.255.255.255 (or mac address invalid) */
263       struct in_pktinfo *pkt;
264       msg.msg_control = control_u.control;
265       msg.msg_controllen = sizeof(control_u);
266       cmptr = CMSG_FIRSTHDR(&msg);
267       pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
268       pkt->ipi_ifindex = iface_index;
269       pkt->ipi_spec_dst.s_addr = 0;
270       msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
271       cmptr->cmsg_level = SOL_IP;
272       cmptr->cmsg_type = IP_PKTINFO;
273       dest.sin_addr.s_addr = INADDR_BROADCAST;
274       dest.sin_port = htons(daemon->dhcp_client_port);
275     }
276   else
277     {
278       /* unicast to unconfigured client. Inject mac address direct into ARP cache.
279 	 struct sockaddr limits size to 14 bytes. */
280       struct arpreq req;
281       dest.sin_addr = mess->yiaddr;
282       dest.sin_port = htons(daemon->dhcp_client_port);
283       *((struct sockaddr_in *)&req.arp_pa) = dest;
284       req.arp_ha.sa_family = mess->htype;
285       memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
286       strncpy(req.arp_dev, ifr.ifr_name, 16);
287       req.arp_flags = ATF_COM;
288       ioctl(daemon->dhcpfd, SIOCSARP, &req);
289     }
290 #endif
291 
292   while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send());
293 }
294 
295 /* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
296    of each interface (and any relay address) and does the  following things:
297 
298    1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
299    2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
300    3) Fills in local (this host) and router (this host or relay) addresses.
301    4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
302 
303    Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
304 
complete_context(struct in_addr local,int if_index,struct in_addr netmask,struct in_addr broadcast,void * vparam)305 static int complete_context(struct in_addr local, int if_index,
306 			    struct in_addr netmask, struct in_addr broadcast, void *vparam)
307 {
308   struct dhcp_context *context;
309   struct iface_param *param = vparam;
310 
311   for (context = daemon->dhcp; context; context = context->next)
312     {
313       if (!(context->flags & CONTEXT_NETMASK) &&
314 	  (is_same_net(local, context->start, netmask) ||
315 	   is_same_net(local, context->end, netmask)))
316       {
317 	if (context->netmask.s_addr != netmask.s_addr &&
318 	    !(is_same_net(local, context->start, netmask) &&
319 	      is_same_net(local, context->end, netmask)))
320 	  {
321 	    strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
322 	    strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
323 	    my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
324 		      daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
325 	  }
326  	context->netmask = netmask;
327       }
328 
329       if (context->netmask.s_addr)
330 	{
331 	  if (is_same_net(local, context->start, context->netmask) &&
332 	      is_same_net(local, context->end, context->netmask))
333 	    {
334 	      /* link it onto the current chain if we've not seen it before */
335 	      if (if_index == param->ind && context->current == context)
336 		{
337 		  context->router = local;
338 		  context->local = local;
339 		  context->current = param->current;
340 		  param->current = context;
341 		}
342 
343 	      if (!(context->flags & CONTEXT_BRDCAST))
344 		{
345 		  if (is_same_net(broadcast, context->start, context->netmask))
346 		    context->broadcast = broadcast;
347 		  else
348 		    context->broadcast.s_addr  = context->start.s_addr | ~context->netmask.s_addr;
349 		}
350 	    }
351 	  else if (param->relay.s_addr && is_same_net(param->relay, context->start, context->netmask))
352 	    {
353 	      context->router = param->relay;
354 	      context->local = param->primary;
355 	      /* fill in missing broadcast addresses for relayed ranges */
356 	      if (!(context->flags & CONTEXT_BRDCAST))
357 		context->broadcast.s_addr  = context->start.s_addr | ~context->netmask.s_addr;
358 	    }
359 
360 	}
361     }
362 
363   return 1;
364 }
365 
address_available(struct dhcp_context * context,struct in_addr taddr,struct dhcp_netid * netids)366 struct dhcp_context *address_available(struct dhcp_context *context,
367 				       struct in_addr taddr,
368 				       struct dhcp_netid *netids)
369 {
370   /* Check is an address is OK for this network, check all
371      possible ranges. Make sure that the address isn't in use
372      by the server itself. */
373 
374   unsigned int start, end, addr = ntohl(taddr.s_addr);
375   struct dhcp_context *tmp;
376 
377   for (tmp = context; tmp; tmp = tmp->current)
378     if (taddr.s_addr == context->router.s_addr)
379       return NULL;
380 
381   for (tmp = context; tmp; tmp = tmp->current)
382     {
383       start = ntohl(tmp->start.s_addr);
384       end = ntohl(tmp->end.s_addr);
385 
386       if (!(tmp->flags & CONTEXT_STATIC) &&
387 	  addr >= start &&
388 	  addr <= end &&
389 	  match_netid(tmp->filter, netids, 1))
390 	return tmp;
391     }
392 
393   return NULL;
394 }
395 
narrow_context(struct dhcp_context * context,struct in_addr taddr,struct dhcp_netid * netids)396 struct dhcp_context *narrow_context(struct dhcp_context *context,
397 				    struct in_addr taddr,
398 				    struct dhcp_netid *netids)
399 {
400   /* We start of with a set of possible contexts, all on the current physical interface.
401      These are chained on ->current.
402      Here we have an address, and return the actual context correponding to that
403      address. Note that none may fit, if the address came a dhcp-host and is outside
404      any dhcp-range. In that case we return a static range if possible, or failing that,
405      any context on the correct subnet. (If there's more than one, this is a dodgy
406      configuration: maybe there should be a warning.) */
407 
408   struct dhcp_context *tmp;
409 
410   if (!(tmp = address_available(context, taddr, netids)))
411     {
412       for (tmp = context; tmp; tmp = tmp->current)
413 	if (is_same_net(taddr, tmp->start, tmp->netmask) &&
414 	    (tmp->flags & CONTEXT_STATIC))
415 	  break;
416 
417       if (!tmp)
418 	for (tmp = context; tmp; tmp = tmp->current)
419 	  if (is_same_net(taddr, tmp->start, tmp->netmask))
420 	    break;
421     }
422 
423   /* Only one context allowed now */
424   if (tmp)
425     tmp->current = NULL;
426 
427   return tmp;
428 }
429 
config_find_by_address(struct dhcp_config * configs,struct in_addr addr)430 struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
431 {
432   struct dhcp_config *config;
433 
434   for (config = configs; config; config = config->next)
435     if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
436       return config;
437 
438   return NULL;
439 }
440 
441 /* Is every member of check matched by a member of pool?
442    If tagnotneeded, untagged is OK */
match_netid(struct dhcp_netid * check,struct dhcp_netid * pool,int tagnotneeded)443 int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
444 {
445   struct dhcp_netid *tmp1;
446 
447   if (!check && !tagnotneeded)
448     return 0;
449 
450   for (; check; check = check->next)
451     {
452       if (check->net[0] != '#')
453 	{
454 	  for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
455 	    if (strcmp(check->net, tmp1->net) == 0)
456 	      break;
457 	  if (!tmp1)
458 	    return 0;
459 	}
460       else
461 	for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
462 	  if (strcmp((check->net)+1, tmp1->net) == 0)
463 	    return 0;
464     }
465   return 1;
466 }
467 
address_allocate(struct dhcp_context * context,struct in_addr * addrp,unsigned char * hwaddr,int hw_len,struct dhcp_netid * netids,time_t now)468 int address_allocate(struct dhcp_context *context,
469 		     struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
470 		     struct dhcp_netid *netids, time_t now)
471 {
472   /* Find a free address: exclude anything in use and anything allocated to
473      a particular hwaddr/clientid/hostname in our configuration.
474      Try to return from contexts which match netids first. */
475 
476   struct in_addr start, addr;
477   struct dhcp_context *c, *d;
478   int i, pass;
479   unsigned int j;
480 
481   /* hash hwaddr */
482   for (j = 0, i = 0; i < hw_len; i++)
483     j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
484 
485   for (pass = 0; pass <= 1; pass++)
486     for (c = context; c; c = c->current)
487       if (c->flags & CONTEXT_STATIC)
488 	continue;
489       else if (!match_netid(c->filter, netids, pass))
490 	continue;
491       else
492 	{
493 	  /* pick a seed based on hwaddr then iterate until we find a free address. */
494 	  start.s_addr = addr.s_addr =
495 	    htonl(ntohl(c->start.s_addr) +
496 		  ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
497 
498 	  do {
499 	    /* eliminate addresses in use by the server. */
500 	    for (d = context; d; d = d->current)
501 	      if (addr.s_addr == d->router.s_addr)
502 		break;
503 
504 	    /* Addresses which end in .255 and .0 are broken in Windows even when using
505 	       supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
506 	       then 192.168.0.255 is a valid IP address, but not for Windows as it's
507 	       in the class C range. See  KB281579. We therefore don't allocate these
508 	       addresses to avoid hard-to-diagnose problems. Thanks Bill. */
509 	    if (!d &&
510 		!lease_find_by_addr(addr) &&
511 		!config_find_by_address(daemon->dhcp_conf, addr) &&
512 		(!IN_CLASSC(ntohl(addr.s_addr)) ||
513 		 ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
514 	      {
515 		struct ping_result *r, *victim = NULL;
516 		int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
517 					      ((float)PING_WAIT)));
518 
519 		*addrp = addr;
520 
521 		if (daemon->options & OPT_NO_PING)
522 		  return 1;
523 
524 		/* check if we failed to ping addr sometime in the last
525 		   PING_CACHE_TIME seconds. If so, assume the same situation still exists.
526 		   This avoids problems when a stupid client bangs
527 		   on us repeatedly. As a final check, if we did more
528 		   than 60% of the possible ping checks in the last
529 		   PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
530 		for (count = 0, r = daemon->ping_results; r; r = r->next)
531 		  if (difftime(now, r->time) >  (float)PING_CACHE_TIME)
532 		    victim = r; /* old record */
533 		  else if (++count == max || r->addr.s_addr == addr.s_addr)
534 		    return 1;
535 
536 		if (icmp_ping(addr))
537 		  /* address in use: perturb address selection so that we are
538 		     less likely to try this address again. */
539 		  c->addr_epoch++;
540 		else
541 		  {
542 		    /* at this point victim may hold an expired record */
543 		    if (!victim)
544 		      {
545 			if ((victim = whine_malloc(sizeof(struct ping_result))))
546 			  {
547 			    victim->next = daemon->ping_results;
548 			    daemon->ping_results = victim;
549 			  }
550 		      }
551 
552 		    /* record that this address is OK for 30s
553 		       without more ping checks */
554 		    if (victim)
555 		      {
556 			victim->addr = addr;
557 			victim->time = now;
558 		      }
559 		    return 1;
560 		  }
561 	      }
562 
563 	    addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
564 
565 	    if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
566 	      addr = c->start;
567 
568 	  } while (addr.s_addr != start.s_addr);
569 	}
570   return 0;
571 }
572 
is_addr_in_context(struct dhcp_context * context,struct dhcp_config * config)573 static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config)
574 {
575   if (!context) /* called via find_config() from lease_update_from_configs() */
576     return 1;
577   if (!(config->flags & CONFIG_ADDR))
578     return 1;
579   for (; context; context = context->current)
580     if (is_same_net(config->addr, context->start, context->netmask))
581       return 1;
582 
583   return 0;
584 }
585 
config_has_mac(struct dhcp_config * config,unsigned char * hwaddr,int len,int type)586 int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
587 {
588   struct hwaddr_config *conf_addr;
589 
590   for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
591     if (conf_addr->wildcard_mask == 0 &&
592 	conf_addr->hwaddr_len == len &&
593 	(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
594 	memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
595       return 1;
596 
597   return 0;
598 }
599 
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)600 struct dhcp_config *find_config(struct dhcp_config *configs,
601 				struct dhcp_context *context,
602 				unsigned char *clid, int clid_len,
603 				unsigned char *hwaddr, int hw_len,
604 				int hw_type, char *hostname)
605 {
606   int count, new;
607   struct dhcp_config *config, *candidate;
608   struct hwaddr_config *conf_addr;
609 
610   if (clid)
611     for (config = configs; config; config = config->next)
612       if (config->flags & CONFIG_CLID)
613 	{
614 	  if (config->clid_len == clid_len &&
615 	      memcmp(config->clid, clid, clid_len) == 0 &&
616 	      is_addr_in_context(context, config))
617 	    return config;
618 
619 	  /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
620 	     cope with that here */
621 	  if (*clid == 0 && config->clid_len == clid_len-1  &&
622 	      memcmp(config->clid, clid+1, clid_len-1) == 0 &&
623 	      is_addr_in_context(context, config))
624 	    return config;
625 	}
626 
627 
628   for (config = configs; config; config = config->next)
629     if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
630 	is_addr_in_context(context, config))
631       return config;
632 
633   if (hostname && context)
634     for (config = configs; config; config = config->next)
635       if ((config->flags & CONFIG_NAME) &&
636 	  hostname_isequal(config->hostname, hostname) &&
637 	  is_addr_in_context(context, config))
638 	return config;
639 
640   /* use match with fewest wildcast octets */
641   for (candidate = NULL, count = 0, config = configs; config; config = config->next)
642     if (is_addr_in_context(context, config))
643       for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
644 	if (conf_addr->wildcard_mask != 0 &&
645 	    conf_addr->hwaddr_len == hw_len &&
646 	    (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
647 	    (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
648 	  {
649 	    count = new;
650 	    candidate = config;
651 	  }
652 
653   return candidate;
654 }
655 
check_dhcp_hosts(int fatal)656 void check_dhcp_hosts(int fatal)
657 {
658   /* If the same IP appears in more than one host config, then DISCOVER
659      for one of the hosts will get the address, but REQUEST will be NAKed,
660      since the address is reserved by the other one -> protocol loop.
661      Also check that FQDNs match the domain we are using. */
662 
663   struct dhcp_config *configs, *cp;
664 
665   for (configs = daemon->dhcp_conf; configs; configs = configs->next)
666     {
667       char *domain;
668 
669       if ((configs->flags & DHOPT_BANK) || fatal)
670        {
671 	 for (cp = configs->next; cp; cp = cp->next)
672 	   if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
673 	     {
674 	       if (fatal)
675 		 die(_("duplicate IP address %s in dhcp-config directive."),
676 		     inet_ntoa(cp->addr), EC_BADCONF);
677 	       else
678 		 my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
679 			   inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
680 	       configs->flags &= ~CONFIG_ADDR;
681 	     }
682 
683 	 /* split off domain part */
684 	 if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
685 	   configs->domain = domain;
686        }
687     }
688 }
689 
dhcp_update_configs(struct dhcp_config * configs)690 void dhcp_update_configs(struct dhcp_config *configs)
691 {
692   /* Some people like to keep all static IP addresses in /etc/hosts.
693      This goes through /etc/hosts and sets static addresses for any DHCP config
694      records which don't have an address and whose name matches.
695      We take care to maintain the invariant that any IP address can appear
696      in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
697      restore the status-quo ante first. */
698 
699   struct dhcp_config *config;
700   struct crec *crec;
701 
702   for (config = configs; config; config = config->next)
703     if (config->flags & CONFIG_ADDR_HOSTS)
704       config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
705 
706 
707   if (daemon->port != 0)
708     for (config = configs; config; config = config->next)
709       if (!(config->flags & CONFIG_ADDR) &&
710 	  (config->flags & CONFIG_NAME) &&
711 	  (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
712 	  (crec->flags & F_HOSTS))
713 	{
714 	  if (cache_find_by_name(crec, config->hostname, 0, F_IPV4))
715 	    {
716 	      /* use primary (first) address */
717 	      while (crec && !(crec->flags & F_REVERSE))
718 		crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
719 	      if (!crec)
720 		continue; /* should be never */
721 	      my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
722 			config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
723 	    }
724 
725 	  if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
726 	    my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
727 		      inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
728 	  else
729 	    {
730 	      config->addr = crec->addr.addr.addr.addr4;
731 	      config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
732 	    }
733 	}
734 }
735 
736 /* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
737    for this address. If it has a domain part, that must match the set domain and
738    it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
739    so check here that the domain name is legal as a hostname. */
host_from_dns(struct in_addr addr)740 char *host_from_dns(struct in_addr addr)
741 {
742   struct crec *lookup;
743   char *hostname = NULL;
744   char *d1, *d2;
745 
746   if (daemon->port == 0)
747     return NULL; /* DNS disabled. */
748 
749   lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
750   if (lookup && (lookup->flags & F_HOSTS))
751     {
752       hostname = daemon->dhcp_buff;
753       strncpy(hostname, cache_get_name(lookup), 256);
754       hostname[255] = 0;
755       d1 = strip_hostname(hostname);
756       d2 = get_domain(addr);
757       if (!legal_hostname(hostname) || (d1 && (!d2 || !hostname_isequal(d1, d2))))
758 	hostname = NULL;
759     }
760 
761   return hostname;
762 }
763 
764 /* return domain or NULL if none. */
strip_hostname(char * hostname)765 char *strip_hostname(char *hostname)
766 {
767   char *dot = strchr(hostname, '.');
768 
769   if (!dot)
770     return NULL;
771 
772   *dot = 0; /* truncate */
773   if (strlen(dot+1) != 0)
774     return dot+1;
775 
776   return NULL;
777 }
778 
779 #endif
780 
781