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