dhcp.c revision ffd68729961f7383f2e35494a03ccdef20f86c98
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
2a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
3a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt   This program is free software; you can redistribute it and/or modify
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   it under the terms of the GNU General Public License as published by
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt   the Free Software Foundation; version 2 dated June, 1991, or
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt   (at your option) version 3 dated 29 June, 2007.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   This program is distributed in the hope that it will be useful,
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   but WITHOUT ANY WARRANTY; without even the implied warranty of
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   GNU General Public License for more details.
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   You should have received a copy of the GNU General Public License
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   along with this program.  If not, see <http://www.gnu.org/licenses/>.
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt*/
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "dnsmasq.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HAVE_DHCP
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iface_param {
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct in_addr relay, primary;
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct dhcp_context *current;
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int ind;
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int complete_context(struct in_addr local, int if_index,
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct in_addr netmask, struct in_addr broadcast, void *vparam);
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid dhcp_init(void)
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct sockaddr_in saddr;
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int oneopt = 1;
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int mtu = IP_PMTUDISC_DONT;
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (fd == -1)
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (!fix_fd(fd) ||
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(HAVE_LINUX_NETWORK)
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET);
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* When bind-interfaces is set, there might be more than one dnmsasq
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     instance binding port 67. That's OK if they serve different networks.
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (daemon->options & OPT_NOWILD)
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef SO_REUSEPORT
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (rc == -1)
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  memset(&saddr, 0, sizeof(saddr));
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  saddr.sin_family = AF_INET;
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  saddr.sin_port = htons(daemon->dhcp_server_port);
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  saddr.sin_addr.s_addr = INADDR_ANY;
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HAVE_SOCKADDR_SA_LEN
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  saddr.sin_len = sizeof(struct sockaddr_in);
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  daemon->dhcpfd = fd;
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(HAVE_BSD_NETWORK)
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* When we're not using capabilities, we need to do this here before
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     we drop root. Also, set buffer size small, to avoid wasting
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     kernel buffers */
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (daemon->options & OPT_NO_PING)
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    daemon->dhcp_icmp_fd = -1;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 ||
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	   setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 )
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    die(_("cannot create ICMP raw socket: %s."), NULL, EC_BADNET);
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* Make BPF raw send socket */
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  init_bpf();
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  check_dhcp_hosts(1);
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid dhcp_packet(time_t now)
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct dhcp_packet *mess;
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct dhcp_context *context;
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct iname *tmp;
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct ifreq ifr;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct msghdr msg;
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct sockaddr_in dest;
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct cmsghdr *cmptr;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct iovec iov;
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  ssize_t sz;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int iface_index = 0, unicast_dest = 0, is_inform = 0;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct in_addr iface_addr, *addrp = NULL;
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct iface_param parm;
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  union {
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    struct cmsghdr align; /* this ensures alignment */
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(HAVE_LINUX_NETWORK)
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(HAVE_SOLARIS_NETWORK)
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    char control[CMSG_SPACE(sizeof(unsigned int))];
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(HAVE_BSD_NETWORK)
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } control_u;
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_control = NULL;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_controllen = 0;
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_name = NULL;
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_namelen = 0;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_iov = &daemon->dhcp_packet;
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_iovlen = 1;
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (1)
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
1371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt      msg.msg_flags = 0;
1381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt      while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (sz == -1)
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return;
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (!(msg.msg_flags & MSG_TRUNC))
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	break;
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* Very new Linux kernels return the actual size needed,
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 older ones always return truncated size */
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((size_t)sz == daemon->dhcp_packet.iov_len)
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  if (!expand_buf(&daemon->dhcp_packet, sz + 100))
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    return;
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      else
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  expand_buf(&daemon->dhcp_packet, sz);
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  break;
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* expand_buf may have moved buffer */
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_controllen = sizeof(control_u);
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_control = control_u.control;
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_flags = 0;
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_name = &dest;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_namelen = sizeof(dest);
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR);
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return;
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined (HAVE_LINUX_NETWORK)
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (msg.msg_controllen >= sizeof(struct cmsghdr))
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    unicast_dest = 1;
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(HAVE_BSD_NETWORK)
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (msg.msg_controllen >= sizeof(struct cmsghdr))
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(HAVE_SOLARIS_NETWORK)
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (msg.msg_controllen >= sizeof(struct cmsghdr))
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iface_index = *((unsigned int *)CMSG_DATA(cmptr));
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return;
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef MSG_BCAST
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* OpenBSD tells us when a packet was broadcast */
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (!(msg.msg_flags & MSG_BCAST))
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    unicast_dest = 1;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  ifr.ifr_addr.sa_family = AF_INET;
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      addrp = &iface_addr;
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return;
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return;
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* interface may have been changed by alias in iface_check */
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (!addrp)
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  return;
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      else
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* unlinked contexts are marked by context->current == context */
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (context = daemon->dhcp; context; context = context->next)
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    context->current = context;
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  parm.relay = mess->giaddr;
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  parm.primary = iface_addr;
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  parm.current = NULL;
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  parm.ind = iface_index;
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (!iface_enumerate(&parm, complete_context, NULL))
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return;
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  lease_prune(NULL, now); /* lose any expired leases */
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   now, unicast_dest, &is_inform);
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  lease_update_file(now);
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  lease_update_dns();
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (iov.iov_len == 0)
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return;
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_name = &dest;
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_namelen = sizeof(dest);
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_control = NULL;
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_controllen = 0;
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  msg.msg_iov = &iov;
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  iov.iov_base = daemon->dhcp_packet.iov_base;
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* packet buffer may have moved */
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HAVE_SOCKADDR_SA_LEN
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  dest.sin_len = sizeof(struct sockaddr_in);
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mess->giaddr.s_addr)
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* Send to BOOTP relay  */
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      dest.sin_port = htons(daemon->dhcp_server_port);
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      dest.sin_addr = mess->giaddr;
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  else if (mess->ciaddr.s_addr)
27450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt    {
27550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt      /* If the client's idea of its own address tallys with
27650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	 the source address in the request packet, we believe the
27750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	 source port too, and send back to that.  If we're replying
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 to a DHCPINFORM, trust the source address always. */
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  dest.sin_port = htons(daemon->dhcp_client_port);
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  dest.sin_addr = mess->ciaddr;
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(HAVE_LINUX_NETWORK)
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	   mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* broadcast to 255.255.255.255 (or mac address invalid) */
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      struct in_pktinfo *pkt;
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      msg.msg_control = control_u.control;
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      msg.msg_controllen = sizeof(control_u);
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      cmptr = CMSG_FIRSTHDR(&msg);
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      pkt->ipi_ifindex = iface_index;
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      pkt->ipi_spec_dst.s_addr = 0;
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      cmptr->cmsg_level = SOL_IP;
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      cmptr->cmsg_type = IP_PKTINFO;
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      dest.sin_addr.s_addr = INADDR_BROADCAST;
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      dest.sin_port = htons(daemon->dhcp_client_port);
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  else
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* unicast to unconfigured client. Inject mac address direct into ARP cache.
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 struct sockaddr limits size to 14 bytes. */
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      struct arpreq req;
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      dest.sin_addr = mess->yiaddr;
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      dest.sin_port = htons(daemon->dhcp_client_port);
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *((struct sockaddr_in *)&req.arp_pa) = dest;
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      req.arp_ha.sa_family = mess->htype;
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      strncpy(req.arp_dev, ifr.ifr_name, 16);
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      req.arp_flags = ATF_COM;
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      ioctl(daemon->dhcpfd, SIOCSARP, &req);
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(HAVE_SOLARIS_NETWORK)
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* broadcast to 255.255.255.255 (or mac address invalid) */
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      dest.sin_addr.s_addr = INADDR_BROADCAST;
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      dest.sin_port = htons(daemon->dhcp_client_port);
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* note that we don't specify the interface here: that's done by the
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 IP_BOUND_IF sockopt lower down. */
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  else
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* unicast to unconfigured client. Inject mac address direct into ARP cache.
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 Note that this only works for ethernet on solaris, because we use SIOCSARP
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 and not SIOCSXARP, which would be perfect, except that it returns ENXIO
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 mysteriously. Bah. Fall back to broadcast for other net types. */
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      struct arpreq req;
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      dest.sin_addr = mess->yiaddr;
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      dest.sin_port = htons(daemon->dhcp_client_port);
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *((struct sockaddr_in *)&req.arp_pa) = dest;
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      req.arp_ha.sa_family = AF_UNSPEC;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      req.arp_flags = ATF_COM;
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      ioctl(daemon->dhcpfd, SIOCSARP, &req);
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(HAVE_BSD_NETWORK)
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  else
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return;
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HAVE_SOLARIS_NETWORK
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send());
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   of each interface (and any relay address) and does the  following things:
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   3) Fills in local (this host) and router (this host or relay) addresses.
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int complete_context(struct in_addr local, int if_index,
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct in_addr netmask, struct in_addr broadcast, void *vparam)
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct dhcp_context *context;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct iface_param *param = vparam;
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (context = daemon->dhcp; context; context = context->next)
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (!(context->flags & CONTEXT_NETMASK) &&
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  (is_same_net(local, context->start, netmask) ||
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	   is_same_net(local, context->end, netmask)))
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      {
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (context->netmask.s_addr != netmask.s_addr &&
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !(is_same_net(local, context->start, netmask) &&
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	      is_same_net(local, context->end, netmask)))
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  {
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  }
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 	context->netmask = netmask;
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (context->netmask.s_addr)
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  if (is_same_net(local, context->start, context->netmask) &&
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	      is_same_net(local, context->end, context->netmask))
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    {
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	      /* link it onto the current chain if we've not seen it before */
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	      if (if_index == param->ind && context->current == context)
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		{
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  context->router = local;
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  context->local = local;
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  context->current = param->current;
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  param->current = context;
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	      if (!(context->flags & CONTEXT_BRDCAST))
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		{
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  if (is_same_net(broadcast, context->start, context->netmask))
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    context->broadcast = broadcast;
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  else
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    context->broadcast.s_addr  = context->start.s_addr | ~context->netmask.s_addr;
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    }
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  else if (param->relay.s_addr && is_same_net(param->relay, context->start, context->netmask))
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    {
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	      context->router = param->relay;
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	      context->local = param->primary;
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	      /* fill in missing broadcast addresses for relayed ranges */
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	      if (!(context->flags & CONTEXT_BRDCAST))
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		context->broadcast.s_addr  = context->start.s_addr | ~context->netmask.s_addr;
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    }
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return 1;
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct dhcp_context *address_available(struct dhcp_context *context,
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct in_addr taddr,
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct dhcp_netid *netids)
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* Check is an address is OK for this network, check all
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     possible ranges. Make sure that the address isn't in use
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     by the server itself. */
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  unsigned int start, end, addr = ntohl(taddr.s_addr);
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  struct dhcp_context *tmp;
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (tmp = context; tmp; tmp = tmp->current)
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (taddr.s_addr == context->router.s_addr)
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return NULL;
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (tmp = context; tmp; tmp = tmp->current)
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      start = ntohl(tmp->start.s_addr);
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      end = ntohl(tmp->end.s_addr);
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (!(tmp->flags & CONTEXT_STATIC) &&
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  addr >= start &&
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  addr <= end &&
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  match_netid(tmp->filter, netids, 1))
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return tmp;
45361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    }
45461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
45561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt  return NULL;
45661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
45761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
45861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstruct dhcp_context *narrow_context(struct dhcp_context *context,
45961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    struct in_addr taddr,
46061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    struct dhcp_netid *netids)
46161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
46261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt  /* We start of with a set of possible contexts, all on the current physical interface.
46361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt     These are chained on ->current.
464a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt     Here we have an address, and return the actual context correponding to that
465a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt     address. Note that none may fit, if the address came a dhcp-host and is outside
466a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt     any dhcp-range. In that case we return a static range if possible, or failing that,
467a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt     any context on the correct subnet. (If there's more than one, this is a dodgy
468a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt     configuration: maybe there should be a warning.) */
469a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
470a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  struct dhcp_context *tmp;
471a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
472a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  if (!(tmp = address_available(context, taddr, netids)))
473a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    {
474a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      for (tmp = context; tmp; tmp = tmp->current)
475a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (is_same_net(taddr, tmp->start, tmp->netmask) &&
476a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    (tmp->flags & CONTEXT_STATIC))
477a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  break;
478a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
479a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      if (!tmp)
480a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	for (tmp = context; tmp; tmp = tmp->current)
481a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  if (is_same_net(taddr, tmp->start, tmp->netmask))
482a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    break;
483a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
484a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
485a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  /* Only one context allowed now */
486a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  if (tmp)
487a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    tmp->current = NULL;
488a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
489a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  return tmp;
490a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
491a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
492a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstruct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
493a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
494a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  struct dhcp_config *config;
495a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
496a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  for (config = configs; config; config = config->next)
497a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
498a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      return config;
499a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
500a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  return NULL;
501a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
502a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
503a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/* Is every member of check matched by a member of pool?
504a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt   If tagnotneeded, untagged is OK */
505a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
506a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
507a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  struct dhcp_netid *tmp1;
508a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
509a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  if (!check && !tagnotneeded)
510a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    return 0;
511a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
512a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  for (; check; check = check->next)
513a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    {
514a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      if (check->net[0] != '#')
515a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	{
516a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
517a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    if (strcmp(check->net, tmp1->net) == 0)
518a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	      break;
519a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  if (!tmp1)
520a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    return 0;
521a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
522a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      else
523a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
524a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  if (strcmp((check->net)+1, tmp1->net) == 0)
525a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    return 0;
526a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
527a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  return 1;
528a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
529a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
530a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint address_allocate(struct dhcp_context *context,
531a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		     struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
532a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		     struct dhcp_netid *netids, time_t now)
533a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
534a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  /* Find a free address: exclude anything in use and anything allocated to
535a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt     a particular hwaddr/clientid/hostname in our configuration.
536a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt     Try to return from contexts which match netids first. */
537a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
538a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  struct in_addr start, addr;
539a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  struct dhcp_context *c, *d;
540a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  int i, pass;
541a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  unsigned int j;
542a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
543a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  /* hash hwaddr */
544a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  for (j = 0, i = 0; i < hw_len; i++)
545a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
546a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
547a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  for (pass = 0; pass <= 1; pass++)
548a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    for (c = context; c; c = c->current)
549a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      if (c->flags & CONTEXT_STATIC)
550a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	continue;
551a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      else if (!match_netid(c->filter, netids, pass))
552a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	continue;
553a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      else
554a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	{
555a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  /* pick a seed based on hwaddr then iterate until we find a free address. */
556a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  start.s_addr = addr.s_addr =
557a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    htonl(ntohl(c->start.s_addr) +
558a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		  ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
559a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
560a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  do {
561a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    /* eliminate addresses in use by the server. */
562a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    for (d = context; d; d = d->current)
563a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	      if (addr.s_addr == d->router.s_addr)
564a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		break;
565a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
566a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    /* Addresses which end in .255 and .0 are broken in Windows even when using
567a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	       supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
568a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	       then 192.168.0.255 is a valid IP address, but not for Windows as it's
569a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	       in the class C range. See  KB281579. We therefore don't allocate these
570a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	       addresses to avoid hard-to-diagnose problems. Thanks Bill. */
571a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    if (!d &&
572a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		!lease_find_by_addr(addr) &&
573a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		!config_find_by_address(daemon->dhcp_conf, addr) &&
574a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		(!IN_CLASSC(ntohl(addr.s_addr)) ||
575a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		 ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
576a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	      {
577a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		struct ping_result *r, *victim = NULL;
578a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
579a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt					      ((float)PING_WAIT)));
580a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
581a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		*addrp = addr;
582a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
583a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (daemon->options & OPT_NO_PING)
584a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		  return 1;
585a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
586a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		/* check if we failed to ping addr sometime in the last
587a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		   PING_CACHE_TIME seconds. If so, assume the same situation still exists.
588a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		   This avoids problems when a stupid client bangs
589a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		   on us repeatedly. As a final check, if we did more
590a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		   than 60% of the possible ping checks in the last
591a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		   PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
592a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		for (count = 0, r = daemon->ping_results; r; r = r->next)
593a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		  if (difftime(now, r->time) >  (float)PING_CACHE_TIME)
594a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    victim = r; /* old record */
595a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		  else if (++count == max || r->addr.s_addr == addr.s_addr)
596a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    return 1;
597a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
598a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (icmp_ping(addr))
599a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		  /* address in use: perturb address selection so that we are
600a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		     less likely to try this address again. */
601a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		  c->addr_epoch++;
602a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else
603a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		  {
604a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    /* at this point victim may hold an expired record */
605a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    if (!victim)
606a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		      {
607a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			if ((victim = whine_malloc(sizeof(struct ping_result))))
608a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			  {
609a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			    victim->next = daemon->ping_results;
610a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			    daemon->ping_results = victim;
611a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			  }
612a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		      }
613a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
614a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    /* record that this address is OK for 30s
615a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		       without more ping checks */
616a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    if (victim)
617a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		      {
618a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			victim->addr = addr;
619a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			victim->time = now;
620a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		      }
621a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    return 1;
622a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		  }
623a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	      }
624a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
625a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
626a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
627a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
628a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	      addr = c->start;
629a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
630a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  } while (addr.s_addr != start.s_addr);
631a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
632a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  return 0;
633a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
634a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
635a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config)
636a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
637a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  if (!context) /* called via find_config() from lease_update_from_configs() */
638a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    return 1;
639a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  if (!(config->flags & CONFIG_ADDR))
640a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    return 1;
641a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  for (; context; context = context->current)
642a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    if (is_same_net(config->addr, context->start, context->netmask))
643a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      return 1;
644a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
645a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  return 0;
646a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
647a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
648a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
649a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
650a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  struct hwaddr_config *conf_addr;
651a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
652a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
653a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    if (conf_addr->wildcard_mask == 0 &&
654a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	conf_addr->hwaddr_len == len &&
655a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
656a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
657a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      return 1;
658a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
659a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  return 0;
660a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
661a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
662a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstruct dhcp_config *find_config(struct dhcp_config *configs,
663a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				struct dhcp_context *context,
664a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				unsigned char *clid, int clid_len,
665a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				unsigned char *hwaddr, int hw_len,
666a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				int hw_type, char *hostname)
667a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
668a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  int count, new;
669a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  struct dhcp_config *config, *candidate;
670a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  struct hwaddr_config *conf_addr;
671a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
672a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  if (clid)
673a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    for (config = configs; config; config = config->next)
674a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      if (config->flags & CONFIG_CLID)
675a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	{
676a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  if (config->clid_len == clid_len &&
677a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	      memcmp(config->clid, clid, clid_len) == 0 &&
678a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	      is_addr_in_context(context, config))
679a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    return config;
680a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
681a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
682a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	     cope with that here */
683a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  if (*clid == 0 && config->clid_len == clid_len-1  &&
684a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	      memcmp(config->clid, clid+1, clid_len-1) == 0 &&
685a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	      is_addr_in_context(context, config))
686a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    return config;
687a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
688a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
689a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
690a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  for (config = configs; config; config = config->next)
691a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
692a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	is_addr_in_context(context, config))
693a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      return config;
694a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
695a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  if (hostname && context)
696a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    for (config = configs; config; config = config->next)
697a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      if ((config->flags & CONFIG_NAME) &&
698a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  hostname_isequal(config->hostname, hostname) &&
699a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  is_addr_in_context(context, config))
700a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return config;
701a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
702a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  /* use match with fewest wildcast octets */
703a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  for (candidate = NULL, count = 0, config = configs; config; config = config->next)
704a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    if (is_addr_in_context(context, config))
705a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
706a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (conf_addr->wildcard_mask != 0 &&
707a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    conf_addr->hwaddr_len == hw_len &&
708a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
709a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
710a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  {
711a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    count = new;
712a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    candidate = config;
713a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  }
714a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
715a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  return candidate;
716a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
717a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
718a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtvoid dhcp_read_ethers(void)
719a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
720a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  FILE *f = fopen(ETHERSFILE, "r");
721a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  unsigned int flags;
722a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  char *buff = daemon->namebuff;
723a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  char *ip, *cp;
724a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  struct in_addr addr;
725a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  unsigned char hwaddr[ETHER_ADDR_LEN];
726a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  struct dhcp_config **up, *tmp;
727a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  struct dhcp_config *config;
728a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  int count = 0, lineno = 0;
729a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
730a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  addr.s_addr = 0; /* eliminate warning */
731a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
732a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  if (!f)
733a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    {
734a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
735a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      return;
736a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
737a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
738a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  /* This can be called again on SIGHUP, so remove entries created last time round. */
739a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  for (up = &daemon->dhcp_conf, config = daemon->dhcp_conf; config; config = tmp)
740a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    {
741a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      tmp = config->next;
742a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      if (config->flags & CONFIG_FROM_ETHERS)
743a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	{
744a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  *up = tmp;
745a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  /* cannot have a clid */
746a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  if (config->flags & CONFIG_NAME)
747a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    free(config->hostname);
748a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  free(config->hwaddr);
749a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  free(config);
750a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
751a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      else
752a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	up = &config->next;
753a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
754a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
755a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt  while (fgets(buff, MAXDNAME, f))
756a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    {
757a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      char *host = NULL;
758a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
759a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      lineno++;
760a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
761a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
762a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	buff[strlen(buff)-1] = 0;
763a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
764a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      if ((*buff == '#') || (*buff == '+') || (*buff == 0))
765a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	continue;
766a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
767a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      for (ip = buff; *ip && !isspace((int)*ip); ip++);
768a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      for(; *ip && isspace((int)*ip); ip++)
769a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	*ip = 0;
770a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
771a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	{
772a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
773a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	  continue;
774a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
775a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
776a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      /* check for name or dotted-quad */
777a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt      for (cp = ip; *cp; cp++)
778a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	  break;
780
781      if (!*cp)
782	{
783	  if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
784	    {
785	      my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
786	      continue;
787	    }
788
789	  flags = CONFIG_ADDR;
790
791	  for (config = daemon->dhcp_conf; config; config = config->next)
792	    if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
793	      break;
794	}
795      else
796	{
797	  int nomem;
798	  if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host))
799	    {
800	      if (!nomem)
801		my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
802	      free(host);
803	      continue;
804	    }
805
806	  flags = CONFIG_NAME;
807
808	  for (config = daemon->dhcp_conf; config; config = config->next)
809	    if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host))
810	      break;
811	}
812
813      if (config && (config->flags & CONFIG_FROM_ETHERS))
814	{
815	  my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno);
816	  continue;
817	}
818
819      if (!config)
820	{
821	  for (config = daemon->dhcp_conf; config; config = config->next)
822	    {
823	      struct hwaddr_config *conf_addr = config->hwaddr;
824	      if (conf_addr &&
825		  conf_addr->next == NULL &&
826		  conf_addr->wildcard_mask == 0 &&
827		  conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
828		  (conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
829		  memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
830		break;
831	    }
832
833	  if (!config)
834	    {
835	      if (!(config = whine_malloc(sizeof(struct dhcp_config))))
836		continue;
837	      config->flags = CONFIG_FROM_ETHERS;
838	      config->hwaddr = NULL;
839	      config->domain = NULL;
840	      config->next = daemon->dhcp_conf;
841	      daemon->dhcp_conf = config;
842	    }
843
844	  config->flags |= flags;
845
846	  if (flags & CONFIG_NAME)
847	    {
848	      config->hostname = host;
849	      host = NULL;
850	    }
851
852	  if (flags & CONFIG_ADDR)
853	    config->addr = addr;
854	}
855
856      config->flags |= CONFIG_NOCLID;
857      if (!config->hwaddr)
858	config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
859      if (config->hwaddr)
860	{
861	  memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
862	  config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
863	  config->hwaddr->hwaddr_type = ARPHRD_ETHER;
864	  config->hwaddr->wildcard_mask = 0;
865	  config->hwaddr->next = NULL;
866	}
867      count++;
868
869      free(host);
870
871    }
872
873  fclose(f);
874
875  my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
876}
877
878void check_dhcp_hosts(int fatal)
879{
880  /* If the same IP appears in more than one host config, then DISCOVER
881     for one of the hosts will get the address, but REQUEST will be NAKed,
882     since the address is reserved by the other one -> protocol loop.
883     Also check that FQDNs match the domain we are using. */
884
885  struct dhcp_config *configs, *cp;
886
887  for (configs = daemon->dhcp_conf; configs; configs = configs->next)
888    {
889      char *domain;
890
891      if ((configs->flags & DHOPT_BANK) || fatal)
892       {
893	 for (cp = configs->next; cp; cp = cp->next)
894	   if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
895	     {
896	       if (fatal)
897		 die(_("duplicate IP address %s in dhcp-config directive."),
898		     inet_ntoa(cp->addr), EC_BADCONF);
899	       else
900		 my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
901			   inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
902	       configs->flags &= ~CONFIG_ADDR;
903	     }
904
905	 /* split off domain part */
906	 if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
907	   configs->domain = domain;
908       }
909    }
910}
911
912void dhcp_update_configs(struct dhcp_config *configs)
913{
914  /* Some people like to keep all static IP addresses in /etc/hosts.
915     This goes through /etc/hosts and sets static addresses for any DHCP config
916     records which don't have an address and whose name matches.
917     We take care to maintain the invariant that any IP address can appear
918     in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
919     restore the status-quo ante first. */
920
921  struct dhcp_config *config;
922  struct crec *crec;
923
924  for (config = configs; config; config = config->next)
925    if (config->flags & CONFIG_ADDR_HOSTS)
926      config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
927
928
929  if (daemon->port != 0)
930    for (config = configs; config; config = config->next)
931      if (!(config->flags & CONFIG_ADDR) &&
932	  (config->flags & CONFIG_NAME) &&
933	  (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
934	  (crec->flags & F_HOSTS))
935	{
936	  if (cache_find_by_name(crec, config->hostname, 0, F_IPV4))
937	    {
938	      /* use primary (first) address */
939	      while (crec && !(crec->flags & F_REVERSE))
940		crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
941	      if (!crec)
942		continue; /* should be never */
943	      my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
944			config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
945	    }
946
947	  if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
948	    my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
949		      inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
950	  else
951	    {
952	      config->addr = crec->addr.addr.addr.addr4;
953	      config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
954	    }
955	}
956}
957
958/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
959   for this address. If it has a domain part, that must match the set domain and
960   it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
961   so check here that the domain name is legal as a hostname. */
962char *host_from_dns(struct in_addr addr)
963{
964  struct crec *lookup;
965  char *hostname = NULL;
966  char *d1, *d2;
967
968  if (daemon->port == 0)
969    return NULL; /* DNS disabled. */
970
971  lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
972  if (lookup && (lookup->flags & F_HOSTS))
973    {
974      hostname = daemon->dhcp_buff;
975      strncpy(hostname, cache_get_name(lookup), 256);
976      hostname[255] = 0;
977      d1 = strip_hostname(hostname);
978      d2 = get_domain(addr);
979      if (!legal_hostname(hostname) || (d1 && (!d2 || !hostname_isequal(d1, d2))))
980	hostname = NULL;
981    }
982
983  return hostname;
984}
985
986/* return domain or NULL if none. */
987char *strip_hostname(char *hostname)
988{
989  char *dot = strchr(hostname, '.');
990
991  if (!dot)
992    return NULL;
993
994  *dot = 0; /* truncate */
995  if (strlen(dot+1) != 0)
996    return dot+1;
997
998  return NULL;
999}
1000
1001#endif
1002
1003