blob: b9aa325ccf225910b6215e5db1bae46e54f8aeb8 [file] [log] [blame]
Simon Kelley28866e92011-02-14 20:19:14 +00001/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelley9e4abcb2004-01-22 19:47:41 +000017#include "dnsmasq.h"
18
Simon Kelley7622fc02009-06-04 20:32:05 +010019#ifdef HAVE_DHCP
20
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010021struct iface_param {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010022 struct dhcp_context *current;
23 int ind;
24};
25
Simon Kelleyc72daea2012-01-05 21:33:27 +000026struct match_param {
27 int ind, matched;
28 struct in_addr netmask, broadcast, addr;
29};
30
Simon Kelley5aabfc72007-08-29 11:24:47 +010031static int complete_context(struct in_addr local, int if_index,
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010032 struct in_addr netmask, struct in_addr broadcast, void *vparam);
Simon Kelleyc72daea2012-01-05 21:33:27 +000033static int check_listen_addrs(struct in_addr local, int if_index,
34 struct in_addr netmask, struct in_addr broadcast, void *vparam);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010035
Simon Kelley316e2732010-01-22 20:16:09 +000036static int make_fd(int port)
Simon Kelley44a2a312004-03-10 20:04:35 +000037{
38 int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
39 struct sockaddr_in saddr;
Simon Kelley7cebd202006-05-06 14:13:33 +010040 int oneopt = 1;
Simon Kelley824af852008-02-12 20:43:05 +000041#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
42 int mtu = IP_PMTUDISC_DONT;
43#endif
Simon Kelleyc72daea2012-01-05 21:33:27 +000044#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
45 int tos = IPTOS_CLASS_CS6;
46#endif
Simon Kelleydfa666f2004-08-02 18:27:27 +010047
Simon Kelley44a2a312004-03-10 20:04:35 +000048 if (fd == -1)
Simon Kelley7622fc02009-06-04 20:32:05 +010049 die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
Simon Kelley44a2a312004-03-10 20:04:35 +000050
Simon Kelley824af852008-02-12 20:43:05 +000051 if (!fix_fd(fd) ||
52#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
Simon Kelleyc72daea2012-01-05 21:33:27 +000053 setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
54#endif
55#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
56 setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1 ||
Simon Kelley824af852008-02-12 20:43:05 +000057#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010058#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc72daea2012-01-05 21:33:27 +000059 setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
Simon Kelley7622fc02009-06-04 20:32:05 +010060#else
Simon Kelley3be34542004-09-11 19:12:13 +010061 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
Simon Kelley44a2a312004-03-10 20:04:35 +000062#endif
Simon Kelley3be34542004-09-11 19:12:13 +010063 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +010064 die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET);
Simon Kelley44a2a312004-03-10 20:04:35 +000065
Simon Kelleyf6b7dc42005-01-23 12:06:08 +000066 /* When bind-interfaces is set, there might be more than one dnmsasq
Simon Kelley4011c4e2006-10-28 16:26:19 +010067 instance binding port 67. That's OK if they serve different networks.
Simon Kelley7622fc02009-06-04 20:32:05 +010068 Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
Simon Kelley28866e92011-02-14 20:19:14 +000069 if (option_bool(OPT_NOWILD))
Simon Kelley4011c4e2006-10-28 16:26:19 +010070 {
71#ifdef SO_REUSEPORT
72 int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
73#else
74 int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
75#endif
76 if (rc == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +010077 die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
Simon Kelley4011c4e2006-10-28 16:26:19 +010078 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +000079
Simon Kelley849a8352006-06-09 21:02:31 +010080 memset(&saddr, 0, sizeof(saddr));
Simon Kelley44a2a312004-03-10 20:04:35 +000081 saddr.sin_family = AF_INET;
Simon Kelley316e2732010-01-22 20:16:09 +000082 saddr.sin_port = htons(port);
Simon Kelley44a2a312004-03-10 20:04:35 +000083 saddr.sin_addr.s_addr = INADDR_ANY;
Simon Kelley3be34542004-09-11 19:12:13 +010084#ifdef HAVE_SOCKADDR_SA_LEN
85 saddr.sin_len = sizeof(struct sockaddr_in);
86#endif
87
Simon Kelley44a2a312004-03-10 20:04:35 +000088 if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
Simon Kelley5aabfc72007-08-29 11:24:47 +010089 die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
Simon Kelley44a2a312004-03-10 20:04:35 +000090
Simon Kelley316e2732010-01-22 20:16:09 +000091 return fd;
92}
93
94void dhcp_init(void)
95{
96#if defined(HAVE_BSD_NETWORK)
97 int oneopt = 1;
98#endif
99
100 daemon->dhcpfd = make_fd(daemon->dhcp_server_port);
101 if (daemon->enable_pxe)
102 daemon->pxefd = make_fd(PXE_PORT);
103 else
104 daemon->pxefd = -1;
Simon Kelley3be34542004-09-11 19:12:13 +0100105
Simon Kelley824af852008-02-12 20:43:05 +0000106#if defined(HAVE_BSD_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100107 /* When we're not using capabilities, we need to do this here before
108 we drop root. Also, set buffer size small, to avoid wasting
109 kernel buffers */
Simon Kelley44a2a312004-03-10 20:04:35 +0000110
Simon Kelley28866e92011-02-14 20:19:14 +0000111 if (option_bool(OPT_NO_PING))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100112 daemon->dhcp_icmp_fd = -1;
113 else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 ||
114 setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 )
Simon Kelley5aabfc72007-08-29 11:24:47 +0100115 die(_("cannot create ICMP raw socket: %s."), NULL, EC_BADNET);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100116
117 /* Make BPF raw send socket */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100118 init_bpf();
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100119#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100120
Simon Kelley824af852008-02-12 20:43:05 +0000121 check_dhcp_hosts(1);
122
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100123 daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
124 daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
Simon Kelley44a2a312004-03-10 20:04:35 +0000125}
Simon Kelleyc72daea2012-01-05 21:33:27 +0000126
127ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
128{
129 ssize_t sz;
130
131 while (1)
132 {
133 msg->msg_flags = 0;
134 while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
135
136 if (sz == -1)
137 return -1;
138
139 if (!(msg->msg_flags & MSG_TRUNC))
140 break;
141
142 /* Very new Linux kernels return the actual size needed,
143 older ones always return truncated size */
144 if ((size_t)sz == daemon->dhcp_packet.iov_len)
145 {
146 if (!expand_buf(&daemon->dhcp_packet, sz + 100))
147 return -1;
148 }
149 else
150 {
151 expand_buf(&daemon->dhcp_packet, sz);
152 break;
153 }
154 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100155
Simon Kelleyc72daea2012-01-05 21:33:27 +0000156 while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
157
158 return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
159}
160
Simon Kelley316e2732010-01-22 20:16:09 +0000161void dhcp_packet(time_t now, int pxe_fd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000162{
Simon Kelley316e2732010-01-22 20:16:09 +0000163 int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100164 struct dhcp_packet *mess;
Simon Kelley44a2a312004-03-10 20:04:35 +0000165 struct dhcp_context *context;
166 struct iname *tmp;
167 struct ifreq ifr;
168 struct msghdr msg;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100169 struct sockaddr_in dest;
Simon Kelley44a2a312004-03-10 20:04:35 +0000170 struct cmsghdr *cmptr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100171 struct iovec iov;
172 ssize_t sz;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100173 int iface_index = 0, unicast_dest = 0, is_inform = 0;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000174 struct in_addr iface_addr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100175 struct iface_param parm;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100176#ifdef HAVE_LINUX_NETWORK
177 struct arpreq arp_req;
178#endif
179
Simon Kelley44a2a312004-03-10 20:04:35 +0000180 union {
181 struct cmsghdr align; /* this ensures alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000182#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +0000183 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +0000184#elif defined(HAVE_SOLARIS_NETWORK)
185 char control[CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley7622fc02009-06-04 20:32:05 +0100186#elif defined(HAVE_BSD_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +0000187 char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
188#endif
189 } control_u;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000190 struct dhcp_bridge *bridge, *alias;
191
192 msg.msg_controllen = sizeof(control_u);
193 msg.msg_control = control_u.control;
194 msg.msg_name = &dest;
195 msg.msg_namelen = sizeof(dest);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100196 msg.msg_iov = &daemon->dhcp_packet;
Simon Kelley44a2a312004-03-10 20:04:35 +0000197 msg.msg_iovlen = 1;
198
Simon Kelleyc72daea2012-01-05 21:33:27 +0000199 if ((sz = recv_dhcp_packet(fd, &msg)) == -1 ||
200 (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
Simon Kelley44a2a312004-03-10 20:04:35 +0000201 return;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000202
203 #if defined (HAVE_LINUX_NETWORK)
Simon Kelley4011c4e2006-10-28 16:26:19 +0100204 if (msg.msg_controllen >= sizeof(struct cmsghdr))
205 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000206 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley4011c4e2006-10-28 16:26:19 +0100207 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100208 union {
209 unsigned char *c;
210 struct in_pktinfo *p;
211 } p;
212 p.c = CMSG_DATA(cmptr);
213 iface_index = p.p->ipi_ifindex;
214 if (p.p->ipi_addr.s_addr != INADDR_BROADCAST)
Simon Kelley4011c4e2006-10-28 16:26:19 +0100215 unicast_dest = 1;
216 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100217
218#elif defined(HAVE_BSD_NETWORK)
Simon Kelley4011c4e2006-10-28 16:26:19 +0100219 if (msg.msg_controllen >= sizeof(struct cmsghdr))
220 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
221 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100222 {
223 union {
224 unsigned char *c;
225 struct sockaddr_dl *s;
226 } p;
227 p.c = CMSG_DATA(cmptr);
228 iface_index = p.s->sdl_index;
229 }
Simon Kelley4011c4e2006-10-28 16:26:19 +0100230
Simon Kelley7622fc02009-06-04 20:32:05 +0100231#elif defined(HAVE_SOLARIS_NETWORK)
232 if (msg.msg_controllen >= sizeof(struct cmsghdr))
233 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
234 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100235 {
236 union {
237 unsigned char *c;
238 unsigned int *i;
239 } p;
240 p.c = CMSG_DATA(cmptr);
241 iface_index = *(p.i);
242 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100243#endif
244
245 if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
246 return;
247
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100248#ifdef HAVE_LINUX_NETWORK
249 /* ARP fiddling uses original interface even if we pretend to use a different one. */
250 strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
251#endif
252
Simon Kelleyc72daea2012-01-05 21:33:27 +0000253 /* One form of bridging on BSD has the property that packets
254 can be recieved on bridge interfaces which do not have an IP address.
255 We allow these to be treated as aliases of another interface which does have
256 an IP address with --dhcp-bridge=interface,alias,alias */
257 for (bridge = daemon->bridges; bridge; bridge = bridge->next)
258 {
259 for (alias = bridge->alias; alias; alias = alias->next)
260 if (strncmp(ifr.ifr_name, alias->iface, IF_NAMESIZE) == 0)
261 {
262 if (!(iface_index = if_nametoindex(bridge->iface)))
263 {
264 my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr.ifr_name);
265 return;
266 }
267 else
268 {
269 strncpy(ifr.ifr_name, bridge->iface, IF_NAMESIZE);
270 break;
271 }
272 }
273
274 if (alias)
275 break;
276 }
277
Simon Kelley4011c4e2006-10-28 16:26:19 +0100278#ifdef MSG_BCAST
279 /* OpenBSD tells us when a packet was broadcast */
280 if (!(msg.msg_flags & MSG_BCAST))
281 unicast_dest = 1;
282#endif
Simon Kelleyc72daea2012-01-05 21:33:27 +0000283
Simon Kelley44a2a312004-03-10 20:04:35 +0000284 ifr.ifr_addr.sa_family = AF_INET;
Simon Kelley832af0b2007-01-21 20:01:28 +0000285 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
Simon Kelleyc72daea2012-01-05 21:33:27 +0000286 iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
287 else
Simon Kelley832af0b2007-01-21 20:01:28 +0000288 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000289 my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
290 return;
Simon Kelley832af0b2007-01-21 20:01:28 +0000291 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000292
Simon Kelley3d8df262005-08-29 12:19:27 +0100293 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
294 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
295 return;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000296
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100297 /* weird libvirt-inspired access control */
298 for (context = daemon->dhcp; context; context = context->next)
299 if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
300 break;
301
302 if (!context)
303 return;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000304
Simon Kelley91dccd02005-03-31 17:48:32 +0100305 /* unlinked contexts are marked by context->current == context */
Simon Kelley3be34542004-09-11 19:12:13 +0100306 for (context = daemon->dhcp; context; context = context->next)
Simon Kelley91dccd02005-03-31 17:48:32 +0100307 context->current = context;
Simon Kelley44a2a312004-03-10 20:04:35 +0000308
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100309 parm.current = NULL;
310 parm.ind = iface_index;
Simon Kelleye17fb622006-01-14 20:33:46 +0000311
Simon Kelleyc72daea2012-01-05 21:33:27 +0000312 if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100313 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000314 /* If we failed to match the primary address of the interface, see if we've got a --listen-address
315 for a secondary */
316 struct match_param match;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100317
Simon Kelleyc72daea2012-01-05 21:33:27 +0000318 match.matched = 0;
319 match.ind = iface_index;
320
321 if (!daemon->if_addrs ||
322 !iface_enumerate(AF_INET, &match, check_listen_addrs) ||
323 !match.matched)
324 return;
325
326 iface_addr = match.addr;
327 /* make sure secondary address gets priority in case
328 there is more than one address on the interface in the same subnet */
329 complete_context(match.addr, iface_index, match.netmask, match.broadcast, &parm);
330 }
331
Simon Kelley28866e92011-02-14 20:19:14 +0000332 if (!iface_enumerate(AF_INET, &parm, complete_context))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100333 return;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000334
Simon Kelley44a2a312004-03-10 20:04:35 +0000335 lease_prune(NULL, now); /* lose any expired leases */
Simon Kelley824af852008-02-12 20:43:05 +0000336 iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
Simon Kelley7de060b2011-08-26 17:24:52 +0100337 now, unicast_dest, &is_inform, pxe_fd, iface_addr);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100338 lease_update_file(now);
339 lease_update_dns();
Simon Kelley16972692006-10-16 20:04:18 +0100340
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100341 if (iov.iov_len == 0)
Simon Kelley44a2a312004-03-10 20:04:35 +0000342 return;
343
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100344 msg.msg_name = &dest;
345 msg.msg_namelen = sizeof(dest);
346 msg.msg_control = NULL;
347 msg.msg_controllen = 0;
348 msg.msg_iov = &iov;
349 iov.iov_base = daemon->dhcp_packet.iov_base;
350
351 /* packet buffer may have moved */
Simon Kelley824af852008-02-12 20:43:05 +0000352 mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100353
Simon Kelley3be34542004-09-11 19:12:13 +0100354#ifdef HAVE_SOCKADDR_SA_LEN
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100355 dest.sin_len = sizeof(struct sockaddr_in);
Simon Kelley3be34542004-09-11 19:12:13 +0100356#endif
Simon Kelleyc72daea2012-01-05 21:33:27 +0000357
Simon Kelley316e2732010-01-22 20:16:09 +0000358 if (pxe_fd)
359 {
360 if (mess->ciaddr.s_addr != 0)
361 dest.sin_addr = mess->ciaddr;
362 }
363 else if (mess->giaddr.s_addr)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100364 {
365 /* Send to BOOTP relay */
Simon Kelley9e038942008-05-30 20:06:34 +0100366 dest.sin_port = htons(daemon->dhcp_server_port);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100367 dest.sin_addr = mess->giaddr;
368 }
369 else if (mess->ciaddr.s_addr)
370 {
Simon Kelley208b65c2006-08-05 21:41:37 +0100371 /* If the client's idea of its own address tallys with
372 the source address in the request packet, we believe the
Simon Kelley5aabfc72007-08-29 11:24:47 +0100373 source port too, and send back to that. If we're replying
374 to a DHCPINFORM, trust the source address always. */
375 if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
376 dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
Simon Kelley208b65c2006-08-05 21:41:37 +0100377 {
Simon Kelley9e038942008-05-30 20:06:34 +0100378 dest.sin_port = htons(daemon->dhcp_client_port);
Simon Kelley208b65c2006-08-05 21:41:37 +0100379 dest.sin_addr = mess->ciaddr;
380 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100381 }
Simon Kelley824af852008-02-12 20:43:05 +0000382#if defined(HAVE_LINUX_NETWORK)
Simon Kelley849a8352006-06-09 21:02:31 +0100383 else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
384 mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100385 {
Simon Kelley849a8352006-06-09 21:02:31 +0100386 /* broadcast to 255.255.255.255 (or mac address invalid) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100387 struct in_pktinfo *pkt;
Simon Kelley26d0dba2006-04-23 20:00:42 +0100388 msg.msg_control = control_u.control;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100389 msg.msg_controllen = sizeof(control_u);
390 cmptr = CMSG_FIRSTHDR(&msg);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100391 pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
392 pkt->ipi_ifindex = iface_index;
393 pkt->ipi_spec_dst.s_addr = 0;
394 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
Simon Kelleyc72daea2012-01-05 21:33:27 +0000395 cmptr->cmsg_level = IPPROTO_IP;
Simon Kelley824af852008-02-12 20:43:05 +0000396 cmptr->cmsg_type = IP_PKTINFO;
397 dest.sin_addr.s_addr = INADDR_BROADCAST;
Simon Kelley9e038942008-05-30 20:06:34 +0100398 dest.sin_port = htons(daemon->dhcp_client_port);
Simon Kelley44a2a312004-03-10 20:04:35 +0000399 }
400 else
401 {
Simon Kelley849a8352006-06-09 21:02:31 +0100402 /* unicast to unconfigured client. Inject mac address direct into ARP cache.
403 struct sockaddr limits size to 14 bytes. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100404 dest.sin_addr = mess->yiaddr;
Simon Kelley9e038942008-05-30 20:06:34 +0100405 dest.sin_port = htons(daemon->dhcp_client_port);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100406 memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
407 arp_req.arp_ha.sa_family = mess->htype;
408 memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
409 /* interface name already copied in */
410 arp_req.arp_flags = ATF_COM;
411 ioctl(daemon->dhcpfd, SIOCSARP, &arp_req);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000412 }
Simon Kelley824af852008-02-12 20:43:05 +0000413#elif defined(HAVE_SOLARIS_NETWORK)
414 else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
415 {
416 /* broadcast to 255.255.255.255 (or mac address invalid) */
417 dest.sin_addr.s_addr = INADDR_BROADCAST;
Simon Kelley9e038942008-05-30 20:06:34 +0100418 dest.sin_port = htons(daemon->dhcp_client_port);
Simon Kelley824af852008-02-12 20:43:05 +0000419 /* note that we don't specify the interface here: that's done by the
Simon Kelley7622fc02009-06-04 20:32:05 +0100420 IP_BOUND_IF sockopt lower down. */
Simon Kelley824af852008-02-12 20:43:05 +0000421 }
422 else
423 {
424 /* unicast to unconfigured client. Inject mac address direct into ARP cache.
425 Note that this only works for ethernet on solaris, because we use SIOCSARP
426 and not SIOCSXARP, which would be perfect, except that it returns ENXIO
427 mysteriously. Bah. Fall back to broadcast for other net types. */
428 struct arpreq req;
429 dest.sin_addr = mess->yiaddr;
Simon Kelley9e038942008-05-30 20:06:34 +0100430 dest.sin_port = htons(daemon->dhcp_client_port);
Simon Kelley824af852008-02-12 20:43:05 +0000431 *((struct sockaddr_in *)&req.arp_pa) = dest;
432 req.arp_ha.sa_family = AF_UNSPEC;
433 memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
434 req.arp_flags = ATF_COM;
435 ioctl(daemon->dhcpfd, SIOCSARP, &req);
436 }
437#elif defined(HAVE_BSD_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100438 else
439 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100440 send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100441 return;
442 }
443#endif
444
Simon Kelley824af852008-02-12 20:43:05 +0000445#ifdef HAVE_SOLARIS_NETWORK
Simon Kelley316e2732010-01-22 20:16:09 +0000446 setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
Simon Kelley824af852008-02-12 20:43:05 +0000447#endif
448
Simon Kelley316e2732010-01-22 20:16:09 +0000449 while(sendmsg(fd, &msg, 0) == -1 && retry_send());
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000450}
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100451
Simon Kelleyc72daea2012-01-05 21:33:27 +0000452/* check against secondary interface addresses */
453static int check_listen_addrs(struct in_addr local, int if_index,
454 struct in_addr netmask, struct in_addr broadcast, void *vparam)
455{
456 struct match_param *param = vparam;
457 struct iname *tmp;
458
459 if (if_index == param->ind)
460 {
461 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
462 if ( tmp->addr.sa.sa_family == AF_INET &&
463 tmp->addr.in.sin_addr.s_addr == local.s_addr)
464 {
465 param->matched = 1;
466 param->addr = local;
467 param->netmask = netmask;
468 param->broadcast = broadcast;
469 break;
470 }
471 }
472
473 return 1;
474}
475
Simon Kelley0a852542005-03-23 20:28:59 +0000476/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100477 of each interface (and any relay address) and does the following things:
478
479 1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
480 2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
481 3) Fills in local (this host) and router (this host or relay) addresses.
482 4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
483
Simon Kelley0a852542005-03-23 20:28:59 +0000484 Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100485
Simon Kelley5aabfc72007-08-29 11:24:47 +0100486static int complete_context(struct in_addr local, int if_index,
487 struct in_addr netmask, struct in_addr broadcast, void *vparam)
Simon Kelley0a852542005-03-23 20:28:59 +0000488{
489 struct dhcp_context *context;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100490 struct iface_param *param = vparam;
491
Simon Kelley0a852542005-03-23 20:28:59 +0000492 for (context = daemon->dhcp; context; context = context->next)
493 {
494 if (!(context->flags & CONTEXT_NETMASK) &&
495 (is_same_net(local, context->start, netmask) ||
496 is_same_net(local, context->end, netmask)))
497 {
498 if (context->netmask.s_addr != netmask.s_addr &&
499 !(is_same_net(local, context->start, netmask) &&
500 is_same_net(local, context->end, netmask)))
501 {
502 strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
503 strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
Simon Kelley7622fc02009-06-04 20:32:05 +0100504 my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
Simon Kelleyf2621c72007-04-29 19:47:21 +0100505 daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
Simon Kelley0a852542005-03-23 20:28:59 +0000506 }
507 context->netmask = netmask;
508 }
509
Simon Kelley7de060b2011-08-26 17:24:52 +0100510 if (context->netmask.s_addr != 0 &&
511 is_same_net(local, context->start, context->netmask) &&
512 is_same_net(local, context->end, context->netmask))
Simon Kelley0a852542005-03-23 20:28:59 +0000513 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100514 /* link it onto the current chain if we've not seen it before */
515 if (if_index == param->ind && context->current == context)
Simon Kelley0a852542005-03-23 20:28:59 +0000516 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100517 context->router = local;
518 context->local = local;
519 context->current = param->current;
520 param->current = context;
521 }
522
523 if (!(context->flags & CONTEXT_BRDCAST))
Simon Kelley0a852542005-03-23 20:28:59 +0000524 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100525 if (is_same_net(broadcast, context->start, context->netmask))
526 context->broadcast = broadcast;
527 else
Simon Kelley0a852542005-03-23 20:28:59 +0000528 context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
529 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100530 }
Simon Kelley0a852542005-03-23 20:28:59 +0000531 }
532
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100533 return 1;
Simon Kelley0a852542005-03-23 20:28:59 +0000534}
535
Simon Kelley824af852008-02-12 20:43:05 +0000536struct dhcp_context *address_available(struct dhcp_context *context,
537 struct in_addr taddr,
538 struct dhcp_netid *netids)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000539{
Simon Kelley36717ee2004-09-20 19:20:58 +0100540 /* Check is an address is OK for this network, check all
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100541 possible ranges. Make sure that the address isn't in use
542 by the server itself. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000543
Simon Kelley36717ee2004-09-20 19:20:58 +0100544 unsigned int start, end, addr = ntohl(taddr.s_addr);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100545 struct dhcp_context *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +0100546
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100547 for (tmp = context; tmp; tmp = tmp->current)
Simon Kelley849a8352006-06-09 21:02:31 +0100548 if (taddr.s_addr == context->router.s_addr)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100549 return NULL;
550
551 for (tmp = context; tmp; tmp = tmp->current)
552 {
553 start = ntohl(tmp->start.s_addr);
554 end = ntohl(tmp->end.s_addr);
555
Simon Kelley7de060b2011-08-26 17:24:52 +0100556 if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
Simon Kelley36717ee2004-09-20 19:20:58 +0100557 addr >= start &&
Simon Kelley824af852008-02-12 20:43:05 +0000558 addr <= end &&
559 match_netid(tmp->filter, netids, 1))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100560 return tmp;
Simon Kelley36717ee2004-09-20 19:20:58 +0100561 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000562
Simon Kelley59353a62004-11-21 19:34:28 +0000563 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000564}
Simon Kelley59353a62004-11-21 19:34:28 +0000565
Simon Kelley824af852008-02-12 20:43:05 +0000566struct dhcp_context *narrow_context(struct dhcp_context *context,
567 struct in_addr taddr,
568 struct dhcp_netid *netids)
Simon Kelley59353a62004-11-21 19:34:28 +0000569{
Simon Kelleye17fb622006-01-14 20:33:46 +0000570 /* We start of with a set of possible contexts, all on the current physical interface.
Simon Kelley59353a62004-11-21 19:34:28 +0000571 These are chained on ->current.
572 Here we have an address, and return the actual context correponding to that
573 address. Note that none may fit, if the address came a dhcp-host and is outside
Simon Kelleye17fb622006-01-14 20:33:46 +0000574 any dhcp-range. In that case we return a static range if possible, or failing that,
575 any context on the correct subnet. (If there's more than one, this is a dodgy
576 configuration: maybe there should be a warning.) */
Simon Kelley59353a62004-11-21 19:34:28 +0000577
Simon Kelleye17fb622006-01-14 20:33:46 +0000578 struct dhcp_context *tmp;
Simon Kelley59353a62004-11-21 19:34:28 +0000579
Simon Kelley824af852008-02-12 20:43:05 +0000580 if (!(tmp = address_available(context, taddr, netids)))
581 {
582 for (tmp = context; tmp; tmp = tmp->current)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100583 if (match_netid(tmp->filter, netids, 1) &&
584 is_same_net(taddr, tmp->start, tmp->netmask) &&
Simon Kelley7622fc02009-06-04 20:32:05 +0100585 (tmp->flags & CONTEXT_STATIC))
586 break;
Simon Kelley824af852008-02-12 20:43:05 +0000587
588 if (!tmp)
589 for (tmp = context; tmp; tmp = tmp->current)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100590 if (match_netid(tmp->filter, netids, 1) &&
Simon Kelley7de060b2011-08-26 17:24:52 +0100591 is_same_net(taddr, tmp->start, tmp->netmask) &&
592 !(tmp->flags & CONTEXT_PROXY))
Simon Kelley824af852008-02-12 20:43:05 +0000593 break;
594 }
Simon Kelley59353a62004-11-21 19:34:28 +0000595
Simon Kelley824af852008-02-12 20:43:05 +0000596 /* Only one context allowed now */
597 if (tmp)
598 tmp->current = NULL;
599
600 return tmp;
Simon Kelley59353a62004-11-21 19:34:28 +0000601}
602
Simon Kelleydfa666f2004-08-02 18:27:27 +0100603struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
604{
605 struct dhcp_config *config;
606
607 for (config = configs; config; config = config->next)
608 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
609 return config;
610
611 return NULL;
612}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000613
Simon Kelleycdeda282006-03-16 20:16:06 +0000614/* Is every member of check matched by a member of pool?
Simon Kelley824af852008-02-12 20:43:05 +0000615 If tagnotneeded, untagged is OK */
616int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000617{
618 struct dhcp_netid *tmp1;
619
Simon Kelley824af852008-02-12 20:43:05 +0000620 if (!check && !tagnotneeded)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000621 return 0;
622
623 for (; check; check = check->next)
624 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100625 /* '#' for not is for backwards compat. */
626 if (check->net[0] != '!' && check->net[0] != '#')
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000627 {
628 for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
629 if (strcmp(check->net, tmp1->net) == 0)
630 break;
Simon Kelley824af852008-02-12 20:43:05 +0000631 if (!tmp1)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000632 return 0;
633 }
634 else
635 for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
636 if (strcmp((check->net)+1, tmp1->net) == 0)
637 return 0;
638 }
639 return 1;
640}
641
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100642struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
643{
644 struct tag_if *exprs;
645 struct dhcp_netid_list *list;
646
647 for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
648 if (match_netid(exprs->tag, tags, 1))
649 for (list = exprs->set; list; list = list->next)
650 {
651 list->list->next = tags;
652 tags = list->list;
653 }
654
655 return tags;
656}
657
Simon Kelley5aabfc72007-08-29 11:24:47 +0100658int address_allocate(struct dhcp_context *context,
Simon Kelleycdeda282006-03-16 20:16:06 +0000659 struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
Simon Kelley3d8df262005-08-29 12:19:27 +0100660 struct dhcp_netid *netids, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000661{
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100662 /* Find a free address: exclude anything in use and anything allocated to
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000663 a particular hwaddr/clientid/hostname in our configuration.
Simon Kelleycdeda282006-03-16 20:16:06 +0000664 Try to return from contexts which match netids first. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000665
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100666 struct in_addr start, addr;
667 struct dhcp_context *c, *d;
Simon Kelleycdeda282006-03-16 20:16:06 +0000668 int i, pass;
669 unsigned int j;
Simon Kelley3d8df262005-08-29 12:19:27 +0100670
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100671 /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good
672 dispersal even with similarly-valued "strings". */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100673 for (j = 0, i = 0; i < hw_len; i++)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100674 j += hwaddr[i] + (j << 6) + (j << 16) - j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100675
Simon Kelleycdeda282006-03-16 20:16:06 +0000676 for (pass = 0; pass <= 1; pass++)
677 for (c = context; c; c = c->current)
Simon Kelley7de060b2011-08-26 17:24:52 +0100678 if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
Simon Kelleycdeda282006-03-16 20:16:06 +0000679 continue;
680 else if (!match_netid(c->filter, netids, pass))
681 continue;
682 else
683 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100684 if (option_bool(OPT_CONSEC_ADDR))
685 /* seed is largest extant lease addr in this context */
686 start = lease_find_max_addr(c);
687 else
688 /* pick a seed based on hwaddr */
689 start.s_addr = htonl(ntohl(c->start.s_addr) +
690 ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
691
692 /* iterate until we find a free address. */
693 addr = start;
Simon Kelleycdeda282006-03-16 20:16:06 +0000694
695 do {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100696 /* eliminate addresses in use by the server. */
697 for (d = context; d; d = d->current)
Simon Kelley849a8352006-06-09 21:02:31 +0100698 if (addr.s_addr == d->router.s_addr)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100699 break;
700
Simon Kelley73a08a22009-02-05 20:28:08 +0000701 /* Addresses which end in .255 and .0 are broken in Windows even when using
702 supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
703 then 192.168.0.255 is a valid IP address, but not for Windows as it's
704 in the class C range. See KB281579. We therefore don't allocate these
705 addresses to avoid hard-to-diagnose problems. Thanks Bill. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100706 if (!d &&
707 !lease_find_by_addr(addr) &&
Simon Kelley73a08a22009-02-05 20:28:08 +0000708 !config_find_by_address(daemon->dhcp_conf, addr) &&
709 (!IN_CLASSC(ntohl(addr.s_addr)) ||
710 ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
Simon Kelleycdeda282006-03-16 20:16:06 +0000711 {
712 struct ping_result *r, *victim = NULL;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100713 int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
714 ((float)PING_WAIT)));
715
716 *addrp = addr;
717
Simon Kelleycdeda282006-03-16 20:16:06 +0000718 /* check if we failed to ping addr sometime in the last
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100719 PING_CACHE_TIME seconds. If so, assume the same situation still exists.
Simon Kelleycdeda282006-03-16 20:16:06 +0000720 This avoids problems when a stupid client bangs
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100721 on us repeatedly. As a final check, if we did more
722 than 60% of the possible ping checks in the last
723 PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
Simon Kelleycdeda282006-03-16 20:16:06 +0000724 for (count = 0, r = daemon->ping_results; r; r = r->next)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100725 if (difftime(now, r->time) > (float)PING_CACHE_TIME)
Simon Kelleycdeda282006-03-16 20:16:06 +0000726 victim = r; /* old record */
Simon Kelley7de060b2011-08-26 17:24:52 +0100727 else
728 {
729 count++;
730 if (r->addr.s_addr == addr.s_addr)
731 {
732 /* consec-ip mode: we offered this address for another client
733 (different hash) recently, don't offer it to this one. */
734 if (option_bool(OPT_CONSEC_ADDR) && r->hash != j)
735 break;
736
737 return 1;
738 }
739 }
740
741 if (!r)
Simon Kelley3d8df262005-08-29 12:19:27 +0100742 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100743 if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
Simon Kelleycdeda282006-03-16 20:16:06 +0000744 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100745 /* address in use: perturb address selection so that we are
746 less likely to try this address again. */
747 if (!option_bool(OPT_CONSEC_ADDR))
748 c->addr_epoch++;
749 }
750 else
751 {
752 /* at this point victim may hold an expired record */
753 if (!victim)
Simon Kelleycdeda282006-03-16 20:16:06 +0000754 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100755 if ((victim = whine_malloc(sizeof(struct ping_result))))
756 {
757 victim->next = daemon->ping_results;
758 daemon->ping_results = victim;
759 }
Simon Kelleycdeda282006-03-16 20:16:06 +0000760 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100761
762 /* record that this address is OK for 30s
763 without more ping checks */
764 if (victim)
765 {
766 victim->addr = addr;
767 victim->time = now;
768 victim->hash = j;
769 }
770 return 1;
Simon Kelleycdeda282006-03-16 20:16:06 +0000771 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100772 }
Simon Kelleycdeda282006-03-16 20:16:06 +0000773 }
Simon Kelley3be34542004-09-11 19:12:13 +0100774
Simon Kelleycdeda282006-03-16 20:16:06 +0000775 addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
776
777 if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
778 addr = c->start;
779
780 } while (addr.s_addr != start.s_addr);
781 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100782
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000783 return 0;
784}
785
786static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config)
787{
Simon Kelleyb8187c82005-11-26 21:46:27 +0000788 if (!context) /* called via find_config() from lease_update_from_configs() */
Simon Kelley0a852542005-03-23 20:28:59 +0000789 return 1;
Simon Kelley33820b72004-04-03 21:10:00 +0100790 if (!(config->flags & CONFIG_ADDR))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000791 return 1;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000792 for (; context; context = context->current)
793 if (is_same_net(config->addr, context->start, context->netmask))
794 return 1;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000795
796 return 0;
797}
798
Simon Kelley9009d742008-11-14 20:04:27 +0000799int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
800{
801 struct hwaddr_config *conf_addr;
802
803 for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
804 if (conf_addr->wildcard_mask == 0 &&
805 conf_addr->hwaddr_len == len &&
806 (conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
807 memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
808 return 1;
809
810 return 0;
811}
Simon Kelley0a852542005-03-23 20:28:59 +0000812
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000813struct dhcp_config *find_config(struct dhcp_config *configs,
814 struct dhcp_context *context,
815 unsigned char *clid, int clid_len,
Simon Kelleycdeda282006-03-16 20:16:06 +0000816 unsigned char *hwaddr, int hw_len,
817 int hw_type, char *hostname)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000818{
Simon Kelley7622fc02009-06-04 20:32:05 +0100819 int count, new;
820 struct dhcp_config *config, *candidate;
Simon Kelley9009d742008-11-14 20:04:27 +0000821 struct hwaddr_config *conf_addr;
822
Simon Kelley0a852542005-03-23 20:28:59 +0000823 if (clid)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000824 for (config = configs; config; config = config->next)
Simon Kelley33820b72004-04-03 21:10:00 +0100825 if (config->flags & CONFIG_CLID)
826 {
827 if (config->clid_len == clid_len &&
828 memcmp(config->clid, clid, clid_len) == 0 &&
829 is_addr_in_context(context, config))
830 return config;
831
832 /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
833 cope with that here */
834 if (*clid == 0 && config->clid_len == clid_len-1 &&
835 memcmp(config->clid, clid+1, clid_len-1) == 0 &&
836 is_addr_in_context(context, config))
837 return config;
838 }
839
Simon Kelley0a852542005-03-23 20:28:59 +0000840
Simon Kelleycdeda282006-03-16 20:16:06 +0000841 for (config = configs; config; config = config->next)
Simon Kelley9009d742008-11-14 20:04:27 +0000842 if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
Simon Kelleycdeda282006-03-16 20:16:06 +0000843 is_addr_in_context(context, config))
844 return config;
Simon Kelley3d8df262005-08-29 12:19:27 +0100845
Simon Kelley0a852542005-03-23 20:28:59 +0000846 if (hostname && context)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000847 for (config = configs; config; config = config->next)
Simon Kelley33820b72004-04-03 21:10:00 +0100848 if ((config->flags & CONFIG_NAME) &&
849 hostname_isequal(config->hostname, hostname) &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000850 is_addr_in_context(context, config))
851 return config;
Simon Kelley7622fc02009-06-04 20:32:05 +0100852
853 /* use match with fewest wildcast octets */
854 for (candidate = NULL, count = 0, config = configs; config; config = config->next)
855 if (is_addr_in_context(context, config))
856 for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
857 if (conf_addr->wildcard_mask != 0 &&
858 conf_addr->hwaddr_len == hw_len &&
859 (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
860 (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
861 {
862 count = new;
863 candidate = config;
864 }
865
866 return candidate;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000867}
868
Simon Kelley5aabfc72007-08-29 11:24:47 +0100869void dhcp_read_ethers(void)
Simon Kelley1ab84e22004-01-29 16:48:35 +0000870{
Simon Kelley44a2a312004-03-10 20:04:35 +0000871 FILE *f = fopen(ETHERSFILE, "r");
Simon Kelley0a852542005-03-23 20:28:59 +0000872 unsigned int flags;
Simon Kelley3be34542004-09-11 19:12:13 +0100873 char *buff = daemon->namebuff;
Simon Kelley33820b72004-04-03 21:10:00 +0100874 char *ip, *cp;
Simon Kelley44a2a312004-03-10 20:04:35 +0000875 struct in_addr addr;
Simon Kelley33820b72004-04-03 21:10:00 +0100876 unsigned char hwaddr[ETHER_ADDR_LEN];
Simon Kelley849a8352006-06-09 21:02:31 +0100877 struct dhcp_config **up, *tmp;
Simon Kelley16972692006-10-16 20:04:18 +0100878 struct dhcp_config *config;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000879 int count = 0, lineno = 0;
Simon Kelley3d8df262005-08-29 12:19:27 +0100880
881 addr.s_addr = 0; /* eliminate warning */
Simon Kelley44a2a312004-03-10 20:04:35 +0000882
883 if (!f)
Simon Kelley33820b72004-04-03 21:10:00 +0100884 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100885 my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
Simon Kelley3be34542004-09-11 19:12:13 +0100886 return;
Simon Kelley33820b72004-04-03 21:10:00 +0100887 }
888
Simon Kelley849a8352006-06-09 21:02:31 +0100889 /* This can be called again on SIGHUP, so remove entries created last time round. */
Simon Kelley16972692006-10-16 20:04:18 +0100890 for (up = &daemon->dhcp_conf, config = daemon->dhcp_conf; config; config = tmp)
Simon Kelley849a8352006-06-09 21:02:31 +0100891 {
892 tmp = config->next;
893 if (config->flags & CONFIG_FROM_ETHERS)
894 {
895 *up = tmp;
896 /* cannot have a clid */
897 if (config->flags & CONFIG_NAME)
898 free(config->hostname);
Simon Kelley9009d742008-11-14 20:04:27 +0000899 free(config->hwaddr);
Simon Kelley849a8352006-06-09 21:02:31 +0100900 free(config);
901 }
902 else
903 up = &config->next;
904 }
905
Simon Kelley44a2a312004-03-10 20:04:35 +0000906 while (fgets(buff, MAXDNAME, f))
907 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100908 char *host = NULL;
909
Simon Kelleyb8187c82005-11-26 21:46:27 +0000910 lineno++;
911
Simon Kelley824af852008-02-12 20:43:05 +0000912 while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
Simon Kelley44a2a312004-03-10 20:04:35 +0000913 buff[strlen(buff)-1] = 0;
914
Simon Kelley73a08a22009-02-05 20:28:08 +0000915 if ((*buff == '#') || (*buff == '+') || (*buff == 0))
Simon Kelley44a2a312004-03-10 20:04:35 +0000916 continue;
917
Simon Kelley824af852008-02-12 20:43:05 +0000918 for (ip = buff; *ip && !isspace((int)*ip); ip++);
919 for(; *ip && isspace((int)*ip); ip++)
Simon Kelley44a2a312004-03-10 20:04:35 +0000920 *ip = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +0000921 if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000922 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100923 my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000924 continue;
925 }
Simon Kelley44a2a312004-03-10 20:04:35 +0000926
927 /* check for name or dotted-quad */
928 for (cp = ip; *cp; cp++)
929 if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
930 break;
931
932 if (!*cp)
933 {
Simon Kelley44a2a312004-03-10 20:04:35 +0000934 if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000935 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100936 my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000937 continue;
938 }
939
Simon Kelley33820b72004-04-03 21:10:00 +0100940 flags = CONFIG_ADDR;
Simon Kelley1cff1662004-03-12 08:12:58 +0000941
Simon Kelley16972692006-10-16 20:04:18 +0100942 for (config = daemon->dhcp_conf; config; config = config->next)
Simon Kelley33820b72004-04-03 21:10:00 +0100943 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
Simon Kelley1cff1662004-03-12 08:12:58 +0000944 break;
Simon Kelley44a2a312004-03-10 20:04:35 +0000945 }
946 else
947 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100948 int nomem;
949 if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host))
Simon Kelleyb8187c82005-11-26 21:46:27 +0000950 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100951 if (!nomem)
952 my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
953 free(host);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000954 continue;
955 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100956
Simon Kelley33820b72004-04-03 21:10:00 +0100957 flags = CONFIG_NAME;
Simon Kelley1cff1662004-03-12 08:12:58 +0000958
Simon Kelley16972692006-10-16 20:04:18 +0100959 for (config = daemon->dhcp_conf; config; config = config->next)
Simon Kelley1f15b812009-10-13 17:49:32 +0100960 if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host))
Simon Kelley1cff1662004-03-12 08:12:58 +0000961 break;
Simon Kelley44a2a312004-03-10 20:04:35 +0000962 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100963
964 if (config && (config->flags & CONFIG_FROM_ETHERS))
965 {
966 my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno);
967 continue;
968 }
969
Simon Kelley1cff1662004-03-12 08:12:58 +0000970 if (!config)
971 {
Simon Kelley16972692006-10-16 20:04:18 +0100972 for (config = daemon->dhcp_conf; config; config = config->next)
Simon Kelley9009d742008-11-14 20:04:27 +0000973 {
974 struct hwaddr_config *conf_addr = config->hwaddr;
975 if (conf_addr &&
976 conf_addr->next == NULL &&
977 conf_addr->wildcard_mask == 0 &&
978 conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
979 (conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
980 memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
981 break;
982 }
Simon Kelley33820b72004-04-03 21:10:00 +0100983
984 if (!config)
985 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100986 if (!(config = whine_malloc(sizeof(struct dhcp_config))))
Simon Kelley33820b72004-04-03 21:10:00 +0100987 continue;
Simon Kelley849a8352006-06-09 21:02:31 +0100988 config->flags = CONFIG_FROM_ETHERS;
Simon Kelley9009d742008-11-14 20:04:27 +0000989 config->hwaddr = NULL;
990 config->domain = NULL;
Simon Kelleyc52e1892010-06-07 22:01:39 +0100991 config->netid = NULL;
Simon Kelley16972692006-10-16 20:04:18 +0100992 config->next = daemon->dhcp_conf;
993 daemon->dhcp_conf = config;
Simon Kelley33820b72004-04-03 21:10:00 +0100994 }
995
996 config->flags |= flags;
997
998 if (flags & CONFIG_NAME)
999 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001000 config->hostname = host;
1001 host = NULL;
Simon Kelley33820b72004-04-03 21:10:00 +01001002 }
1003
1004 if (flags & CONFIG_ADDR)
1005 config->addr = addr;
Simon Kelley1cff1662004-03-12 08:12:58 +00001006 }
Simon Kelley33820b72004-04-03 21:10:00 +01001007
Simon Kelley9009d742008-11-14 20:04:27 +00001008 config->flags |= CONFIG_NOCLID;
1009 if (!config->hwaddr)
1010 config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
1011 if (config->hwaddr)
1012 {
1013 memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
1014 config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
1015 config->hwaddr->hwaddr_type = ARPHRD_ETHER;
1016 config->hwaddr->wildcard_mask = 0;
1017 config->hwaddr->next = NULL;
1018 }
Simon Kelley33820b72004-04-03 21:10:00 +01001019 count++;
Simon Kelley1f15b812009-10-13 17:49:32 +01001020
1021 free(host);
1022
Simon Kelley44a2a312004-03-10 20:04:35 +00001023 }
1024
1025 fclose(f);
Simon Kelley33820b72004-04-03 21:10:00 +01001026
Simon Kelley7622fc02009-06-04 20:32:05 +01001027 my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
Simon Kelley44a2a312004-03-10 20:04:35 +00001028}
1029
Simon Kelley824af852008-02-12 20:43:05 +00001030void check_dhcp_hosts(int fatal)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001031{
Simon Kelley824af852008-02-12 20:43:05 +00001032 /* If the same IP appears in more than one host config, then DISCOVER
1033 for one of the hosts will get the address, but REQUEST will be NAKed,
1034 since the address is reserved by the other one -> protocol loop.
1035 Also check that FQDNs match the domain we are using. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001036
Simon Kelley824af852008-02-12 20:43:05 +00001037 struct dhcp_config *configs, *cp;
1038
1039 for (configs = daemon->dhcp_conf; configs; configs = configs->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001040 {
Simon Kelley824af852008-02-12 20:43:05 +00001041 char *domain;
1042
1043 if ((configs->flags & DHOPT_BANK) || fatal)
1044 {
1045 for (cp = configs->next; cp; cp = cp->next)
1046 if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
1047 {
1048 if (fatal)
1049 die(_("duplicate IP address %s in dhcp-config directive."),
1050 inet_ntoa(cp->addr), EC_BADCONF);
1051 else
Simon Kelley7622fc02009-06-04 20:32:05 +01001052 my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
Simon Kelley824af852008-02-12 20:43:05 +00001053 inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
1054 configs->flags &= ~CONFIG_ADDR;
1055 }
1056
Simon Kelley9009d742008-11-14 20:04:27 +00001057 /* split off domain part */
Simon Kelley824af852008-02-12 20:43:05 +00001058 if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
Simon Kelley9009d742008-11-14 20:04:27 +00001059 configs->domain = domain;
Simon Kelley824af852008-02-12 20:43:05 +00001060 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001061 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001062}
1063
Simon Kelley44a2a312004-03-10 20:04:35 +00001064void dhcp_update_configs(struct dhcp_config *configs)
1065{
1066 /* Some people like to keep all static IP addresses in /etc/hosts.
1067 This goes through /etc/hosts and sets static addresses for any DHCP config
Simon Kelley3d8df262005-08-29 12:19:27 +01001068 records which don't have an address and whose name matches.
1069 We take care to maintain the invariant that any IP address can appear
Simon Kelley849a8352006-06-09 21:02:31 +01001070 in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
1071 restore the status-quo ante first. */
Simon Kelley44a2a312004-03-10 20:04:35 +00001072
Simon Kelley1ab84e22004-01-29 16:48:35 +00001073 struct dhcp_config *config;
1074 struct crec *crec;
Simon Kelley849a8352006-06-09 21:02:31 +01001075
1076 for (config = configs; config; config = config->next)
1077 if (config->flags & CONFIG_ADDR_HOSTS)
1078 config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
Simon Kelley44a2a312004-03-10 20:04:35 +00001079
Simon Kelley824af852008-02-12 20:43:05 +00001080
1081 if (daemon->port != 0)
1082 for (config = configs; config; config = config->next)
1083 if (!(config->flags & CONFIG_ADDR) &&
1084 (config->flags & CONFIG_NAME) &&
1085 (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
1086 (crec->flags & F_HOSTS))
1087 {
1088 if (cache_find_by_name(crec, config->hostname, 0, F_IPV4))
1089 {
1090 /* use primary (first) address */
1091 while (crec && !(crec->flags & F_REVERSE))
1092 crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
1093 if (!crec)
1094 continue; /* should be never */
Simon Kelley7622fc02009-06-04 20:32:05 +01001095 my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
Simon Kelley824af852008-02-12 20:43:05 +00001096 config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
1097 }
1098
1099 if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
Simon Kelley7622fc02009-06-04 20:32:05 +01001100 my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
Simon Kelley824af852008-02-12 20:43:05 +00001101 inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
1102 else
1103 {
1104 config->addr = crec->addr.addr.addr.addr4;
1105 config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
1106 }
1107 }
Simon Kelley1ab84e22004-01-29 16:48:35 +00001108}
Simon Kelley44a2a312004-03-10 20:04:35 +00001109
Simon Kelleybb01cb92004-12-13 20:56:23 +00001110/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
1111 for this address. If it has a domain part, that must match the set domain and
Simon Kelley1f15b812009-10-13 17:49:32 +01001112 it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001113 so check here that the domain name is legal as a hostname.
1114 NOTE: we're only allowed to overwrite daemon->dhcp_buff if we succeed. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001115char *host_from_dns(struct in_addr addr)
Simon Kelleybb01cb92004-12-13 20:56:23 +00001116{
Simon Kelley824af852008-02-12 20:43:05 +00001117 struct crec *lookup;
Simon Kelley824af852008-02-12 20:43:05 +00001118
1119 if (daemon->port == 0)
1120 return NULL; /* DNS disabled. */
Simon Kelleybb01cb92004-12-13 20:56:23 +00001121
Simon Kelley824af852008-02-12 20:43:05 +00001122 lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001123
Simon Kelleybb01cb92004-12-13 20:56:23 +00001124 if (lookup && (lookup->flags & F_HOSTS))
1125 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001126 char *dot, *hostname = cache_get_name(lookup);
1127 dot = strchr(hostname, '.');
1128
1129 if (dot && strlen(dot+1) != 0)
1130 {
1131 char *d2 = get_domain(addr);
1132 if (!d2 || !hostname_isequal(dot+1, d2))
1133 return NULL; /* wrong domain */
1134 }
1135
1136 if (!legal_hostname(hostname))
1137 return NULL;
1138
1139 strncpy(daemon->dhcp_buff, hostname, 256);
1140 daemon->dhcp_buff[255] = 0;
1141 strip_hostname(daemon->dhcp_buff);
1142
1143 return daemon->dhcp_buff;
Simon Kelleybb01cb92004-12-13 20:56:23 +00001144 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001145
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001146 return NULL;
Simon Kelleybb01cb92004-12-13 20:56:23 +00001147}
1148
Simon Kelley9009d742008-11-14 20:04:27 +00001149/* return domain or NULL if none. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001150char *strip_hostname(char *hostname)
Simon Kelleybb01cb92004-12-13 20:56:23 +00001151{
1152 char *dot = strchr(hostname, '.');
Simon Kelley5aabfc72007-08-29 11:24:47 +01001153
1154 if (!dot)
1155 return NULL;
1156
1157 *dot = 0; /* truncate */
Simon Kelley9009d742008-11-14 20:04:27 +00001158 if (strlen(dot+1) != 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001159 return dot+1;
1160
1161 return NULL;
Simon Kelleybb01cb92004-12-13 20:56:23 +00001162}
Simon Kelley9009d742008-11-14 20:04:27 +00001163
Simon Kelley7622fc02009-06-04 20:32:05 +01001164#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001165