Home | History | Annotate | Download | only in src
      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 
     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 
     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 
    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 
    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 
    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 
    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 */
    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 
    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 
    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 
    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 
    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 
    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 
    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. */
    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. */
    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