import of dnsmasq-2.48.tar.gz
diff --git a/src/dhcp.c b/src/dhcp.c
index 706f8d4..3a9ffd7 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -16,6 +16,8 @@
 
 #include "dnsmasq.h"
 
+#ifdef HAVE_DHCP
+
 struct iface_param {
   struct in_addr relay, primary;
   struct dhcp_context *current;
@@ -35,7 +37,7 @@
 #endif
 
   if (fd == -1)
-    die (_("cannot create DHCP socket : %s"), NULL, EC_BADNET);
+    die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
   
   if (!fix_fd(fd) ||
 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
@@ -43,7 +45,7 @@
 #endif
 #if defined(HAVE_LINUX_NETWORK)
       setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
-#elif defined(IP_RECVIF)
+#else
       setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
 #endif
       setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)  
@@ -51,12 +53,7 @@
   
   /* When bind-interfaces is set, there might be more than one dnmsasq
      instance binding port 67. That's OK if they serve different networks.
-     Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD.
-     OpenBSD <= 4.0 screws up IP_RECVIF when SO_REUSEPORT is set, but
-     OpenBSD <= 3.9 doesn't have IP_RECVIF anyway, so we just have to elide
-     this for OpenBSD 4.0, if you want more than one instance on oBSD4.0, tough. */
-
-#ifndef OpenBSD4_0
+     Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
   if (daemon->options & OPT_NOWILD)
     {
 #ifdef SO_REUSEPORT
@@ -67,7 +64,6 @@
       if (rc == -1)
 	die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
     }
-#endif
   
   memset(&saddr, 0, sizeof(saddr));
   saddr.sin_family = AF_INET;
@@ -124,7 +120,7 @@
     char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
 #elif defined(HAVE_SOLARIS_NETWORK)
     char control[CMSG_SPACE(sizeof(unsigned int))];
-#elif defined(IP_RECVIF) 
+#elif defined(HAVE_BSD_NETWORK) 
     char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
 #endif
   } control_u;
@@ -136,13 +132,30 @@
   msg.msg_iov = &daemon->dhcp_packet;
   msg.msg_iovlen = 1;
   
-  do
+  while (1)
     {
       msg.msg_flags = 0;
-      while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
+      while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
+      
+      if (sz == -1)
+	return;
+      
+      if (!(msg.msg_flags & MSG_TRUNC))
+	break;
+
+      /* Very new Linux kernels return the actual size needed, 
+	 older ones always return truncated size */
+      if ((size_t)sz == daemon->dhcp_packet.iov_len)
+	{
+	  if (!expand_buf(&daemon->dhcp_packet, sz + 100))
+	    return;
+	}
+      else
+	{
+	  expand_buf(&daemon->dhcp_packet, sz);
+	  break;
+	}
     }
-  while (sz != -1 && (msg.msg_flags & MSG_TRUNC) &&
-	 expand_buf(&daemon->dhcp_packet, daemon->dhcp_packet.iov_len + 100));
   
   /* expand_buf may have moved buffer */
   mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
@@ -154,7 +167,7 @@
 
   while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR);
  
-  if (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
+  if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
     return;
   
 #if defined (HAVE_LINUX_NETWORK)
@@ -166,41 +179,31 @@
 	  if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
 	    unicast_dest = 1;
 	}
-  
-  if (!(ifr.ifr_ifindex = iface_index) || 
-      ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) == -1)
-    return;
-  
-#elif defined(IP_RECVIF)
+
+#elif defined(HAVE_BSD_NETWORK) 
   if (msg.msg_controllen >= sizeof(struct cmsghdr))
     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
       if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
-#ifdef HAVE_SOLARIS_NETWORK
-	iface_index = *((unsigned int *)CMSG_DATA(cmptr));
-#else
         iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
-#endif
-	  
-  if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name))
-    return;
+
   
+#elif defined(HAVE_SOLARIS_NETWORK) 
+  if (msg.msg_controllen >= sizeof(struct cmsghdr))
+    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+      if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
+	iface_index = *((unsigned int *)CMSG_DATA(cmptr));
+	  
+#endif
+	
+  if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
+    return;
+
 #ifdef MSG_BCAST
   /* OpenBSD tells us when a packet was broadcast */
   if (!(msg.msg_flags & MSG_BCAST))
     unicast_dest = 1;
 #endif
 
-#else
-  /* fallback for systems without IP_RECVIF - allow only one interface
-     and assume packets arrive from it - yuk. */
-  {
-    struct iname *name;
-    for (name = daemon->if_names; name->isloop; name = name->next);
-    strcpy(ifr.ifr_name, name->name);
-    iface_index = if_nametoindex(name->name);
-  }
-#endif
-  
   ifr.ifr_addr.sa_family = AF_INET;
   if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
     {
@@ -208,7 +211,7 @@
       iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
     }
 
-  if (!iface_check(AF_INET, (struct all_addr *)addrp, &ifr, &iface_index))
+  if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
     return;
   
   for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
@@ -218,9 +221,9 @@
   /* interface may have been changed by alias in iface_check */
   if (!addrp)
     {
-      if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1)
+      if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
 	{
-	  my_syslog(LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
+	  my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
 	  return;
 	}
       else
@@ -319,7 +322,7 @@
       dest.sin_addr.s_addr = INADDR_BROADCAST;
       dest.sin_port = htons(daemon->dhcp_client_port);
       /* note that we don't specify the interface here: that's done by the
-	 IP_XMIT_IF sockopt lower down. */
+	 IP_BOUND_IF sockopt lower down. */
     }
   else
     {
@@ -345,12 +348,7 @@
 #endif
    
 #ifdef HAVE_SOLARIS_NETWORK
-  /* OpenSolaris eliminates IP_XMIT_IF */
-#  ifdef IP_XMIT_IF
-  setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_XMIT_IF, &iface_index, sizeof(iface_index));
-#  else
   setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
-#  endif
 #endif
   
   while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send());
@@ -384,7 +382,7 @@
 	  {
 	    strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
 	    strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
-	    my_syslog(LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
+	    my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
 		      daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
 	  }	
  	context->netmask = netmask;
@@ -474,9 +472,9 @@
   if (!(tmp = address_available(context, taddr, netids)))
     {
       for (tmp = context; tmp; tmp = tmp->current)
-      if (is_same_net(taddr, tmp->start, tmp->netmask) && 
-	  (tmp->flags & CONTEXT_STATIC))
-	break;
+	if (is_same_net(taddr, tmp->start, tmp->netmask) && 
+	    (tmp->flags & CONTEXT_STATIC))
+	  break;
       
       if (!tmp)
 	for (tmp = context; tmp; tmp = tmp->current)
@@ -667,7 +665,8 @@
 				unsigned char *hwaddr, int hw_len, 
 				int hw_type, char *hostname)
 {
-  struct dhcp_config *config; 
+  int count, new;
+  struct dhcp_config *config, *candidate; 
   struct hwaddr_config *conf_addr;
 
   if (clid)
@@ -699,17 +698,21 @@
 	  hostname_isequal(config->hostname, hostname) &&
 	  is_addr_in_context(context, config))
 	return config;
-  
-  for (config = configs; config; config = config->next)
-    for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
-      if (conf_addr->wildcard_mask != 0 &&
-	  conf_addr->hwaddr_len == hw_len &&	
-	  (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
-	  is_addr_in_context(context, config) &&
-	  memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask))
-	return config;
-  
-  return NULL;
+
+  /* use match with fewest wildcast octets */
+  for (candidate = NULL, count = 0, config = configs; config; config = config->next)
+    if (is_addr_in_context(context, config))
+      for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
+	if (conf_addr->wildcard_mask != 0 &&
+	    conf_addr->hwaddr_len == hw_len &&	
+	    (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
+	    (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
+	  {
+	    count = new;
+	    candidate = config;
+	  }
+
+  return candidate;
 }
 
 void dhcp_read_ethers(void)
@@ -728,7 +731,7 @@
   
   if (!f)
     {
-      my_syslog(LOG_ERR, _("failed to read %s:%s"), ETHERSFILE, strerror(errno));
+      my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
       return;
     }
 
@@ -764,7 +767,7 @@
 	*ip = 0;
       if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
 	{
-	  my_syslog(LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno); 
+	  my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno); 
 	  continue;
 	}
       
@@ -777,7 +780,7 @@
 	{
 	  if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
 	    {
-	      my_syslog(LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno); 
+	      my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno); 
 	      continue;
 	    }
 
@@ -791,7 +794,7 @@
 	{
 	  if (!canonicalise(ip))
 	    {
-	      my_syslog(LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno); 
+	      my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno); 
 	      continue;
 	    }
 	      
@@ -857,7 +860,7 @@
   
   fclose(f);
 
-  my_syslog(LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
+  my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
 }
 
 void check_dhcp_hosts(int fatal)
@@ -882,7 +885,7 @@
 		 die(_("duplicate IP address %s in dhcp-config directive."), 
 		     inet_ntoa(cp->addr), EC_BADCONF);
 	       else
-		 my_syslog(LOG_ERR, _("duplicate IP address %s in %s."), 
+		 my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."), 
 			   inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
 	       configs->flags &= ~CONFIG_ADDR;
 	     }
@@ -925,12 +928,12 @@
 		crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
 	      if (!crec)
 		continue; /* should be never */
-	      my_syslog(LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), 
+	      my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), 
 			config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
 	    }
 
 	  if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
-	    my_syslog(LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"), 
+	    my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"), 
 		      inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
 	  else 
 	    {
@@ -982,14 +985,5 @@
   return NULL;
 }
 
-char *get_domain(struct in_addr addr)
-{
-  struct cond_domain *c;
+#endif
 
-  for (c = daemon->cond_domain; c; c = c->next)
-    if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
-	ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
-      return c->domain;
-  
-  return daemon->domain_suffix;
-}