1*8415e52bSreyk /* $OpenBSD: dhcp.c,v 1.57 2017/07/11 10:28:24 reyk Exp $ */
2e853bc5dShenning
3e853bc5dShenning /*
4e853bc5dShenning * Copyright (c) 1995, 1996, 1997, 1998, 1999
5e853bc5dShenning * The Internet Software Consortium. All rights reserved.
6e853bc5dShenning *
7e853bc5dShenning * Redistribution and use in source and binary forms, with or without
8e853bc5dShenning * modification, are permitted provided that the following conditions
9e853bc5dShenning * are met:
10e853bc5dShenning *
11e853bc5dShenning * 1. Redistributions of source code must retain the above copyright
12e853bc5dShenning * notice, this list of conditions and the following disclaimer.
13e853bc5dShenning * 2. Redistributions in binary form must reproduce the above copyright
14e853bc5dShenning * notice, this list of conditions and the following disclaimer in the
15e853bc5dShenning * documentation and/or other materials provided with the distribution.
16e853bc5dShenning * 3. Neither the name of The Internet Software Consortium nor the names
17e853bc5dShenning * of its contributors may be used to endorse or promote products derived
18e853bc5dShenning * from this software without specific prior written permission.
19e853bc5dShenning *
20e853bc5dShenning * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
21e853bc5dShenning * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22e853bc5dShenning * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23e853bc5dShenning * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24e853bc5dShenning * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
25e853bc5dShenning * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26e853bc5dShenning * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27e853bc5dShenning * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28e853bc5dShenning * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29e853bc5dShenning * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30e853bc5dShenning * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31e853bc5dShenning * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32e853bc5dShenning * SUCH DAMAGE.
33e853bc5dShenning *
34e853bc5dShenning * This software has been written for the Internet Software Consortium
35e853bc5dShenning * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
36e853bc5dShenning * Enterprises. To learn more about the Internet Software Consortium,
37e853bc5dShenning * see ``http://www.vix.com/isc''. To learn more about Vixie
38e853bc5dShenning * Enterprises, see ``http://www.vix.com''.
39e853bc5dShenning */
40e853bc5dShenning
41837cddffSkrw #include <sys/types.h>
42837cddffSkrw #include <sys/socket.h>
43837cddffSkrw
44837cddffSkrw #include <arpa/inet.h>
45837cddffSkrw
46837cddffSkrw #include <net/if.h>
47837cddffSkrw
48837cddffSkrw #include <netinet/in.h>
49837cddffSkrw
50837cddffSkrw #include <errno.h>
51837cddffSkrw #include <stdio.h>
52837cddffSkrw #include <stdlib.h>
53837cddffSkrw #include <string.h>
54837cddffSkrw
55837cddffSkrw #include "dhcp.h"
56837cddffSkrw #include "tree.h"
57e853bc5dShenning #include "dhcpd.h"
58c525a185Skrw #include "log.h"
595f515bebSbeck #include "sync.h"
60e853bc5dShenning
61e853bc5dShenning int outstanding_pings;
62e853bc5dShenning
63e853bc5dShenning static char dhcp_message[256];
64e853bc5dShenning
65ea507cabSderaadt void
dhcp(struct packet * packet,int is_udpsock)6694bf53e6Skrw dhcp(struct packet *packet, int is_udpsock)
67e853bc5dShenning {
68e853bc5dShenning if (!locate_network(packet) && packet->packet_type != DHCPREQUEST)
69e853bc5dShenning return;
70e853bc5dShenning
7194bf53e6Skrw if (is_udpsock && packet->packet_type != DHCPINFORM) {
72c525a185Skrw log_info("Unable to handle a DHCP message type=%d on UDP "
7394bf53e6Skrw "socket", packet->packet_type);
7494bf53e6Skrw return;
7594bf53e6Skrw }
7694bf53e6Skrw
77e853bc5dShenning switch (packet->packet_type) {
78e853bc5dShenning case DHCPDISCOVER:
79e853bc5dShenning dhcpdiscover(packet);
80e853bc5dShenning break;
81e853bc5dShenning
82e853bc5dShenning case DHCPREQUEST:
83e853bc5dShenning dhcprequest(packet);
84e853bc5dShenning break;
85e853bc5dShenning
86e853bc5dShenning case DHCPRELEASE:
87e853bc5dShenning dhcprelease(packet);
88e853bc5dShenning break;
89e853bc5dShenning
90e853bc5dShenning case DHCPDECLINE:
91e853bc5dShenning dhcpdecline(packet);
92e853bc5dShenning break;
93e853bc5dShenning
94e853bc5dShenning case DHCPINFORM:
95e853bc5dShenning dhcpinform(packet);
96e853bc5dShenning break;
97e853bc5dShenning
98e853bc5dShenning default:
99e853bc5dShenning break;
100e853bc5dShenning }
101e853bc5dShenning }
102e853bc5dShenning
1038e1c2028Sderaadt void
dhcpdiscover(struct packet * packet)1048e1c2028Sderaadt dhcpdiscover(struct packet *packet)
105e853bc5dShenning {
106e853bc5dShenning struct lease *lease = find_lease(packet, packet->shared_network, 0);
107e853bc5dShenning struct host_decl *hp;
108e853bc5dShenning
109c525a185Skrw log_info("DHCPDISCOVER from %s via %s",
1108e1c2028Sderaadt print_hw_addr(packet->raw->htype, packet->raw->hlen,
111e853bc5dShenning packet->raw->chaddr),
1128e1c2028Sderaadt packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) :
1138e1c2028Sderaadt packet->interface->name);
114e853bc5dShenning
115e853bc5dShenning /* Sourceless packets don't make sense here. */
116e853bc5dShenning if (!packet->shared_network) {
117c525a185Skrw log_info("Packet from unknown subnet: %s",
118e853bc5dShenning inet_ntoa(packet->raw->giaddr));
119e853bc5dShenning return;
120e853bc5dShenning }
121e853bc5dShenning
122e853bc5dShenning /* If we didn't find a lease, try to allocate one... */
123e853bc5dShenning if (!lease) {
124e853bc5dShenning lease = packet->shared_network->last_lease;
125e853bc5dShenning
1268e1c2028Sderaadt /*
1278e1c2028Sderaadt * If there are no leases in that subnet that have
1288e1c2028Sderaadt * expired, we have nothing to offer this client.
1298e1c2028Sderaadt */
130e853bc5dShenning if (!lease || lease->ends > cur_time) {
131c525a185Skrw log_info("no free leases on subnet %s",
132e853bc5dShenning packet->shared_network->name);
133e853bc5dShenning return;
134e853bc5dShenning }
135e853bc5dShenning
1368e1c2028Sderaadt /*
1378e1c2028Sderaadt * If we find an abandoned lease, take it, but print a
1388e1c2028Sderaadt * warning message, so that if it continues to lose,
1398e1c2028Sderaadt * the administrator will eventually investigate.
1408e1c2028Sderaadt */
141e853bc5dShenning if ((lease->flags & ABANDONED_LEASE)) {
142e853bc5dShenning struct lease *lp;
143e853bc5dShenning
144e853bc5dShenning /* See if we can find an unabandoned lease first. */
145e853bc5dShenning for (lp = lease; lp; lp = lp->prev) {
146e853bc5dShenning if (lp->ends > cur_time)
147e853bc5dShenning break;
148e853bc5dShenning if (!(lp->flags & ABANDONED_LEASE)) {
149e853bc5dShenning lease = lp;
150e853bc5dShenning break;
151e853bc5dShenning }
152e853bc5dShenning }
153e853bc5dShenning
1548e1c2028Sderaadt /*
1558e1c2028Sderaadt * If we can't find an unabandoned lease,
1568e1c2028Sderaadt * reclaim the abandoned lease.
1578e1c2028Sderaadt */
158e853bc5dShenning if ((lease->flags & ABANDONED_LEASE)) {
159c525a185Skrw log_warnx("Reclaiming abandoned IP address %s.",
160e853bc5dShenning piaddr(lease->ip_addr));
161e853bc5dShenning lease->flags &= ~ABANDONED_LEASE;
1626f4dfa88Sckuethe
163dfafa184Sckuethe pfmsg('L', lease); /* unabandon address */
164e853bc5dShenning }
165e853bc5dShenning }
166e853bc5dShenning
167e853bc5dShenning /* Try to find a host_decl that matches the client
168e853bc5dShenning identifier or hardware address on the packet, and
169e853bc5dShenning has no fixed IP address. If there is one, hang
170e853bc5dShenning it off the lease so that its option definitions
171e853bc5dShenning can be used. */
1728e1c2028Sderaadt if (((packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len != 0) &&
1738e1c2028Sderaadt ((hp = find_hosts_by_uid(
1748e1c2028Sderaadt packet->options[DHO_DHCP_CLIENT_IDENTIFIER].data,
17535318e8fSkrw packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len)) !=
17635318e8fSkrw NULL)) ||
177e853bc5dShenning ((hp = find_hosts_by_haddr(packet->raw->htype,
1788e1c2028Sderaadt packet->raw->chaddr, packet->raw->hlen)) != NULL)) {
179e853bc5dShenning for (; hp; hp = hp->n_ipaddr) {
180e853bc5dShenning if (!hp->fixed_addr) {
181e853bc5dShenning lease->host = hp;
182e853bc5dShenning break;
183e853bc5dShenning }
184e853bc5dShenning }
1858e1c2028Sderaadt } else
1868e1c2028Sderaadt lease->host = NULL;
187e853bc5dShenning }
188e853bc5dShenning
189e853bc5dShenning /* If this subnet won't boot unknown clients, ignore the
190e853bc5dShenning request. */
191e853bc5dShenning if (!lease->host &&
192e853bc5dShenning !lease->subnet->group->boot_unknown_clients) {
193c525a185Skrw log_info("Ignoring unknown client %s",
1948e1c2028Sderaadt print_hw_addr(packet->raw->htype, packet->raw->hlen,
195e853bc5dShenning packet->raw->chaddr));
1968e1c2028Sderaadt } else if (lease->host && !lease->host->group->allow_booting) {
197c525a185Skrw log_info("Declining to boot client %s",
1988e1c2028Sderaadt lease->host->name ? lease->host->name :
1998e1c2028Sderaadt print_hw_addr(packet->raw->htype, packet->raw->hlen,
200e853bc5dShenning packet->raw->chaddr));
201e853bc5dShenning } else
202e853bc5dShenning ack_lease(packet, lease, DHCPOFFER, cur_time + 120);
203e853bc5dShenning }
204e853bc5dShenning
2058e1c2028Sderaadt void
dhcprequest(struct packet * packet)2068e1c2028Sderaadt dhcprequest(struct packet *packet)
207e853bc5dShenning {
208e853bc5dShenning struct lease *lease;
209e853bc5dShenning struct iaddr cip;
210e853bc5dShenning struct subnet *subnet;
211e853bc5dShenning int ours = 0;
212e853bc5dShenning
213e853bc5dShenning cip.len = 4;
21441b6b05bStobias if (packet->options[DHO_DHCP_REQUESTED_ADDRESS].len == 4)
215e853bc5dShenning memcpy(cip.iabuf,
2168e1c2028Sderaadt packet->options[DHO_DHCP_REQUESTED_ADDRESS].data, 4);
2178e1c2028Sderaadt else
218e853bc5dShenning memcpy(cip.iabuf, &packet->raw->ciaddr.s_addr, 4);
219e853bc5dShenning subnet = find_subnet(cip);
220e853bc5dShenning
2218e1c2028Sderaadt /* Find the lease that matches the address requested by the client. */
222e853bc5dShenning
223e853bc5dShenning if (subnet)
224e853bc5dShenning lease = find_lease(packet, subnet->shared_network, &ours);
225e853bc5dShenning else
226ea507cabSderaadt lease = NULL;
227e853bc5dShenning
228c525a185Skrw log_info("DHCPREQUEST for %s from %s via %s", piaddr(cip),
2298e1c2028Sderaadt print_hw_addr(packet->raw->htype, packet->raw->hlen,
230e853bc5dShenning packet->raw->chaddr),
2318e1c2028Sderaadt packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) :
2328e1c2028Sderaadt packet->interface->name);
233e853bc5dShenning
234e853bc5dShenning /* If a client on a given network REQUESTs a lease on an
2358e1c2028Sderaadt * address on a different network, NAK it. If the Requested
2368e1c2028Sderaadt * Address option was used, the protocol says that it must
2378e1c2028Sderaadt * have been broadcast, so we can trust the source network
2388e1c2028Sderaadt * information.
2398e1c2028Sderaadt *
2408e1c2028Sderaadt * If ciaddr was specified and Requested Address was not, then
2418e1c2028Sderaadt * we really only know for sure what network a packet came from
2428e1c2028Sderaadt * if it came through a BOOTP gateway - if it came through an
2438e1c2028Sderaadt * IP router, we'll just have to assume that it's cool.
2448e1c2028Sderaadt *
2458e1c2028Sderaadt * If we don't think we know where the packet came from, it
2468e1c2028Sderaadt * came through a gateway from an unknown network, so it's not
2478e1c2028Sderaadt * from a RENEWING client. If we recognize the network it
2488e1c2028Sderaadt * *thinks* it's on, we can NAK it even though we don't
2498e1c2028Sderaadt * recognize the network it's *actually* on; otherwise we just
2508e1c2028Sderaadt * have to ignore it.
2518e1c2028Sderaadt *
2528e1c2028Sderaadt * We don't currently try to take advantage of access to the
2538e1c2028Sderaadt * raw packet, because it's not available on all platforms.
2548e1c2028Sderaadt * So a packet that was unicast to us through a router from a
2558e1c2028Sderaadt * RENEWING client is going to look exactly like a packet that
2568e1c2028Sderaadt * was broadcast to us from an INIT-REBOOT client.
2578e1c2028Sderaadt *
2588e1c2028Sderaadt * Since we can't tell the difference between these two kinds
2598e1c2028Sderaadt * of packets, if the packet appears to have come in off the
2608e1c2028Sderaadt * local wire, we have to treat it as if it's a RENEWING
2618e1c2028Sderaadt * client. This means that we can't NAK a RENEWING client on
2628e1c2028Sderaadt * the local wire that has a bogus address. The good news is
2638e1c2028Sderaadt * that we won't ACK it either, so it should revert to INIT
2648e1c2028Sderaadt * state and send us a DHCPDISCOVER, which we *can* work with.
2658e1c2028Sderaadt *
2668e1c2028Sderaadt * Because we can't detect that a RENEWING client is on the
2678e1c2028Sderaadt * wrong wire, it's going to sit there trying to renew until
2688e1c2028Sderaadt * it gets to the REBIND state, when we *can* NAK it because
2698e1c2028Sderaadt * the packet will get to us through a BOOTP gateway. We
2708e1c2028Sderaadt * shouldn't actually see DHCPREQUEST packets from RENEWING
2718e1c2028Sderaadt * clients on the wrong wire anyway, since their idea of their
2728e1c2028Sderaadt * local router will be wrong. In any case, the protocol
2738e1c2028Sderaadt * doesn't really allow us to NAK a DHCPREQUEST from a
2748e1c2028Sderaadt * RENEWING client, so we can punt on this issue.
2758e1c2028Sderaadt */
276e853bc5dShenning if (!packet->shared_network ||
2778e1c2028Sderaadt (packet->raw->ciaddr.s_addr && packet->raw->giaddr.s_addr) ||
27841b6b05bStobias (packet->options[DHO_DHCP_REQUESTED_ADDRESS].len == 4 &&
279e853bc5dShenning !packet->raw->ciaddr.s_addr)) {
280e853bc5dShenning
2818e1c2028Sderaadt /*
2828e1c2028Sderaadt * If we don't know where it came from but we do know
2838e1c2028Sderaadt * where it claims to have come from, it didn't come
2848e1c2028Sderaadt * from there. Fry it.
2858e1c2028Sderaadt */
286e853bc5dShenning if (!packet->shared_network) {
287e853bc5dShenning if (subnet &&
2888e1c2028Sderaadt subnet->shared_network->group->authoritative) {
289e853bc5dShenning nak_lease(packet, &cip);
290e853bc5dShenning return;
291e853bc5dShenning }
292e853bc5dShenning /* Otherwise, ignore it. */
293e853bc5dShenning return;
294e853bc5dShenning }
295e853bc5dShenning
2968e1c2028Sderaadt /*
2978e1c2028Sderaadt * If we do know where it came from and it asked for an
2988e1c2028Sderaadt * address that is not on that shared network, nak it.
2998e1c2028Sderaadt */
300e853bc5dShenning subnet = find_grouped_subnet(packet->shared_network, cip);
301e853bc5dShenning if (!subnet) {
302e853bc5dShenning if (packet->shared_network->group->authoritative)
303e853bc5dShenning nak_lease(packet, &cip);
304e853bc5dShenning return;
305e853bc5dShenning }
306e853bc5dShenning }
307e853bc5dShenning
3088e1c2028Sderaadt /*
3098e1c2028Sderaadt * If we found a lease for the client but it's not the one the
3108e1c2028Sderaadt * client asked for, don't send it - some other server probably
3118e1c2028Sderaadt * made the cut.
3128e1c2028Sderaadt */
313e853bc5dShenning if (lease && !addr_eq(lease->ip_addr, cip)) {
3148e1c2028Sderaadt /*
3158e1c2028Sderaadt * If we found the address the client asked for, but
3168e1c2028Sderaadt * it wasn't what got picked, the lease belongs to us,
3178e1c2028Sderaadt * so we should NAK it.
3188e1c2028Sderaadt */
319e853bc5dShenning if (ours)
320e853bc5dShenning nak_lease(packet, &cip);
321e853bc5dShenning return;
322e853bc5dShenning }
323e853bc5dShenning
3248e1c2028Sderaadt /*
3258e1c2028Sderaadt * If the address the client asked for is ours, but it wasn't
3268e1c2028Sderaadt * available for the client, NAK it.
3278e1c2028Sderaadt */
328e853bc5dShenning if (!lease && ours) {
329e853bc5dShenning nak_lease(packet, &cip);
330e853bc5dShenning return;
331e853bc5dShenning }
332e853bc5dShenning
333e853bc5dShenning /* If we're not allowed to serve this client anymore, don't. */
3348e1c2028Sderaadt if (lease && !lease->host &&
335e853bc5dShenning !lease->subnet->group->boot_unknown_clients) {
336c525a185Skrw log_info("Ignoring unknown client %s",
3378e1c2028Sderaadt print_hw_addr(packet->raw->htype, packet->raw->hlen,
338e853bc5dShenning packet->raw->chaddr));
339e853bc5dShenning return;
34035318e8fSkrw } else if (lease && lease->host && !lease->host->group->allow_booting)
34135318e8fSkrw {
342c525a185Skrw log_info("Declining to renew client %s",
3438e1c2028Sderaadt lease->host->name ? lease->host->name :
3448e1c2028Sderaadt print_hw_addr(packet->raw->htype, packet->raw->hlen,
345e853bc5dShenning packet->raw->chaddr));
346e853bc5dShenning return;
347e853bc5dShenning }
348e853bc5dShenning
3498e1c2028Sderaadt /*
3508e1c2028Sderaadt * If we own the lease that the client is asking for,
3518e1c2028Sderaadt * and it's already been assigned to the client, ack it.
3528e1c2028Sderaadt */
353e853bc5dShenning if (lease &&
354e853bc5dShenning ((lease->uid_len && lease->uid_len ==
355e853bc5dShenning packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len &&
3568e1c2028Sderaadt !memcmp(packet->options[DHO_DHCP_CLIENT_IDENTIFIER].data,
357e853bc5dShenning lease->uid, lease->uid_len)) ||
358e853bc5dShenning (lease->hardware_addr.hlen == packet->raw->hlen &&
359e853bc5dShenning lease->hardware_addr.htype == packet->raw->htype &&
3608e1c2028Sderaadt !memcmp(lease->hardware_addr.haddr, packet->raw->chaddr,
361e853bc5dShenning packet->raw->hlen)))) {
362e853bc5dShenning ack_lease(packet, lease, DHCPACK, 0);
3635f515bebSbeck sync_lease(lease);
364e853bc5dShenning return;
365e853bc5dShenning }
366e853bc5dShenning
3678e1c2028Sderaadt /*
3688e1c2028Sderaadt * At this point, the client has requested a lease, and it's
3698e1c2028Sderaadt * available, but it wasn't assigned to the client, which
3708e1c2028Sderaadt * means that the client probably hasn't gone through the
3718e1c2028Sderaadt * DHCPDISCOVER part of the protocol. We are within our
3728e1c2028Sderaadt * rights to send a DHCPNAK. We can also send a DHCPACK.
3738e1c2028Sderaadt * The thing we probably should not do is to remain silent.
3748e1c2028Sderaadt * For now, we'll just assign the lease to the client anyway.
3758e1c2028Sderaadt */
3765f515bebSbeck if (lease) {
377e853bc5dShenning ack_lease(packet, lease, DHCPACK, 0);
3785f515bebSbeck sync_lease(lease);
3795f515bebSbeck }
380e853bc5dShenning }
381e853bc5dShenning
3828e1c2028Sderaadt void
dhcprelease(struct packet * packet)3838e1c2028Sderaadt dhcprelease(struct packet *packet)
384e853bc5dShenning {
385d7503dcfSkrw char ciaddrbuf[INET_ADDRSTRLEN];
386e853bc5dShenning struct lease *lease;
387e853bc5dShenning struct iaddr cip;
388e853bc5dShenning int i;
389e853bc5dShenning
3908e1c2028Sderaadt /*
3918e1c2028Sderaadt * DHCPRELEASE must not specify address in requested-address
3928e1c2028Sderaadt * option, but old protocol specs weren't explicit about this,
3938e1c2028Sderaadt * so let it go.
3948e1c2028Sderaadt */
395e853bc5dShenning if (packet->options[DHO_DHCP_REQUESTED_ADDRESS].len) {
396c525a185Skrw log_info("DHCPRELEASE from %s specified requested-address.",
3978e1c2028Sderaadt print_hw_addr(packet->raw->htype, packet->raw->hlen,
398e853bc5dShenning packet->raw->chaddr));
399e853bc5dShenning }
400e853bc5dShenning
401e853bc5dShenning i = DHO_DHCP_CLIENT_IDENTIFIER;
402e853bc5dShenning if (packet->options[i].len) {
403e853bc5dShenning lease = find_lease_by_uid(packet->options[i].data,
404e853bc5dShenning packet->options[i].len);
405e853bc5dShenning
4068e1c2028Sderaadt /*
4078e1c2028Sderaadt * See if we can find a lease that matches the
4088e1c2028Sderaadt * IP address the client is claiming.
4098e1c2028Sderaadt */
410e853bc5dShenning for (; lease; lease = lease->n_uid) {
411e853bc5dShenning if (!memcmp(&packet->raw->ciaddr,
412e853bc5dShenning lease->ip_addr.iabuf, 4)) {
413e853bc5dShenning break;
414e853bc5dShenning }
415e853bc5dShenning }
416e853bc5dShenning } else {
4178e1c2028Sderaadt /*
4188e1c2028Sderaadt * The client is supposed to pass a valid client-identifier,
4198e1c2028Sderaadt * but the spec on this has changed historically, so try the
4208e1c2028Sderaadt * IP address in ciaddr if the client-identifier fails.
4218e1c2028Sderaadt */
422e853bc5dShenning cip.len = 4;
423e853bc5dShenning memcpy(cip.iabuf, &packet->raw->ciaddr, 4);
424e853bc5dShenning lease = find_lease_by_ip_addr(cip);
425e853bc5dShenning }
426e853bc5dShenning
427d7503dcfSkrw /* Can't do >1 inet_ntoa() in a printf()! */
428d7503dcfSkrw strlcpy(ciaddrbuf, inet_ntoa(packet->raw->ciaddr), sizeof(ciaddrbuf));
429d7503dcfSkrw
430c525a185Skrw log_info("DHCPRELEASE of %s from %s via %s (%sfound)",
431d7503dcfSkrw ciaddrbuf,
4328e1c2028Sderaadt print_hw_addr(packet->raw->htype, packet->raw->hlen,
433e853bc5dShenning packet->raw->chaddr),
4348e1c2028Sderaadt packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) :
4358e1c2028Sderaadt packet->interface->name,
436e853bc5dShenning lease ? "" : "not ");
437e853bc5dShenning
438fbccfd36Sclaudio /* If we're already acking this lease, don't do it again. */
439fbccfd36Sclaudio if (lease && lease->state) {
440c525a185Skrw log_info("DHCPRELEASE already acking lease %s",
441fbccfd36Sclaudio piaddr(lease->ip_addr));
442fbccfd36Sclaudio return;
443fbccfd36Sclaudio }
444fbccfd36Sclaudio
445e853bc5dShenning /* If we found a lease, release it. */
446e853bc5dShenning if (lease && lease->ends > cur_time) {
4478e1c2028Sderaadt /*
4488e1c2028Sderaadt * First, we ping this lease to see if it's still
4498e1c2028Sderaadt * there. if it is, we don't release it. This avoids
4508e1c2028Sderaadt * the problem of spoofed releases being used to liberate
4518e1c2028Sderaadt * addresses from the server.
452e853bc5dShenning */
453e853bc5dShenning if (!lease->releasing) {
454c525a185Skrw log_info("DHCPRELEASE of %s from %s via %s (found)",
455d7503dcfSkrw ciaddrbuf,
456e853bc5dShenning print_hw_addr(packet->raw->htype,
4578e1c2028Sderaadt packet->raw->hlen, packet->raw->chaddr),
4588e1c2028Sderaadt packet->raw->giaddr.s_addr ?
4598e1c2028Sderaadt inet_ntoa(packet->raw->giaddr) :
4608e1c2028Sderaadt packet->interface->name);
461e853bc5dShenning
462e853bc5dShenning lease->releasing = 1;
463e853bc5dShenning add_timeout(cur_time + 1, lease_ping_timeout, lease);
464e853bc5dShenning icmp_echorequest(&(lease->ip_addr));
465e853bc5dShenning ++outstanding_pings;
4668e1c2028Sderaadt } else {
467c525a185Skrw log_info("DHCPRELEASE of %s from %s via %s ignored "
4688e1c2028Sderaadt "(release already pending)",
469d7503dcfSkrw ciaddrbuf,
470e853bc5dShenning print_hw_addr(packet->raw->htype,
4718e1c2028Sderaadt packet->raw->hlen, packet->raw->chaddr),
4728e1c2028Sderaadt packet->raw->giaddr.s_addr ?
4738e1c2028Sderaadt inet_ntoa(packet->raw->giaddr) :
4748e1c2028Sderaadt packet->interface->name);
475e853bc5dShenning }
4768e1c2028Sderaadt } else {
47735318e8fSkrw log_info("DHCPRELEASE of %s from %s via %s for nonexistent "
47835318e8fSkrw "lease", ciaddrbuf, print_hw_addr(packet->raw->htype,
47935318e8fSkrw packet->raw->hlen, packet->raw->chaddr),
4808e1c2028Sderaadt packet->raw->giaddr.s_addr ?
48135318e8fSkrw inet_ntoa(packet->raw->giaddr) : packet->interface->name);
482e853bc5dShenning }
483e853bc5dShenning }
484e853bc5dShenning
4858e1c2028Sderaadt void
dhcpdecline(struct packet * packet)4868e1c2028Sderaadt dhcpdecline(struct packet *packet)
487e853bc5dShenning {
488e853bc5dShenning struct lease *lease;
489e853bc5dShenning struct iaddr cip;
490e853bc5dShenning
491e853bc5dShenning /* DHCPDECLINE must specify address. */
49241b6b05bStobias if (packet->options[DHO_DHCP_REQUESTED_ADDRESS].len != 4)
493e853bc5dShenning return;
494e853bc5dShenning
495e853bc5dShenning cip.len = 4;
496e853bc5dShenning memcpy(cip.iabuf,
497e853bc5dShenning packet->options[DHO_DHCP_REQUESTED_ADDRESS].data, 4);
498e853bc5dShenning lease = find_lease_by_ip_addr(cip);
499e853bc5dShenning
500c525a185Skrw log_info("DHCPDECLINE on %s from %s via %s",
5018e1c2028Sderaadt piaddr(cip), print_hw_addr(packet->raw->htype,
5028e1c2028Sderaadt packet->raw->hlen, packet->raw->chaddr),
5038e1c2028Sderaadt packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) :
5048e1c2028Sderaadt packet->interface->name);
505e853bc5dShenning
506fbccfd36Sclaudio /* If we're already acking this lease, don't do it again. */
507fbccfd36Sclaudio if (lease && lease->state) {
508c525a185Skrw log_info("DHCPDECLINE already acking lease %s",
509fbccfd36Sclaudio piaddr(lease->ip_addr));
510fbccfd36Sclaudio return;
511fbccfd36Sclaudio }
512fbccfd36Sclaudio
513e853bc5dShenning /* If we found a lease, mark it as unusable and complain. */
5148e1c2028Sderaadt if (lease)
515e853bc5dShenning abandon_lease(lease, "declined.");
516e853bc5dShenning }
517e853bc5dShenning
5188e1c2028Sderaadt void
dhcpinform(struct packet * packet)5198e1c2028Sderaadt dhcpinform(struct packet *packet)
520e853bc5dShenning {
521fc9106f9Syasuoka struct lease lease;
52227efec96Smillert struct iaddr cip;
52327efec96Smillert struct subnet *subnet;
52427efec96Smillert
52527efec96Smillert /*
52627efec96Smillert * ciaddr should be set to client's IP address but
52727efec96Smillert * not all clients are standards compliant.
52827efec96Smillert */
52927efec96Smillert cip.len = 4;
530*8415e52bSreyk if (packet->raw->ciaddr.s_addr && !packet->raw->giaddr.s_addr) {
531fc9106f9Syasuoka if (memcmp(&packet->raw->ciaddr.s_addr,
532fc9106f9Syasuoka packet->client_addr.iabuf, 4) != 0) {
533c525a185Skrw log_info("DHCPINFORM from %s but ciaddr %s is not "
5346b03e9c2Skrw "consistent with actual address",
535fc9106f9Syasuoka piaddr(packet->client_addr),
536fc9106f9Syasuoka inet_ntoa(packet->raw->ciaddr));
537fc9106f9Syasuoka return;
538fc9106f9Syasuoka }
53927efec96Smillert memcpy(cip.iabuf, &packet->raw->ciaddr.s_addr, 4);
540fc9106f9Syasuoka } else
54127efec96Smillert memcpy(cip.iabuf, &packet->client_addr.iabuf, 4);
54227efec96Smillert
543c525a185Skrw log_info("DHCPINFORM from %s", piaddr(cip));
54427efec96Smillert
54527efec96Smillert /* Find the lease that matches the address requested by the client. */
54627efec96Smillert subnet = find_subnet(cip);
54727efec96Smillert if (!subnet)
54827efec96Smillert return;
54927efec96Smillert
55027efec96Smillert /* Sourceless packets don't make sense here. */
55127efec96Smillert if (!subnet->shared_network) {
552c525a185Skrw log_info("Packet from unknown subnet: %s",
55327efec96Smillert inet_ntoa(packet->raw->giaddr));
55427efec96Smillert return;
55527efec96Smillert }
55627efec96Smillert
557fc9106f9Syasuoka /* Use a fake lease entry */
558fc9106f9Syasuoka memset(&lease, 0, sizeof(lease));
559fc9106f9Syasuoka lease.subnet = subnet;
560fc9106f9Syasuoka lease.shared_network = subnet->shared_network;
56127efec96Smillert
562fc9106f9Syasuoka if (packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len)
563fc9106f9Syasuoka lease.host = find_hosts_by_uid(
564fc9106f9Syasuoka packet->options[DHO_DHCP_CLIENT_IDENTIFIER].data,
565fc9106f9Syasuoka packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len);
566fc9106f9Syasuoka
567fc9106f9Syasuoka lease.starts = lease.timestamp = lease.ends = MIN_TIME;
568fc9106f9Syasuoka lease.flags = INFORM_NOLEASE;
569fc9106f9Syasuoka ack_lease(packet, &lease, DHCPACK, 0);
570fc9106f9Syasuoka if (lease.state != NULL)
571fc9106f9Syasuoka free_lease_state(lease.state, "ack_lease");
572e853bc5dShenning }
573e853bc5dShenning
5748e1c2028Sderaadt void
nak_lease(struct packet * packet,struct iaddr * cip)5758e1c2028Sderaadt nak_lease(struct packet *packet, struct iaddr *cip)
576e853bc5dShenning {
577e853bc5dShenning struct sockaddr_in to;
578e853bc5dShenning struct in_addr from;
5791a4d4b6bSkrw ssize_t result;
5801a4d4b6bSkrw int i;
581e853bc5dShenning struct dhcp_packet raw;
582e853bc5dShenning unsigned char nak = DHCPNAK;
583e853bc5dShenning struct packet outgoing;
5842c9b957aSkrw struct tree_cache *options[256];
5852c9b957aSkrw struct tree_cache dhcpnak_tree, dhcpmsg_tree;
5862c9b957aSkrw struct tree_cache client_tree, server_tree;
587e853bc5dShenning
588e853bc5dShenning memset(options, 0, sizeof options);
589e853bc5dShenning memset(&outgoing, 0, sizeof outgoing);
590e853bc5dShenning memset(&raw, 0, sizeof raw);
591e853bc5dShenning outgoing.raw = &raw;
592e853bc5dShenning
593e853bc5dShenning /* Set DHCP_MESSAGE_TYPE to DHCPNAK */
5949e601734Skrw i = DHO_DHCP_MESSAGE_TYPE;
5959e601734Skrw options[i] = &dhcpnak_tree;
5969e601734Skrw options[i]->value = &nak;
5979e601734Skrw options[i]->len = sizeof nak;
5989e601734Skrw options[i]->buf_size = sizeof nak;
5999e601734Skrw options[i]->timeout = -1;
6009e601734Skrw options[i]->tree = NULL;
6019e601734Skrw options[i]->flags = 0;
602e853bc5dShenning
603e853bc5dShenning /* Set DHCP_MESSAGE to whatever the message is */
6049e601734Skrw i = DHO_DHCP_MESSAGE;
6059e601734Skrw options[i] = &dhcpmsg_tree;
6069e601734Skrw options[i]->value = (unsigned char *)dhcp_message;
6079e601734Skrw options[i]->len = strlen(dhcp_message);
6089e601734Skrw options[i]->buf_size = strlen(dhcp_message);
6099e601734Skrw options[i]->timeout = -1;
6109e601734Skrw options[i]->tree = NULL;
6119e601734Skrw options[i]->flags = 0;
6122c9b957aSkrw
6139e20d503Skrw /* Include server identifier in the NAK. At least one
6149e20d503Skrw * router vendor depends on it when using dhcp relay proxy mode.
6159e20d503Skrw */
6169e601734Skrw i = DHO_DHCP_SERVER_IDENTIFIER;
6179e601734Skrw if (packet->options[i].len) {
6189e601734Skrw options[i] = &server_tree;
6199e601734Skrw options[i]->value = packet->options[i].data,
6209e601734Skrw options[i]->len = packet->options[i].len;
6219e601734Skrw options[i]->buf_size = packet->options[i].len;
6229e601734Skrw options[i]->timeout = -1;
6239e601734Skrw options[i]->tree = NULL;
6249e601734Skrw options[i]->flags = 0;
6259e20d503Skrw }
6269e20d503Skrw
6272c9b957aSkrw /* Echo back the client-identifier as RFC 6842 mandates. */
6282c9b957aSkrw i = DHO_DHCP_CLIENT_IDENTIFIER;
6292c9b957aSkrw if (packet->options[i].len) {
6302c9b957aSkrw options[i] = &client_tree;
6312c9b957aSkrw options[i]->value = packet->options[i].data,
6322c9b957aSkrw options[i]->len = packet->options[i].len;
6332c9b957aSkrw options[i]->buf_size = packet->options[i].len;
6342c9b957aSkrw options[i]->timeout = -1;
6352c9b957aSkrw options[i]->tree = NULL;
6362c9b957aSkrw options[i]->flags = 0;
6372c9b957aSkrw }
6382c9b957aSkrw
639e853bc5dShenning /* Do not use the client's requested parameter list. */
640e853bc5dShenning i = DHO_DHCP_PARAMETER_REQUEST_LIST;
641e853bc5dShenning if (packet->options[i].data) {
642e853bc5dShenning packet->options[i].len = 0;
64392b98df2Skrw free(packet->options[i].data);
6448e1c2028Sderaadt packet->options[i].data = NULL;
645e853bc5dShenning }
646e853bc5dShenning
647e853bc5dShenning /* Set up the option buffer... */
6488e1c2028Sderaadt outgoing.packet_length = cons_options(packet, outgoing.raw,
6498e1c2028Sderaadt 0, options, 0, 0, 0, NULL, 0);
650e853bc5dShenning
651e853bc5dShenning /* memset(&raw.ciaddr, 0, sizeof raw.ciaddr);*/
652e853bc5dShenning raw.siaddr = packet->interface->primary_address;
653e853bc5dShenning raw.giaddr = packet->raw->giaddr;
654e853bc5dShenning memcpy(raw.chaddr, packet->raw->chaddr, sizeof raw.chaddr);
655e853bc5dShenning raw.hlen = packet->raw->hlen;
656e853bc5dShenning raw.htype = packet->raw->htype;
657e853bc5dShenning raw.xid = packet->raw->xid;
658e853bc5dShenning raw.secs = packet->raw->secs;
659e853bc5dShenning raw.flags = packet->raw->flags | htons(BOOTP_BROADCAST);
660e853bc5dShenning raw.hops = packet->raw->hops;
661e853bc5dShenning raw.op = BOOTREPLY;
662e853bc5dShenning
663e853bc5dShenning /* Report what we're sending... */
664c525a185Skrw log_info("DHCPNAK on %s to %s via %s", piaddr(*cip),
665ea507cabSderaadt print_hw_addr(packet->raw->htype, packet->raw->hlen,
666ea507cabSderaadt packet->raw->chaddr), packet->raw->giaddr.s_addr ?
667ea507cabSderaadt inet_ntoa(packet->raw->giaddr) : packet->interface->name);
668e853bc5dShenning
669e853bc5dShenning /* Set up the common stuff... */
670e853bc5dShenning memset(&to, 0, sizeof to);
671e853bc5dShenning to.sin_family = AF_INET;
672e853bc5dShenning to.sin_len = sizeof to;
673e853bc5dShenning
674e853bc5dShenning from = packet->interface->primary_address;
675e853bc5dShenning
676e853bc5dShenning /* Make sure that the packet is at least as big as a BOOTP packet. */
677e853bc5dShenning if (outgoing.packet_length < BOOTP_MIN_LEN)
678e853bc5dShenning outgoing.packet_length = BOOTP_MIN_LEN;
679e853bc5dShenning
6808e1c2028Sderaadt /*
6818e1c2028Sderaadt * If this was gatewayed, send it back to the gateway.
6828e1c2028Sderaadt * Otherwise, broadcast it on the local network.
6838e1c2028Sderaadt */
684e853bc5dShenning if (raw.giaddr.s_addr) {
685e853bc5dShenning to.sin_addr = raw.giaddr;
686390956b7Scanacar to.sin_port = server_port;
687e853bc5dShenning
68884d8c049Syasuoka result = packet->interface->send_packet(packet->interface, &raw,
689cc3e8043Sclaudio outgoing.packet_length, from, &to, packet->haddr);
690e853bc5dShenning if (result == -1)
6910438cf0aSkrw log_warn("send_fallback");
692e853bc5dShenning return;
693e853bc5dShenning } else {
694e853bc5dShenning to.sin_addr.s_addr = htonl(INADDR_BROADCAST);
695390956b7Scanacar to.sin_port = client_port;
696e853bc5dShenning }
697e853bc5dShenning
698e853bc5dShenning errno = 0;
69984d8c049Syasuoka result = packet->interface->send_packet(packet->interface, &raw,
7008e1c2028Sderaadt outgoing.packet_length, from, &to, NULL);
701e853bc5dShenning }
702e853bc5dShenning
7038e1c2028Sderaadt void
ack_lease(struct packet * packet,struct lease * lease,unsigned int offer,time_t when)7048e1c2028Sderaadt ack_lease(struct packet *packet, struct lease *lease, unsigned int offer,
7058e1c2028Sderaadt time_t when)
706e853bc5dShenning {
707e853bc5dShenning struct lease lt;
708e853bc5dShenning struct lease_state *state;
7098e1c2028Sderaadt time_t lease_time, offered_lease_time, max_lease_time, default_lease_time;
710e853bc5dShenning struct class *vendor_class, *user_class;
711a51e9872Skrw int ulafdr, echo_client_id, i;
712e853bc5dShenning
713e853bc5dShenning /* If we're already acking this lease, don't do it again. */
714e853bc5dShenning if (lease->state) {
715b450f114Sbeck if ((lease->flags & STATIC_LEASE) ||
716b450f114Sbeck cur_time - lease->timestamp < 60) {
71735318e8fSkrw log_info("already acking lease %s",
71835318e8fSkrw piaddr(lease->ip_addr));
719e853bc5dShenning return;
720e853bc5dShenning }
721b450f114Sbeck free_lease_state(lease->state, "ACK timed out");
722b450f114Sbeck lease->state = NULL;
723b450f114Sbeck }
724e853bc5dShenning
7259e601734Skrw i = DHO_DHCP_CLASS_IDENTIFIER;
7269e601734Skrw if (packet->options[i].len) {
7279e601734Skrw vendor_class = find_class(0, packet->options[i].data,
7289e601734Skrw packet->options[i].len);
7298e1c2028Sderaadt } else
7308e1c2028Sderaadt vendor_class = NULL;
731e853bc5dShenning
7329e601734Skrw i = DHO_DHCP_USER_CLASS_ID;
7339e601734Skrw if (packet->options[i].len) {
7349e601734Skrw user_class = find_class(1, packet->options[i].data,
7359e601734Skrw packet->options[i].len);
7368e1c2028Sderaadt } else
7378e1c2028Sderaadt user_class = NULL;
738e853bc5dShenning
739e853bc5dShenning /*
740e853bc5dShenning * If there is not a specific host entry, and either the
741e853bc5dShenning * vendor class or user class (if they exist) deny booting,
742e853bc5dShenning * then bug out.
743e853bc5dShenning */
744e853bc5dShenning if (!lease->host) {
745e853bc5dShenning if (vendor_class && !vendor_class->group->allow_booting) {
746c525a185Skrw log_debug("Booting denied by vendor class");
747e853bc5dShenning return;
748e853bc5dShenning }
749e853bc5dShenning
750e853bc5dShenning if (user_class && !user_class->group->allow_booting) {
751c525a185Skrw log_debug("Booting denied by user class");
752e853bc5dShenning return;
753e853bc5dShenning }
754e853bc5dShenning }
755e853bc5dShenning
756e853bc5dShenning /* Allocate a lease state structure... */
757e853bc5dShenning state = new_lease_state("ack_lease");
758e853bc5dShenning if (!state)
759c525a185Skrw fatalx("unable to allocate lease state!");
760e853bc5dShenning memset(state, 0, sizeof *state);
761e853bc5dShenning state->got_requested_address = packet->got_requested_address;
762e853bc5dShenning state->shared_network = packet->interface->shared_network;
763e853bc5dShenning
764e853bc5dShenning /* Remember if we got a server identifier option. */
7659e601734Skrw i = DHO_DHCP_SERVER_IDENTIFIER;
7669e601734Skrw if (packet->options[i].len)
767e853bc5dShenning state->got_server_identifier = 1;
768e853bc5dShenning
769e853bc5dShenning /* Replace the old lease hostname with the new one, if it's changed. */
7709e601734Skrw i = DHO_HOST_NAME;
7719e601734Skrw if (packet->options[i].len && lease->client_hostname &&
7729e601734Skrw (strlen(lease->client_hostname) == packet->options[i].len) &&
7739e601734Skrw !memcmp(lease->client_hostname, packet->options[i].data,
7749e601734Skrw packet->options[i].len)) {
7759e601734Skrw } else if (packet->options[i].len) {
776e853bc5dShenning free(lease->client_hostname);
7779e601734Skrw lease->client_hostname = malloc( packet->options[i].len + 1);
778e853bc5dShenning if (!lease->client_hostname)
779c525a185Skrw fatalx("no memory for client hostname.\n");
7809e601734Skrw memcpy(lease->client_hostname, packet->options[i].data,
7819e601734Skrw packet->options[i].len);
7829e601734Skrw lease->client_hostname[packet->options[i].len] = 0;
783e853bc5dShenning } else if (lease->client_hostname) {
784e853bc5dShenning free(lease->client_hostname);
785e853bc5dShenning lease->client_hostname = 0;
786e853bc5dShenning }
787e853bc5dShenning
7882c9b957aSkrw /* Replace the lease client identifier with a new one. */
7892c9b957aSkrw i = DHO_DHCP_CLIENT_IDENTIFIER;
7902c9b957aSkrw if (packet->options[i].len && lease->client_identifier &&
7918d148acdSkrw lease->client_identifier_len == packet->options[i].len &&
7922c9b957aSkrw !memcmp(lease->client_identifier, packet->options[i].data,
7932c9b957aSkrw packet->options[i].len)) {
7942c9b957aSkrw /* Same client identifier. */
7952c9b957aSkrw } else if (packet->options[i].len) {
7962c9b957aSkrw free(lease->client_identifier);
7972c9b957aSkrw lease->client_identifier = malloc(packet->options[i].len);
7982c9b957aSkrw if (!lease->client_identifier)
799c525a185Skrw fatalx("no memory for client identifier.\n");
8002c9b957aSkrw lease->client_identifier_len = packet->options[i].len;
8012c9b957aSkrw memcpy(lease->client_identifier, packet->options[i].data,
8022c9b957aSkrw packet->options[i].len);
8032c9b957aSkrw } else if (lease->client_identifier) {
8042c9b957aSkrw free(lease->client_identifier);
8052c9b957aSkrw lease->client_identifier = NULL;
8062c9b957aSkrw lease->client_identifier_len = 0;
8072c9b957aSkrw }
8082c9b957aSkrw
8098e1c2028Sderaadt /*
8108e1c2028Sderaadt * Choose a filename; first from the host_decl, if any, then from
8118e1c2028Sderaadt * the user class, then from the vendor class.
8128e1c2028Sderaadt */
813e853bc5dShenning if (lease->host && lease->host->group->filename)
814e853bc5dShenning strlcpy(state->filename, lease->host->group->filename,
815e853bc5dShenning sizeof state->filename);
816e853bc5dShenning else if (user_class && user_class->group->filename)
817e853bc5dShenning strlcpy(state->filename, user_class->group->filename,
818e853bc5dShenning sizeof state->filename);
819e853bc5dShenning else if (vendor_class && vendor_class->group->filename)
820e853bc5dShenning strlcpy(state->filename, vendor_class->group->filename,
821e853bc5dShenning sizeof state->filename);
822e853bc5dShenning else if (packet->raw->file[0])
823e853bc5dShenning strlcpy(state->filename, packet->raw->file,
824e853bc5dShenning sizeof state->filename);
825e853bc5dShenning else if (lease->subnet->group->filename)
8268e1c2028Sderaadt strlcpy(state->filename, lease->subnet->group->filename,
827e853bc5dShenning sizeof state->filename);
828e853bc5dShenning else
829e853bc5dShenning strlcpy(state->filename, "", sizeof state->filename);
830e853bc5dShenning
831e853bc5dShenning /* Choose a server name as above. */
832e853bc5dShenning if (lease->host && lease->host->group->server_name)
833e853bc5dShenning state->server_name = lease->host->group->server_name;
834e853bc5dShenning else if (user_class && user_class->group->server_name)
835e853bc5dShenning state->server_name = user_class->group->server_name;
836e853bc5dShenning else if (vendor_class && vendor_class->group->server_name)
837e853bc5dShenning state->server_name = vendor_class->group->server_name;
838e853bc5dShenning else if (lease->subnet->group->server_name)
8398e1c2028Sderaadt state->server_name = lease->subnet->group->server_name;
8408e1c2028Sderaadt else state->server_name = NULL;
841e853bc5dShenning
8428e1c2028Sderaadt /*
8438e1c2028Sderaadt * At this point, we have a lease that we can offer the client.
8448e1c2028Sderaadt * Now we construct a lease structure that contains what we want,
8458e1c2028Sderaadt * and call supersede_lease to do the right thing with it.
8468e1c2028Sderaadt */
847e853bc5dShenning memset(<, 0, sizeof lt);
848e853bc5dShenning
8498e1c2028Sderaadt /*
8508e1c2028Sderaadt * Use the ip address of the lease that we finally found in
8518e1c2028Sderaadt * the database.
8528e1c2028Sderaadt */
853e853bc5dShenning lt.ip_addr = lease->ip_addr;
854e853bc5dShenning
855e853bc5dShenning /* Start now. */
856e853bc5dShenning lt.starts = cur_time;
857e853bc5dShenning
858e853bc5dShenning /* Figure out maximum lease time. */
8598e1c2028Sderaadt if (lease->host && lease->host->group->max_lease_time)
860e853bc5dShenning max_lease_time = lease->host->group->max_lease_time;
861e853bc5dShenning else
862e853bc5dShenning max_lease_time = lease->subnet->group->max_lease_time;
863e853bc5dShenning
864e853bc5dShenning /* Figure out default lease time. */
8658e1c2028Sderaadt if (lease->host && lease->host->group->default_lease_time)
8668e1c2028Sderaadt default_lease_time = lease->host->group->default_lease_time;
867e853bc5dShenning else
8688e1c2028Sderaadt default_lease_time = lease->subnet->group->default_lease_time;
869e853bc5dShenning
8708e1c2028Sderaadt /*
8718e1c2028Sderaadt * Figure out how long a lease to assign. If this is a
8728e1c2028Sderaadt * dynamic BOOTP lease, its duration must be infinite.
8738e1c2028Sderaadt */
874e853bc5dShenning if (offer) {
8759e601734Skrw i = DHO_DHCP_LEASE_TIME;
8769e601734Skrw if (packet->options[i].len == 4) {
8779e601734Skrw lease_time = getULong( packet->options[i].data);
878e853bc5dShenning
8798e1c2028Sderaadt /*
8808e1c2028Sderaadt * Don't let the client ask for a longer lease than
8818e1c2028Sderaadt * is supported for this subnet or host.
8825c9a6b01Stom *
8835c9a6b01Stom * time_t is signed, so really large numbers come
8845c9a6b01Stom * back as negative. Don't allow lease_time of 0,
8855c9a6b01Stom * either.
8868e1c2028Sderaadt */
8875c9a6b01Stom if (lease_time < 1 || lease_time > max_lease_time)
888e853bc5dShenning lease_time = max_lease_time;
889e853bc5dShenning } else
890e853bc5dShenning lease_time = default_lease_time;
891e853bc5dShenning
892e853bc5dShenning state->offered_expiry = cur_time + lease_time;
893e853bc5dShenning if (when)
894e853bc5dShenning lt.ends = when;
895e853bc5dShenning else
896e853bc5dShenning lt.ends = state->offered_expiry;
897e853bc5dShenning } else {
898e853bc5dShenning if (lease->host &&
899e853bc5dShenning lease->host->group->bootp_lease_length)
900e853bc5dShenning lt.ends = (cur_time +
9018e1c2028Sderaadt lease->host->group->bootp_lease_length);
902e853bc5dShenning else if (lease->subnet->group->bootp_lease_length)
903e853bc5dShenning lt.ends = (cur_time +
9048e1c2028Sderaadt lease->subnet->group->bootp_lease_length);
905e853bc5dShenning else if (lease->host &&
906e853bc5dShenning lease->host->group->bootp_lease_cutoff)
907e853bc5dShenning lt.ends = lease->host->group->bootp_lease_cutoff;
908e853bc5dShenning else
9098e1c2028Sderaadt lt.ends = lease->subnet->group->bootp_lease_cutoff;
910e853bc5dShenning state->offered_expiry = lt.ends;
911e853bc5dShenning lt.flags = BOOTP_LEASE;
912e853bc5dShenning }
913e853bc5dShenning
914e853bc5dShenning /* Record the uid, if given... */
915e853bc5dShenning i = DHO_DHCP_CLIENT_IDENTIFIER;
916e853bc5dShenning if (packet->options[i].len) {
917e853bc5dShenning if (packet->options[i].len <= sizeof lt.uid_buf) {
918e853bc5dShenning memcpy(lt.uid_buf, packet->options[i].data,
919e853bc5dShenning packet->options[i].len);
920e853bc5dShenning lt.uid = lt.uid_buf;
921e853bc5dShenning lt.uid_max = sizeof lt.uid_buf;
922e853bc5dShenning lt.uid_len = packet->options[i].len;
923e853bc5dShenning } else {
924e853bc5dShenning lt.uid_max = lt.uid_len = packet->options[i].len;
92535de856eSderaadt lt.uid = malloc(lt.uid_max);
926e853bc5dShenning if (!lt.uid)
927c525a185Skrw fatalx("can't allocate memory for large uid.");
9288e1c2028Sderaadt memcpy(lt.uid, packet->options[i].data, lt.uid_len);
929e853bc5dShenning }
930e853bc5dShenning }
931e853bc5dShenning
932e853bc5dShenning lt.host = lease->host;
933e853bc5dShenning lt.subnet = lease->subnet;
934e853bc5dShenning lt.shared_network = lease->shared_network;
935e853bc5dShenning
936e853bc5dShenning /* Don't call supersede_lease on a mocked-up lease. */
937fc9106f9Syasuoka if (lease->flags & (STATIC_LEASE | INFORM_NOLEASE)) {
938e853bc5dShenning /* Copy the hardware address into the static lease
939e853bc5dShenning structure. */
940e853bc5dShenning lease->hardware_addr.hlen = packet->raw->hlen;
941e853bc5dShenning lease->hardware_addr.htype = packet->raw->htype;
942e853bc5dShenning memcpy(lease->hardware_addr.haddr, packet->raw->chaddr,
943e853bc5dShenning sizeof packet->raw->chaddr); /* XXX */
944e853bc5dShenning } else {
945e853bc5dShenning /* Record the hardware address, if given... */
946e853bc5dShenning lt.hardware_addr.hlen = packet->raw->hlen;
947e853bc5dShenning lt.hardware_addr.htype = packet->raw->htype;
948e853bc5dShenning memcpy(lt.hardware_addr.haddr, packet->raw->chaddr,
949e853bc5dShenning sizeof packet->raw->chaddr);
950e853bc5dShenning
951e853bc5dShenning /* Install the new information about this lease in the
952e853bc5dShenning database. If this is a DHCPACK or a dynamic BOOTREPLY
953e853bc5dShenning and we can't write the lease, don't ACK it (or BOOTREPLY
954e853bc5dShenning it) either. */
955e853bc5dShenning
95635318e8fSkrw if (!(supersede_lease(lease, <, !offer ||
95735318e8fSkrw offer == DHCPACK) || (offer && offer != DHCPACK))) {
95804fac749Smillert free_lease_state(state, "ack_lease: !supersede_lease");
959e853bc5dShenning return;
960e853bc5dShenning }
96104fac749Smillert }
962e853bc5dShenning
963e853bc5dShenning /* Remember the interface on which the packet arrived. */
964e853bc5dShenning state->ip = packet->interface;
965e853bc5dShenning
966e853bc5dShenning /* Set a flag if this client is a lame Microsoft client that NUL
967e853bc5dShenning terminates string options and expects us to do likewise. */
9689e601734Skrw i = DHO_HOST_NAME;
9699e601734Skrw if (packet->options[i].len &&
9709e601734Skrw packet->options[i].data[packet->options[i].len - 1] == '\0')
971e853bc5dShenning lease->flags |= MS_NULL_TERMINATION;
972e853bc5dShenning else
973e853bc5dShenning lease->flags &= ~MS_NULL_TERMINATION;
974e853bc5dShenning
975e853bc5dShenning /* Remember the giaddr, xid, secs, flags and hops. */
976e853bc5dShenning state->giaddr = packet->raw->giaddr;
977e853bc5dShenning state->ciaddr = packet->raw->ciaddr;
978e853bc5dShenning state->xid = packet->raw->xid;
979e853bc5dShenning state->secs = packet->raw->secs;
980e853bc5dShenning state->bootp_flags = packet->raw->flags;
981e853bc5dShenning state->hops = packet->raw->hops;
982e853bc5dShenning state->offer = offer;
983cc3e8043Sclaudio memcpy(&state->haddr, packet->haddr, sizeof state->haddr);
984e853bc5dShenning
985e853bc5dShenning /* Figure out what options to send to the client: */
986e853bc5dShenning
987e853bc5dShenning /* Start out with the subnet options... */
9888e1c2028Sderaadt memcpy(state->options, lease->subnet->group->options,
989e853bc5dShenning sizeof state->options);
990e853bc5dShenning
991e853bc5dShenning /* Vendor and user classes are only supported for DHCP clients. */
992e853bc5dShenning if (state->offer) {
993e853bc5dShenning /* If we have a vendor class, install those options,
994e853bc5dShenning superseding any subnet options. */
995e853bc5dShenning if (vendor_class) {
996e853bc5dShenning for (i = 0; i < 256; i++)
997e853bc5dShenning if (vendor_class->group->options[i])
998e853bc5dShenning state->options[i] =
9998e1c2028Sderaadt vendor_class->group->options[i];
1000e853bc5dShenning }
1001e853bc5dShenning
1002e853bc5dShenning /* If we have a user class, install those options,
1003e853bc5dShenning superseding any subnet and vendor class options. */
1004e853bc5dShenning if (user_class) {
1005e853bc5dShenning for (i = 0; i < 256; i++)
1006e853bc5dShenning if (user_class->group->options[i])
1007e853bc5dShenning state->options[i] =
10088e1c2028Sderaadt user_class->group->options[i];
1009e853bc5dShenning }
1010e853bc5dShenning
1011e853bc5dShenning }
1012e853bc5dShenning
1013e853bc5dShenning /* If we have a host_decl structure, install the associated
1014e853bc5dShenning options, superseding anything that's in the way. */
1015e853bc5dShenning if (lease->host) {
1016e853bc5dShenning for (i = 0; i < 256; i++)
1017e853bc5dShenning if (lease->host->group->options[i])
10188e1c2028Sderaadt state->options[i] =
10198e1c2028Sderaadt lease->host->group->options[i];
1020e853bc5dShenning }
1021e853bc5dShenning
1022e853bc5dShenning /* Get the Maximum Message Size option from the packet, if one
1023e853bc5dShenning was sent. */
1024e853bc5dShenning i = DHO_DHCP_MAX_MESSAGE_SIZE;
1025e853bc5dShenning if (packet->options[i].data &&
10268e1c2028Sderaadt packet->options[i].len == sizeof(u_int16_t))
10278e1c2028Sderaadt state->max_message_size = getUShort(packet->options[i].data);
1028e853bc5dShenning /* Otherwise, if a maximum message size was specified, use that. */
1029e853bc5dShenning else if (state->options[i] && state->options[i]->value)
10308e1c2028Sderaadt state->max_message_size = getUShort(state->options[i]->value);
1031e853bc5dShenning
1032e853bc5dShenning /* Save the parameter request list if there is one. */
1033e853bc5dShenning i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1034e853bc5dShenning if (packet->options[i].data) {
1035d60fc4a4Skrw state->prl = calloc(1, packet->options[i].len);
1036e853bc5dShenning if (!state->prl)
1037c525a185Skrw log_warnx("no memory for parameter request list");
1038e853bc5dShenning else {
10398e1c2028Sderaadt memcpy(state->prl, packet->options[i].data,
1040e853bc5dShenning packet->options[i].len);
1041e853bc5dShenning state->prl_len = packet->options[i].len;
1042e853bc5dShenning }
1043e853bc5dShenning }
1044e853bc5dShenning
1045e853bc5dShenning /* If we didn't get a hostname from an option somewhere, see if
1046e853bc5dShenning we can get one from the lease. */
1047e853bc5dShenning i = DHO_HOST_NAME;
1048e853bc5dShenning if (!state->options[i] && lease->hostname) {
1049e853bc5dShenning state->options[i] = new_tree_cache("hostname");
1050e853bc5dShenning state->options[i]->flags = TC_TEMPORARY;
10518e1c2028Sderaadt state->options[i]->value = (unsigned char *)lease->hostname;
1052e853bc5dShenning state->options[i]->len = strlen(lease->hostname);
1053e853bc5dShenning state->options[i]->buf_size = state->options[i]->len;
10545dee4edfSotto state->options[i]->timeout = -1;
10558e1c2028Sderaadt state->options[i]->tree = NULL;
1056e853bc5dShenning }
1057e853bc5dShenning
10588e1c2028Sderaadt /*
10598e1c2028Sderaadt * Now, if appropriate, put in DHCP-specific options that
10608e1c2028Sderaadt * override those.
10618e1c2028Sderaadt */
1062e853bc5dShenning if (state->offer) {
1063e853bc5dShenning i = DHO_DHCP_MESSAGE_TYPE;
1064e853bc5dShenning state->options[i] = new_tree_cache("message-type");
1065e853bc5dShenning state->options[i]->flags = TC_TEMPORARY;
1066e853bc5dShenning state->options[i]->value = &state->offer;
1067e853bc5dShenning state->options[i]->len = sizeof state->offer;
1068e853bc5dShenning state->options[i]->buf_size = sizeof state->offer;
10695dee4edfSotto state->options[i]->timeout = -1;
10708e1c2028Sderaadt state->options[i]->tree = NULL;
1071e853bc5dShenning
1072e853bc5dShenning i = DHO_DHCP_SERVER_IDENTIFIER;
1073e853bc5dShenning if (!state->options[i]) {
1074e853bc5dShenning use_primary:
1075e853bc5dShenning state->options[i] = new_tree_cache("server-id");
1076e853bc5dShenning state->options[i]->value =
10778e1c2028Sderaadt (unsigned char *)&state->ip->primary_address;
1078e853bc5dShenning state->options[i]->len =
1079e853bc5dShenning sizeof state->ip->primary_address;
10809e601734Skrw state->options[i]->buf_size = state->options[i]->len;
10815dee4edfSotto state->options[i]->timeout = -1;
10828e1c2028Sderaadt state->options[i]->tree = NULL;
10838e1c2028Sderaadt state->from.len = sizeof state->ip->primary_address;
10848e1c2028Sderaadt memcpy(state->from.iabuf, &state->ip->primary_address,
1085e853bc5dShenning state->from.len);
1086e853bc5dShenning } else {
1087e853bc5dShenning /* Find the value of the server identifier... */
1088e853bc5dShenning if (!tree_evaluate(state->options[i]))
1089e853bc5dShenning goto use_primary;
1090e853bc5dShenning if (!state->options[i]->value ||
109135318e8fSkrw (state->options[i]->len >
109235318e8fSkrw sizeof state->from.iabuf))
1093e853bc5dShenning goto use_primary;
1094e853bc5dShenning
1095e853bc5dShenning state->from.len = state->options[i]->len;
10968e1c2028Sderaadt memcpy(state->from.iabuf, state->options[i]->value,
1097e853bc5dShenning state->from.len);
1098e853bc5dShenning }
10997e041c99Skrw /*
11007e041c99Skrw * Do not ACK a REQUEST intended for another server.
11017e041c99Skrw */
11027e041c99Skrw if (packet->options[i].len == 4) {
11037e041c99Skrw if (state->options[i]->len != 4 ||
11047e041c99Skrw memcmp(packet->options[i].data,
11057e041c99Skrw state->options[i]->value, 4) != 0) {
11067e041c99Skrw free_lease_state(state, "ack_lease: "
11077e041c99Skrw "server identifier");
11087e041c99Skrw return;
11097e041c99Skrw }
11107e041c99Skrw }
11117e041c99Skrw
1112fc9106f9Syasuoka /* If we used the vendor class the client specified, we
1113fc9106f9Syasuoka have to return it. */
1114fc9106f9Syasuoka if (vendor_class) {
1115fc9106f9Syasuoka i = DHO_DHCP_CLASS_IDENTIFIER;
11169e601734Skrw state->options[i] = new_tree_cache("class-identifier");
1117fc9106f9Syasuoka state->options[i]->flags = TC_TEMPORARY;
1118fc9106f9Syasuoka state->options[i]->value =
1119fc9106f9Syasuoka (unsigned char *)vendor_class->name;
11209e601734Skrw state->options[i]->len = strlen(vendor_class->name);
11219e601734Skrw state->options[i]->buf_size = state->options[i]->len;
1122fc9106f9Syasuoka state->options[i]->timeout = -1;
1123fc9106f9Syasuoka state->options[i]->tree = NULL;
1124fc9106f9Syasuoka }
1125fc9106f9Syasuoka
1126fc9106f9Syasuoka /* If we used the user class the client specified, we
1127fc9106f9Syasuoka have to return it. */
1128fc9106f9Syasuoka if (user_class) {
1129fc9106f9Syasuoka i = DHO_DHCP_USER_CLASS_ID;
1130fc9106f9Syasuoka state->options[i] = new_tree_cache("user-class");
1131fc9106f9Syasuoka state->options[i]->flags = TC_TEMPORARY;
1132fc9106f9Syasuoka state->options[i]->value =
1133fc9106f9Syasuoka (unsigned char *)user_class->name;
11349e601734Skrw state->options[i]->len = strlen(user_class->name);
11359e601734Skrw state->options[i]->buf_size = state->options[i]->len;
1136fc9106f9Syasuoka state->options[i]->timeout = -1;
1137fc9106f9Syasuoka state->options[i]->tree = NULL;
1138fc9106f9Syasuoka }
1139fc9106f9Syasuoka }
1140fc9106f9Syasuoka
1141fc9106f9Syasuoka /* for DHCPINFORM, don't include lease time parameters */
1142fc9106f9Syasuoka if (state->offer && (lease->flags & INFORM_NOLEASE) == 0) {
1143e853bc5dShenning
1144e853bc5dShenning /* Sanity check the lease time. */
1145e853bc5dShenning if ((state->offered_expiry - cur_time) < 15)
1146e853bc5dShenning offered_lease_time = default_lease_time;
1147e853bc5dShenning else if (state->offered_expiry - cur_time > max_lease_time)
1148e853bc5dShenning offered_lease_time = max_lease_time;
1149e853bc5dShenning else
1150e853bc5dShenning offered_lease_time =
1151e853bc5dShenning state->offered_expiry - cur_time;
1152e853bc5dShenning
11539e601734Skrw putULong((unsigned char *)&state->expiry, offered_lease_time);
1154e853bc5dShenning i = DHO_DHCP_LEASE_TIME;
1155e853bc5dShenning state->options[i] = new_tree_cache("lease-expiry");
1156e853bc5dShenning state->options[i]->flags = TC_TEMPORARY;
11578e1c2028Sderaadt state->options[i]->value = (unsigned char *)&state->expiry;
1158e853bc5dShenning state->options[i]->len = sizeof state->expiry;
1159e853bc5dShenning state->options[i]->buf_size = sizeof state->expiry;
11605dee4edfSotto state->options[i]->timeout = -1;
11618e1c2028Sderaadt state->options[i]->tree = NULL;
1162e853bc5dShenning
1163e853bc5dShenning /* Renewal time is lease time * 0.5. */
1164e853bc5dShenning offered_lease_time /= 2;
11659e601734Skrw putULong((unsigned char *)&state->renewal, offered_lease_time);
1166e853bc5dShenning i = DHO_DHCP_RENEWAL_TIME;
1167e853bc5dShenning state->options[i] = new_tree_cache("renewal-time");
1168e853bc5dShenning state->options[i]->flags = TC_TEMPORARY;
1169e853bc5dShenning state->options[i]->value =
1170e853bc5dShenning (unsigned char *)&state->renewal;
1171e853bc5dShenning state->options[i]->len = sizeof state->renewal;
1172e853bc5dShenning state->options[i]->buf_size = sizeof state->renewal;
11735dee4edfSotto state->options[i]->timeout = -1;
11748e1c2028Sderaadt state->options[i]->tree = NULL;
1175e853bc5dShenning
1176e853bc5dShenning
1177e853bc5dShenning /* Rebinding time is lease time * 0.875. */
11788e1c2028Sderaadt offered_lease_time += (offered_lease_time / 2 +
11798e1c2028Sderaadt offered_lease_time / 4);
11809e601734Skrw putULong((unsigned char *)&state->rebind, offered_lease_time);
1181e853bc5dShenning i = DHO_DHCP_REBINDING_TIME;
1182e853bc5dShenning state->options[i] = new_tree_cache("rebind-time");
1183e853bc5dShenning state->options[i]->flags = TC_TEMPORARY;
11849e601734Skrw state->options[i]->value = (unsigned char *)&state->rebind;
1185e853bc5dShenning state->options[i]->len = sizeof state->rebind;
1186e853bc5dShenning state->options[i]->buf_size = sizeof state->rebind;
11875dee4edfSotto state->options[i]->timeout = -1;
11888e1c2028Sderaadt state->options[i]->tree = NULL;
1189e853bc5dShenning }
1190e853bc5dShenning
1191e853bc5dShenning /* Use the subnet mask from the subnet declaration if no other
1192e853bc5dShenning mask has been provided. */
1193e853bc5dShenning i = DHO_SUBNET_MASK;
1194e853bc5dShenning if (!state->options[i]) {
1195e853bc5dShenning state->options[i] = new_tree_cache("subnet-mask");
1196e853bc5dShenning state->options[i]->flags = TC_TEMPORARY;
11979e601734Skrw state->options[i]->value = lease->subnet->netmask.iabuf;
1198e853bc5dShenning state->options[i]->len = lease->subnet->netmask.len;
11999e601734Skrw state->options[i]->buf_size = lease->subnet->netmask.len;
12005dee4edfSotto state->options[i]->timeout = -1;
12018e1c2028Sderaadt state->options[i]->tree = NULL;
1202e853bc5dShenning }
1203e853bc5dShenning
1204e853bc5dShenning /* If so directed, use the leased IP address as the router address.
1205e853bc5dShenning This supposedly makes Win95 machines ARP for all IP addresses,
1206e853bc5dShenning so if the local router does proxy arp, you win. */
1207e853bc5dShenning
1208e853bc5dShenning ulafdr = 0;
1209e853bc5dShenning if (lease->host) {
1210e853bc5dShenning if (lease->host->group->use_lease_addr_for_default_route)
1211e853bc5dShenning ulafdr = 1;
1212e853bc5dShenning } else if (user_class) {
1213e853bc5dShenning if (user_class->group->use_lease_addr_for_default_route)
1214e853bc5dShenning ulafdr = 1;
1215e853bc5dShenning } else if (vendor_class) {
1216e853bc5dShenning if (vendor_class->group->use_lease_addr_for_default_route)
1217e853bc5dShenning ulafdr = 1;
12188e1c2028Sderaadt } else if (lease->subnet->group->use_lease_addr_for_default_route)
1219e853bc5dShenning ulafdr = 1;
1220e853bc5dShenning else
1221e853bc5dShenning ulafdr = 0;
1222e853bc5dShenning
1223e853bc5dShenning i = DHO_ROUTERS;
1224e853bc5dShenning if (ulafdr && !state->options[i]) {
1225e853bc5dShenning state->options[i] = new_tree_cache("routers");
1226e853bc5dShenning state->options[i]->flags = TC_TEMPORARY;
12278e1c2028Sderaadt state->options[i]->value = lease->ip_addr.iabuf;
12288e1c2028Sderaadt state->options[i]->len = lease->ip_addr.len;
12298e1c2028Sderaadt state->options[i]->buf_size = lease->ip_addr.len;
12305dee4edfSotto state->options[i]->timeout = -1;
12318e1c2028Sderaadt state->options[i]->tree = NULL;
1232e853bc5dShenning }
1233e853bc5dShenning
1234a82310c0Skrw /*
1235a82310c0Skrw * RFC 3046: MUST NOT echo relay agent information if the server
1236a82310c0Skrw * does not understand/use the data. We don't.
1237a82310c0Skrw */
12385b44f46dSreyk i = DHO_RELAY_AGENT_INFORMATION;
1239a82310c0Skrw memset(&state->options[i], 0, sizeof(state->options[i]));
12405b44f46dSreyk
12412c9b957aSkrw /* Echo back the client-identifier as RFC 6842 mandates. */
1242a51e9872Skrw if (lease->host)
1243a51e9872Skrw echo_client_id = lease->host->group->echo_client_id;
1244a51e9872Skrw else if (user_class)
1245a51e9872Skrw echo_client_id = user_class->group->echo_client_id;
1246a51e9872Skrw else if (vendor_class)
1247a51e9872Skrw echo_client_id = vendor_class->group->echo_client_id;
1248a51e9872Skrw else
1249a51e9872Skrw echo_client_id = lease->subnet->group->echo_client_id;
12503fd9b174Skrw i = DHO_DHCP_CLIENT_IDENTIFIER;
1251a51e9872Skrw if (lease->client_identifier && echo_client_id) {
12522c9b957aSkrw state->options[i] = new_tree_cache("dhcp-client-identifier");
12532c9b957aSkrw state->options[i]->flags = TC_TEMPORARY;
12542c9b957aSkrw state->options[i]->value = lease->client_identifier;
12552c9b957aSkrw state->options[i]->len = lease->client_identifier_len;
12562c9b957aSkrw state->options[i]->buf_size = lease->client_identifier_len;
12572c9b957aSkrw state->options[i]->timeout = -1;
12582c9b957aSkrw state->options[i]->tree = NULL;
12592c9b957aSkrw } else
12603fd9b174Skrw memset(&state->options[i], 0, sizeof(state->options[i]));
12613fd9b174Skrw
1262e853bc5dShenning lease->state = state;
1263e853bc5dShenning
1264e853bc5dShenning /* If this is a DHCPOFFER, ping the lease address before actually
1265e853bc5dShenning sending the offer. */
1266e853bc5dShenning if (offer == DHCPOFFER && !(lease->flags & STATIC_LEASE) &&
1267e853bc5dShenning cur_time - lease->timestamp > 60) {
1268e853bc5dShenning lease->timestamp = cur_time;
1269e853bc5dShenning icmp_echorequest(&lease->ip_addr);
1270e853bc5dShenning add_timeout(cur_time + 1, lease_ping_timeout, lease);
1271e853bc5dShenning ++outstanding_pings;
1272e853bc5dShenning } else {
1273e853bc5dShenning lease->timestamp = cur_time;
1274e853bc5dShenning dhcp_reply(lease);
1275e853bc5dShenning }
1276e853bc5dShenning }
1277e853bc5dShenning
12788e1c2028Sderaadt void
dhcp_reply(struct lease * lease)12798e1c2028Sderaadt dhcp_reply(struct lease *lease)
1280e853bc5dShenning {
1281d7503dcfSkrw char ciaddrbuf[INET_ADDRSTRLEN];
12820795b389Sderaadt int bufs = 0, packet_length, i;
1283e853bc5dShenning struct dhcp_packet raw;
1284e853bc5dShenning struct sockaddr_in to;
1285e853bc5dShenning struct in_addr from;
1286e853bc5dShenning struct lease_state *state = lease->state;
1287e853bc5dShenning int nulltp, bootpp;
1288e853bc5dShenning u_int8_t *prl;
1289e853bc5dShenning int prl_len;
1290e853bc5dShenning
1291e853bc5dShenning if (!state)
1292c525a185Skrw fatalx("dhcp_reply was supplied lease with no state!");
1293e853bc5dShenning
1294e853bc5dShenning /* Compose a response for the client... */
1295e853bc5dShenning memset(&raw, 0, sizeof raw);
1296e853bc5dShenning
1297e853bc5dShenning /* Copy in the filename if given; otherwise, flag the filename
1298e853bc5dShenning buffer as available for options. */
1299e853bc5dShenning if (state->filename[0])
1300e853bc5dShenning strlcpy(raw.file, state->filename, sizeof raw.file);
1301e853bc5dShenning else
1302e853bc5dShenning bufs |= 1;
1303e853bc5dShenning
1304e853bc5dShenning /* Copy in the server name if given; otherwise, flag the
1305e853bc5dShenning server_name buffer as available for options. */
1306e853bc5dShenning if (state->server_name)
1307e853bc5dShenning strlcpy(raw.sname, state->server_name, sizeof raw.sname);
1308e853bc5dShenning else
1309e853bc5dShenning bufs |= 2; /* XXX */
1310e853bc5dShenning
1311e853bc5dShenning memcpy(raw.chaddr, lease->hardware_addr.haddr, sizeof raw.chaddr);
1312e853bc5dShenning raw.hlen = lease->hardware_addr.hlen;
1313e853bc5dShenning raw.htype = lease->hardware_addr.htype;
1314e853bc5dShenning
1315e853bc5dShenning /* See if this is a Microsoft client that NUL-terminates its
1316e853bc5dShenning strings and expects us to do likewise... */
1317e853bc5dShenning if (lease->flags & MS_NULL_TERMINATION)
1318e853bc5dShenning nulltp = 1;
1319e853bc5dShenning else
1320e853bc5dShenning nulltp = 0;
1321e853bc5dShenning
1322e853bc5dShenning /* See if this is a bootp client... */
1323e853bc5dShenning if (state->offer)
1324e853bc5dShenning bootpp = 0;
1325e853bc5dShenning else
1326e853bc5dShenning bootpp = 1;
1327e853bc5dShenning
1328e853bc5dShenning if (state->options[DHO_DHCP_PARAMETER_REQUEST_LIST] &&
1329e853bc5dShenning state->options[DHO_DHCP_PARAMETER_REQUEST_LIST]->value) {
13308e1c2028Sderaadt prl = state->options[DHO_DHCP_PARAMETER_REQUEST_LIST]->value;
13318e1c2028Sderaadt prl_len = state->options[DHO_DHCP_PARAMETER_REQUEST_LIST]->len;
1332e853bc5dShenning } else if (state->prl) {
1333e853bc5dShenning prl = state->prl;
1334e853bc5dShenning prl_len = state->prl_len;
1335e853bc5dShenning } else {
13368e1c2028Sderaadt prl = NULL;
1337e853bc5dShenning prl_len = 0;
1338e853bc5dShenning }
1339e853bc5dShenning
1340e853bc5dShenning /* Insert such options as will fit into the buffer. */
13418e1c2028Sderaadt packet_length = cons_options(NULL, &raw, state->max_message_size,
13428e1c2028Sderaadt state->options, bufs, nulltp, bootpp, prl, prl_len);
1343e853bc5dShenning
1344e853bc5dShenning /* Having done the cons_options(), we can release the tree_cache
1345e853bc5dShenning entries. */
1346e853bc5dShenning for (i = 0; i < 256; i++) {
1347e853bc5dShenning if (state->options[i] &&
1348e853bc5dShenning state->options[i]->flags & TC_TEMPORARY)
1349285f06efSderaadt free_tree_cache(state->options[i]);
1350e853bc5dShenning }
1351e853bc5dShenning
1352e853bc5dShenning memcpy(&raw.ciaddr, &state->ciaddr, sizeof raw.ciaddr);
1353fc9106f9Syasuoka if ((lease->flags & INFORM_NOLEASE) == 0)
1354e853bc5dShenning memcpy(&raw.yiaddr, lease->ip_addr.iabuf, 4);
1355e853bc5dShenning
1356e853bc5dShenning /* Figure out the address of the next server. */
1357e853bc5dShenning if (lease->host && lease->host->group->next_server.len)
13588e1c2028Sderaadt memcpy(&raw.siaddr, lease->host->group->next_server.iabuf, 4);
1359e853bc5dShenning else if (lease->subnet->group->next_server.len)
136035318e8fSkrw memcpy(&raw.siaddr, lease->subnet->group->next_server.iabuf,
136135318e8fSkrw 4);
1362e853bc5dShenning else if (lease->subnet->interface_address.len)
13638e1c2028Sderaadt memcpy(&raw.siaddr, lease->subnet->interface_address.iabuf, 4);
1364e853bc5dShenning else
1365e853bc5dShenning raw.siaddr = state->ip->primary_address;
1366e853bc5dShenning
1367e853bc5dShenning raw.giaddr = state->giaddr;
1368e853bc5dShenning
1369e853bc5dShenning raw.xid = state->xid;
1370e853bc5dShenning raw.secs = state->secs;
1371e853bc5dShenning raw.flags = state->bootp_flags;
1372e853bc5dShenning raw.hops = state->hops;
1373e853bc5dShenning raw.op = BOOTREPLY;
1374e853bc5dShenning
1375d7503dcfSkrw /* Can't do >1 inet_ntoa() in a printf()! */
1376d7503dcfSkrw strlcpy(ciaddrbuf, inet_ntoa(state->ciaddr), sizeof(ciaddrbuf));
1377d7503dcfSkrw
1378e853bc5dShenning /* Say what we're doing... */
1379c9109787Skrw if ((state->offer == DHCPACK) && (lease->flags & INFORM_NOLEASE))
1380c525a185Skrw log_info("DHCPACK to %s (%s) via %s",
1381d7503dcfSkrw ciaddrbuf,
1382c9109787Skrw print_hw_addr(lease->hardware_addr.htype,
1383c9109787Skrw lease->hardware_addr.hlen, lease->hardware_addr.haddr),
1384c9109787Skrw state->giaddr.s_addr ? inet_ntoa(state->giaddr) :
1385c9109787Skrw state->ip->name);
1386c9109787Skrw else
1387c525a185Skrw log_info("%s on %s to %s via %s",
1388c9109787Skrw (state->offer ? (state->offer == DHCPACK ? "DHCPACK" :
1389c9109787Skrw "DHCPOFFER") : "BOOTREPLY"),
1390e853bc5dShenning piaddr(lease->ip_addr),
1391c9109787Skrw print_hw_addr(lease->hardware_addr.htype,
1392c9109787Skrw lease->hardware_addr.hlen, lease->hardware_addr.haddr),
1393c9109787Skrw state->giaddr.s_addr ? inet_ntoa(state->giaddr) :
1394c9109787Skrw state->ip->name);
1395e853bc5dShenning
1396e853bc5dShenning memset(&to, 0, sizeof to);
1397e853bc5dShenning to.sin_family = AF_INET;
1398e853bc5dShenning #ifdef HAVE_SA_LEN
1399e853bc5dShenning to.sin_len = sizeof to;
1400e853bc5dShenning #endif
1401e853bc5dShenning
1402e853bc5dShenning /* Make sure outgoing packets are at least as big
1403e853bc5dShenning as a BOOTP packet. */
1404e853bc5dShenning if (packet_length < BOOTP_MIN_LEN)
1405e853bc5dShenning packet_length = BOOTP_MIN_LEN;
1406e853bc5dShenning
1407e853bc5dShenning /* If this was gatewayed, send it back to the gateway... */
1408e853bc5dShenning if (raw.giaddr.s_addr) {
1409e853bc5dShenning to.sin_addr = raw.giaddr;
1410390956b7Scanacar to.sin_port = server_port;
1411e853bc5dShenning
1412bbbabac3Sclaudio memcpy(&from, state->from.iabuf, sizeof from);
1413bbbabac3Sclaudio
141484d8c049Syasuoka (void) state->ip->send_packet(state->ip, &raw,
14156b08fb5bSclaudio packet_length, from, &to, &state->haddr);
1416e853bc5dShenning
1417cc3e8043Sclaudio free_lease_state(state, "dhcp_reply gateway");
14188e1c2028Sderaadt lease->state = NULL;
1419e853bc5dShenning return;
1420e853bc5dShenning
1421e853bc5dShenning /* If the client is RENEWING, unicast to the client using the
1422e853bc5dShenning regular IP stack. Some clients, particularly those that
1423e853bc5dShenning follow RFC1541, are buggy, and send both ciaddr and
1424e853bc5dShenning server-identifier. We deal with this situation by assuming
1425e853bc5dShenning that if we got both dhcp-server-identifier and ciaddr, and
1426e853bc5dShenning giaddr was not set, then the client is on the local
1427e853bc5dShenning network, and we can therefore unicast or broadcast to it
1428e853bc5dShenning successfully. A client in REQUESTING state on another
1429e853bc5dShenning network that's making this mistake will have set giaddr,
1430e853bc5dShenning and will therefore get a relayed response from the above
1431e853bc5dShenning code. */
1432e853bc5dShenning } else if (raw.ciaddr.s_addr &&
1433e853bc5dShenning !((state->got_server_identifier ||
1434e853bc5dShenning (raw.flags & htons(BOOTP_BROADCAST))) &&
1435e853bc5dShenning /* XXX This won't work if giaddr isn't zero, but it is: */
1436e853bc5dShenning (state->shared_network == lease->shared_network)) &&
1437e853bc5dShenning state->offer == DHCPACK) {
1438e853bc5dShenning to.sin_addr = raw.ciaddr;
1439390956b7Scanacar to.sin_port = client_port;
1440e853bc5dShenning
1441e853bc5dShenning /* If it comes from a client that already knows its address
1442e853bc5dShenning and is not requesting a broadcast response, and we can
1443e853bc5dShenning unicast to a client without using the ARP protocol, sent it
1444e853bc5dShenning directly to that client. */
1445e853bc5dShenning } else if (!(raw.flags & htons(BOOTP_BROADCAST))) {
1446e853bc5dShenning to.sin_addr = raw.yiaddr;
1447390956b7Scanacar to.sin_port = client_port;
1448e853bc5dShenning
1449e853bc5dShenning /* Otherwise, broadcast it on the local network. */
1450e853bc5dShenning } else {
1451e853bc5dShenning to.sin_addr.s_addr = htonl(INADDR_BROADCAST);
1452390956b7Scanacar to.sin_port = client_port;
1453e4a7785eSkrw memset(&state->haddr, 0xff, sizeof state->haddr);
1454e853bc5dShenning }
1455e853bc5dShenning
1456e853bc5dShenning memcpy(&from, state->from.iabuf, sizeof from);
1457e853bc5dShenning
145884d8c049Syasuoka (void) state->ip->send_packet(state->ip, &raw, packet_length,
1459cc55341fSclaudio from, &to, &state->haddr);
1460e853bc5dShenning
1461e853bc5dShenning free_lease_state(state, "dhcp_reply");
14628e1c2028Sderaadt lease->state = NULL;
1463e853bc5dShenning }
1464e853bc5dShenning
14658e1c2028Sderaadt struct lease *
find_lease(struct packet * packet,struct shared_network * share,int * ours)14668e1c2028Sderaadt find_lease(struct packet *packet, struct shared_network *share,
14678e1c2028Sderaadt int *ours)
1468e853bc5dShenning {
1469e853bc5dShenning struct lease *uid_lease, *ip_lease, *hw_lease;
1470ea507cabSderaadt struct lease *lease = NULL;
1471e853bc5dShenning struct iaddr cip;
14728e1c2028Sderaadt struct host_decl *hp, *host = NULL;
1473e853bc5dShenning struct lease *fixed_lease;
1474e853bc5dShenning
1475e853bc5dShenning /* Figure out what IP address the client is requesting, if any. */
147641b6b05bStobias if (packet->options[DHO_DHCP_REQUESTED_ADDRESS].len == 4) {
1477e853bc5dShenning packet->got_requested_address = 1;
1478e853bc5dShenning cip.len = 4;
1479e853bc5dShenning memcpy(cip.iabuf,
1480e853bc5dShenning packet->options[DHO_DHCP_REQUESTED_ADDRESS].data,
1481e853bc5dShenning cip.len);
1482e853bc5dShenning } else if (packet->raw->ciaddr.s_addr) {
1483e853bc5dShenning cip.len = 4;
1484e853bc5dShenning memcpy(cip.iabuf, &packet->raw->ciaddr, 4);
1485e853bc5dShenning } else
1486e853bc5dShenning cip.len = 0;
1487e853bc5dShenning
1488e853bc5dShenning /* Try to find a host or lease that's been assigned to the
1489e853bc5dShenning specified unique client identifier. */
1490e853bc5dShenning if (packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len) {
1491e853bc5dShenning /* First, try to find a fixed host entry for the specified
1492e853bc5dShenning client identifier... */
14938e1c2028Sderaadt hp = find_hosts_by_uid(
14948e1c2028Sderaadt packet->options[DHO_DHCP_CLIENT_IDENTIFIER].data,
14958e1c2028Sderaadt packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len);
1496e853bc5dShenning if (hp) {
1497e853bc5dShenning host = hp;
1498e853bc5dShenning fixed_lease = mockup_lease(packet, share, hp);
1499ea507cabSderaadt uid_lease = NULL;
1500e853bc5dShenning } else {
15018e1c2028Sderaadt uid_lease = find_lease_by_uid(
15028e1c2028Sderaadt packet->options[DHO_DHCP_CLIENT_IDENTIFIER].data,
15038e1c2028Sderaadt packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len);
1504e853bc5dShenning /* Find the lease matching this uid that's on the
1505e853bc5dShenning network the packet came from (if any). */
1506e853bc5dShenning for (; uid_lease; uid_lease = uid_lease->n_uid)
1507e853bc5dShenning if (uid_lease->shared_network == share)
1508e853bc5dShenning break;
1509ea507cabSderaadt fixed_lease = NULL;
15108e1c2028Sderaadt if (uid_lease && (uid_lease->flags & ABANDONED_LEASE))
1511ea507cabSderaadt uid_lease = NULL;
1512e853bc5dShenning }
1513e853bc5dShenning } else {
1514ea507cabSderaadt uid_lease = NULL;
1515ea507cabSderaadt fixed_lease = NULL;
1516e853bc5dShenning }
1517e853bc5dShenning
1518e853bc5dShenning /* If we didn't find a fixed lease using the uid, try doing
1519e853bc5dShenning it with the hardware address... */
1520e853bc5dShenning if (!fixed_lease) {
1521e853bc5dShenning hp = find_hosts_by_haddr(packet->raw->htype,
15228e1c2028Sderaadt packet->raw->chaddr, packet->raw->hlen);
1523e853bc5dShenning if (hp) {
1524e853bc5dShenning host = hp; /* Save it for later. */
1525e853bc5dShenning fixed_lease = mockup_lease(packet, share, hp);
1526e853bc5dShenning }
1527e853bc5dShenning }
1528e853bc5dShenning
1529e853bc5dShenning /* If fixed_lease is present but does not match the requested
1530e853bc5dShenning IP address, and this is a DHCPREQUEST, then we can't return
1531e853bc5dShenning any other lease, so we might as well return now. */
1532e853bc5dShenning if (packet->packet_type == DHCPREQUEST && fixed_lease &&
1533e853bc5dShenning (fixed_lease->ip_addr.len != cip.len ||
15348e1c2028Sderaadt memcmp(fixed_lease->ip_addr.iabuf, cip.iabuf, cip.len))) {
1535e853bc5dShenning if (ours)
1536e853bc5dShenning *ours = 1;
1537e853bc5dShenning strlcpy(dhcp_message, "requested address is incorrect",
1538e853bc5dShenning sizeof(dhcp_message));
1539ea507cabSderaadt return NULL;
1540e853bc5dShenning }
1541e853bc5dShenning
1542e853bc5dShenning /* Try to find a lease that's been attached to the client's
1543e853bc5dShenning hardware address... */
1544e853bc5dShenning hw_lease = find_lease_by_hw_addr(packet->raw->chaddr,
1545e853bc5dShenning packet->raw->hlen);
1546e853bc5dShenning /* Find the lease that's on the network the packet came from
1547e853bc5dShenning (if any). */
1548e853bc5dShenning for (; hw_lease; hw_lease = hw_lease->n_hw) {
1549e853bc5dShenning if (hw_lease->shared_network == share) {
1550e853bc5dShenning if ((hw_lease->flags & ABANDONED_LEASE))
1551e853bc5dShenning continue;
1552e853bc5dShenning if (packet->packet_type)
1553e853bc5dShenning break;
1554e853bc5dShenning if (hw_lease->flags &
1555e853bc5dShenning (BOOTP_LEASE | DYNAMIC_BOOTP_OK))
1556e853bc5dShenning break;
1557e853bc5dShenning }
1558e853bc5dShenning }
1559e853bc5dShenning
1560e853bc5dShenning /* Try to find a lease that's been allocated to the client's
1561e853bc5dShenning IP address. */
1562e853bc5dShenning if (cip.len)
1563e853bc5dShenning ip_lease = find_lease_by_ip_addr(cip);
1564e853bc5dShenning else
1565ea507cabSderaadt ip_lease = NULL;
1566e853bc5dShenning
1567e853bc5dShenning /* If ip_lease is valid at this point, set ours to one, so that
1568e853bc5dShenning even if we choose a different lease, we know that the address
1569e853bc5dShenning the client was requesting was ours, and thus we can NAK it. */
1570e853bc5dShenning if (ip_lease && ours)
1571e853bc5dShenning *ours = 1;
1572e853bc5dShenning
1573e853bc5dShenning /* If the requested IP address isn't on the network the packet
1574e853bc5dShenning came from, don't use it. Allow abandoned leases to be matched
1575e853bc5dShenning here - if the client is requesting it, there's a decent chance
1576e853bc5dShenning that it's because the lease database got trashed and a client
1577e853bc5dShenning that thought it had this lease answered an ARP or PING, causing the
1578e853bc5dShenning lease to be abandoned. If so, this request probably came from
1579e853bc5dShenning that client. */
1580e853bc5dShenning if (ip_lease && (ip_lease->shared_network != share)) {
1581ea507cabSderaadt ip_lease = NULL;
1582e853bc5dShenning strlcpy(dhcp_message, "requested address on bad subnet",
1583e853bc5dShenning sizeof(dhcp_message));
1584e853bc5dShenning }
1585e853bc5dShenning
1586e853bc5dShenning /* Toss ip_lease if it hasn't yet expired and isn't owned by the
1587e853bc5dShenning client. */
15888e1c2028Sderaadt if (ip_lease && ip_lease->ends >= cur_time && ip_lease != uid_lease) {
1589e853bc5dShenning int i = DHO_DHCP_CLIENT_IDENTIFIER;
15908e1c2028Sderaadt
1591e853bc5dShenning /* Make sure that ip_lease actually belongs to the client,
1592e853bc5dShenning and toss it if not. */
15938e1c2028Sderaadt if ((ip_lease->uid_len && packet->options[i].data &&
1594e853bc5dShenning ip_lease->uid_len == packet->options[i].len &&
15958e1c2028Sderaadt !memcmp(packet->options[i].data, ip_lease->uid,
15968e1c2028Sderaadt ip_lease->uid_len)) ||
1597e853bc5dShenning (!ip_lease->uid_len &&
15988e1c2028Sderaadt ip_lease->hardware_addr.htype == packet->raw->htype &&
1599e853bc5dShenning ip_lease->hardware_addr.hlen == packet->raw->hlen &&
16008e1c2028Sderaadt !memcmp(ip_lease->hardware_addr.haddr, packet->raw->chaddr,
1601e853bc5dShenning ip_lease->hardware_addr.hlen))) {
1602e853bc5dShenning if (uid_lease) {
1603e853bc5dShenning if (uid_lease->ends > cur_time) {
160435318e8fSkrw log_warnx("client %s has duplicate "
160535318e8fSkrw "leases on %s",
1606e853bc5dShenning print_hw_addr(packet->raw->htype,
160735318e8fSkrw packet->raw->hlen,
160835318e8fSkrw packet->raw->chaddr),
1609e853bc5dShenning ip_lease->shared_network->name);
1610e853bc5dShenning
161135318e8fSkrw if (uid_lease &&
161235318e8fSkrw !packet->raw->ciaddr.s_addr)
1613e853bc5dShenning release_lease(uid_lease);
1614e853bc5dShenning }
1615e853bc5dShenning uid_lease = ip_lease;
1616e853bc5dShenning }
1617e853bc5dShenning } else {
161835318e8fSkrw strlcpy(dhcp_message, "requested address is not "
161935318e8fSkrw "available", sizeof(dhcp_message));
1620ea507cabSderaadt ip_lease = NULL;
1621e853bc5dShenning }
1622e853bc5dShenning
1623e853bc5dShenning /* If we get to here and fixed_lease is not null, that means
1624e853bc5dShenning that there are both a dynamic lease and a fixed-address
1625e853bc5dShenning declaration for the same IP address. */
1626e853bc5dShenning if (packet->packet_type == DHCPREQUEST && fixed_lease) {
1627ea507cabSderaadt fixed_lease = NULL;
1628e853bc5dShenning db_conflict:
162935318e8fSkrw log_warnx("Both dynamic and static leases present for "
163035318e8fSkrw "%s.", piaddr(cip));
163135318e8fSkrw log_warnx("Either remove host declaration %s or "
163235318e8fSkrw "remove %s", (fixed_lease && fixed_lease->host ?
163335318e8fSkrw (fixed_lease->host->name ?
163435318e8fSkrw fixed_lease->host->name : piaddr(cip)) :
163535318e8fSkrw piaddr(cip)), piaddr(cip));
1636c525a185Skrw log_warnx("from the dynamic address pool for %s",
1637e853bc5dShenning share->name);
1638e853bc5dShenning if (fixed_lease)
1639ea507cabSderaadt ip_lease = NULL;
164035318e8fSkrw strlcpy(dhcp_message, "database conflict - call for "
164135318e8fSkrw "help!", sizeof(dhcp_message));
1642e853bc5dShenning }
1643e853bc5dShenning }
1644e853bc5dShenning
1645e853bc5dShenning /* If we get to here with both fixed_lease and ip_lease not
1646e853bc5dShenning null, then we have a configuration file bug. */
1647e853bc5dShenning if (packet->packet_type == DHCPREQUEST && fixed_lease && ip_lease)
1648e853bc5dShenning goto db_conflict;
1649e853bc5dShenning
1650e853bc5dShenning /* Toss hw_lease if it hasn't yet expired and the uid doesn't
1651e853bc5dShenning match, except that if the hardware address matches and the
1652e853bc5dShenning client is now doing dynamic BOOTP (and thus hasn't provided
1653e853bc5dShenning a uid) we let the client get away with it. */
16548e1c2028Sderaadt if (hw_lease && hw_lease->ends >= cur_time && hw_lease->uid &&
1655e853bc5dShenning packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len &&
1656e853bc5dShenning hw_lease != uid_lease)
1657ea507cabSderaadt hw_lease = NULL;
1658e853bc5dShenning
1659e853bc5dShenning /* Toss extra pointers to the same lease... */
1660e853bc5dShenning if (hw_lease == uid_lease)
1661ea507cabSderaadt hw_lease = NULL;
1662e853bc5dShenning if (ip_lease == hw_lease)
1663ea507cabSderaadt hw_lease = NULL;
1664e853bc5dShenning if (ip_lease == uid_lease)
1665ea507cabSderaadt uid_lease = NULL;
1666e853bc5dShenning
1667e853bc5dShenning /* If we've already eliminated the lease, it wasn't there to
1668e853bc5dShenning begin with. If we have come up with a matching lease,
1669e853bc5dShenning set the message to bad network in case we have to throw it out. */
1670e853bc5dShenning if (!ip_lease) {
1671e853bc5dShenning strlcpy(dhcp_message, "requested address not available",
1672e853bc5dShenning sizeof(dhcp_message));
1673e853bc5dShenning }
1674e853bc5dShenning
1675e853bc5dShenning /* Now eliminate leases that are on the wrong network... */
16768e1c2028Sderaadt if (ip_lease && share != ip_lease->shared_network) {
1677e853bc5dShenning if (packet->packet_type == DHCPREQUEST)
1678e853bc5dShenning release_lease(ip_lease);
1679ea507cabSderaadt ip_lease = NULL;
1680e853bc5dShenning }
16818e1c2028Sderaadt if (uid_lease && share != uid_lease->shared_network) {
1682e853bc5dShenning if (packet->packet_type == DHCPREQUEST)
1683e853bc5dShenning release_lease(uid_lease);
1684ea507cabSderaadt uid_lease = NULL;
1685e853bc5dShenning }
16868e1c2028Sderaadt if (hw_lease && share != hw_lease->shared_network) {
1687e853bc5dShenning if (packet->packet_type == DHCPREQUEST)
1688e853bc5dShenning release_lease(hw_lease);
1689ea507cabSderaadt hw_lease = NULL;
1690e853bc5dShenning }
1691e853bc5dShenning
1692e853bc5dShenning /* If this is a DHCPREQUEST, make sure the lease we're going to return
1693e853bc5dShenning matches the requested IP address. If it doesn't, don't return a
1694e853bc5dShenning lease at all. */
1695e853bc5dShenning if (packet->packet_type == DHCPREQUEST && !ip_lease && !fixed_lease)
1696ea507cabSderaadt return NULL;
1697e853bc5dShenning
1698e853bc5dShenning /* At this point, if fixed_lease is nonzero, we can assign it to
1699e853bc5dShenning this client. */
17008e1c2028Sderaadt if (fixed_lease)
1701e853bc5dShenning lease = fixed_lease;
1702e853bc5dShenning
1703e853bc5dShenning /* If we got a lease that matched the ip address and don't have
1704e853bc5dShenning a better offer, use that; otherwise, release it. */
1705e853bc5dShenning if (ip_lease) {
1706e853bc5dShenning if (lease) {
1707e853bc5dShenning if (packet->packet_type == DHCPREQUEST)
1708e853bc5dShenning release_lease(ip_lease);
1709e853bc5dShenning } else {
1710e853bc5dShenning lease = ip_lease;
17118e1c2028Sderaadt lease->host = NULL;
1712e853bc5dShenning }
1713e853bc5dShenning }
1714e853bc5dShenning
1715e853bc5dShenning /* If we got a lease that matched the client identifier, we may want
1716e853bc5dShenning to use it, but if we already have a lease we like, we must free
1717e853bc5dShenning the lease that matched the client identifier. */
1718e853bc5dShenning if (uid_lease) {
1719e853bc5dShenning if (lease) {
1720e853bc5dShenning if (packet->packet_type == DHCPREQUEST)
1721e853bc5dShenning release_lease(uid_lease);
1722e853bc5dShenning } else {
1723e853bc5dShenning lease = uid_lease;
17248e1c2028Sderaadt lease->host = NULL;
1725e853bc5dShenning }
1726e853bc5dShenning }
1727e853bc5dShenning
1728e853bc5dShenning /* The lease that matched the hardware address is treated likewise. */
1729e853bc5dShenning if (hw_lease) {
1730e853bc5dShenning if (lease) {
1731e853bc5dShenning if (packet->packet_type == DHCPREQUEST)
1732e853bc5dShenning release_lease(hw_lease);
1733e853bc5dShenning } else {
1734e853bc5dShenning lease = hw_lease;
17358e1c2028Sderaadt lease->host = NULL;
1736e853bc5dShenning }
1737e853bc5dShenning }
1738e853bc5dShenning
1739e853bc5dShenning /* If we found a host_decl but no matching address, try to
1740e853bc5dShenning find a host_decl that has no address, and if there is one,
1741e853bc5dShenning hang it off the lease so that we can use the supplied
1742e853bc5dShenning options. */
1743e853bc5dShenning if (lease && host && !lease->host) {
1744e853bc5dShenning for (; host; host = host->n_ipaddr) {
1745e853bc5dShenning if (!host->fixed_addr) {
1746e853bc5dShenning lease->host = host;
1747e853bc5dShenning break;
1748e853bc5dShenning }
1749e853bc5dShenning }
1750e853bc5dShenning }
1751e853bc5dShenning
1752e853bc5dShenning /* If we find an abandoned lease, take it, but print a
1753e853bc5dShenning warning message, so that if it continues to lose,
1754e853bc5dShenning the administrator will eventually investigate. */
1755e853bc5dShenning if (lease && (lease->flags & ABANDONED_LEASE)) {
1756e853bc5dShenning if (packet->packet_type == DHCPREQUEST) {
175735318e8fSkrw log_warnx("Reclaiming REQUESTed abandoned IP address "
175835318e8fSkrw "%s.", piaddr(lease->ip_addr));
1759e853bc5dShenning lease->flags &= ~ABANDONED_LEASE;
1760e853bc5dShenning } else
1761ea507cabSderaadt lease = NULL;
1762e853bc5dShenning }
1763e853bc5dShenning return lease;
1764e853bc5dShenning }
1765e853bc5dShenning
1766ea507cabSderaadt /*
1767ea507cabSderaadt * Search the provided host_decl structure list for an address that's on
1768ea507cabSderaadt * the specified shared network. If one is found, mock up and return a
1769ea507cabSderaadt * lease structure for it; otherwise return the null pointer.
1770ea507cabSderaadt */
1771ea507cabSderaadt struct lease *
mockup_lease(struct packet * packet,struct shared_network * share,struct host_decl * hp)1772ea507cabSderaadt mockup_lease(struct packet *packet, struct shared_network *share,
1773ea507cabSderaadt struct host_decl *hp)
1774e853bc5dShenning {
1775e853bc5dShenning static struct lease mock;
1776e853bc5dShenning
1777e853bc5dShenning mock.subnet = find_host_for_network(&hp, &mock.ip_addr, share);
1778e853bc5dShenning if (!mock.subnet)
1779ea507cabSderaadt return (NULL);
1780ea507cabSderaadt mock.next = mock.prev = NULL;
1781e853bc5dShenning mock.shared_network = mock.subnet->shared_network;
1782e853bc5dShenning mock.host = hp;
1783e853bc5dShenning
1784e853bc5dShenning if (hp->group->options[DHO_DHCP_CLIENT_IDENTIFIER]) {
178535318e8fSkrw mock.uid =
178635318e8fSkrw hp->group->options[DHO_DHCP_CLIENT_IDENTIFIER]->value;
178735318e8fSkrw mock.uid_len =
178835318e8fSkrw hp->group->options[DHO_DHCP_CLIENT_IDENTIFIER]->len;
1789e853bc5dShenning } else {
1790ea507cabSderaadt mock.uid = NULL;
1791e853bc5dShenning mock.uid_len = 0;
1792e853bc5dShenning }
1793e853bc5dShenning
1794e853bc5dShenning mock.hardware_addr = hp->interface;
1795e853bc5dShenning mock.starts = mock.timestamp = mock.ends = MIN_TIME;
1796e853bc5dShenning mock.flags = STATIC_LEASE;
1797e853bc5dShenning return &mock;
1798e853bc5dShenning }
1799