GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/dhcpd/bootp.c Lines: 0 153 0.0 %
Date: 2017-11-07 Branches: 0 102 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: bootp.c,v 1.18 2017/02/13 22:33:39 krw Exp $	*/
2
3
/*
4
 * BOOTP Protocol support.
5
 */
6
7
/*
8
 * Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium.
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 *
15
 * 1. Redistributions of source code must retain the above copyright
16
 *    notice, this list of conditions and the following disclaimer.
17
 * 2. Redistributions in binary form must reproduce the above copyright
18
 *    notice, this list of conditions and the following disclaimer in the
19
 *    documentation and/or other materials provided with the distribution.
20
 * 3. Neither the name of The Internet Software Consortium nor the names
21
 *    of its contributors may be used to endorse or promote products derived
22
 *    from this software without specific prior written permission.
23
 *
24
 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
25
 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
26
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28
 * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
29
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
32
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
33
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
34
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
35
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36
 * SUCH DAMAGE.
37
 *
38
 * This software has been written for the Internet Software Consortium
39
 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
40
 * Enterprises.  To learn more about the Internet Software Consortium,
41
 * see ``http://www.vix.com/isc''.  To learn more about Vixie
42
 * Enterprises, see ``http://www.vix.com''.
43
 */
44
45
#include <sys/socket.h>
46
47
#include <arpa/inet.h>
48
49
#include <net/if.h>
50
51
#include <netinet/in.h>
52
53
#include <errno.h>
54
#include <stdio.h>
55
#include <string.h>
56
57
#include "dhcp.h"
58
#include "tree.h"
59
#include "dhcpd.h"
60
#include "log.h"
61
62
void
63
bootp(struct packet *packet)
64
{
65
	struct host_decl *hp, *host = NULL;
66
	struct packet outgoing;
67
	struct dhcp_packet raw;
68
	struct sockaddr_in to;
69
	struct in_addr from;
70
	struct tree_cache *options[256];
71
	struct shared_network *s;
72
	struct subnet *subnet = NULL;
73
	struct lease *lease;
74
	struct iaddr ip_address;
75
	int i;
76
77
	if (packet->raw->op != BOOTREQUEST)
78
		return;
79
80
	log_info("BOOTREQUEST from %s via %s%s",
81
	    print_hw_addr(packet->raw->htype, packet->raw->hlen,
82
	    packet->raw->chaddr), packet->raw->giaddr.s_addr ?
83
	    inet_ntoa(packet->raw->giaddr) : packet->interface->name,
84
	    packet->options_valid ? "" : " (non-rfc1048)");
85
86
	if (!locate_network(packet))
87
		return;
88
89
	hp = find_hosts_by_haddr(packet->raw->htype, packet->raw->chaddr,
90
	    packet->raw->hlen);
91
92
	s = packet->shared_network;
93
	lease = find_lease(packet, s, 0);
94
95
	/*
96
	 * Find an IP address in the host_decl that matches the specified
97
	 * network.
98
	 */
99
	if (hp)
100
		subnet = find_host_for_network(&hp, &ip_address, s);
101
102
	if (!subnet) {
103
		/*
104
		 * We didn't find an applicable host declaration. Just in case
105
		 * we may be able to dynamically assign an address, see if
106
		 * there's a host declaration that doesn't have an ip address
107
		 * associated with it.
108
		 */
109
		if (hp)
110
			for (; hp; hp = hp->n_ipaddr)
111
				if (!hp->fixed_addr) {
112
					host = hp;
113
					break;
114
				}
115
116
		if (host && (!host->group->allow_booting)) {
117
			log_info("Ignoring excluded BOOTP client %s",
118
			    host->name ?  host->name :
119
			    print_hw_addr (packet->raw->htype,
120
			    packet->raw->hlen, packet->raw->chaddr));
121
			return;
122
		}
123
124
		if (host && (!host->group->allow_bootp)) {
125
			log_info("Ignoring BOOTP request from client %s",
126
			    host->name ? host->name :
127
			    print_hw_addr(packet->raw->htype,
128
			    packet->raw->hlen, packet->raw->chaddr));
129
			return;
130
		}
131
132
		/*
133
		 * If we've been told not to boot unknown clients, and we
134
		 * didn't find any host record for this client, ignore it.
135
		 */
136
		if (!host && !(s->group->boot_unknown_clients)) {
137
			log_info("Ignoring unknown BOOTP client %s via %s",
138
			    print_hw_addr(packet->raw->htype,
139
			    packet->raw->hlen, packet->raw->chaddr),
140
			    packet->raw->giaddr.s_addr ?
141
			    inet_ntoa(packet->raw->giaddr) :
142
			    packet->interface->name);
143
			return;
144
		}
145
146
		/*
147
		 * If we've been told not to boot with bootp on this network,
148
		 * ignore it.
149
		 */
150
		if (!host && !(s->group->allow_bootp)) {
151
			log_info("Ignoring BOOTP request from client %s via "
152
			    "%s", print_hw_addr(packet->raw->htype,
153
			    packet->raw->hlen, packet->raw->chaddr),
154
			    packet->raw->giaddr.s_addr ?
155
			    inet_ntoa(packet->raw->giaddr) :
156
			    packet->interface->name);
157
			return;
158
		}
159
160
		/*
161
		 * If the packet is from a host we don't know and there are no
162
		 * dynamic bootp addresses on the network it came in on, drop
163
		 * it on the floor.
164
		 */
165
		if (!(s->group->dynamic_bootp)) {
166
lose:
167
			log_info("No applicable record for BOOTP host %s via "
168
			    "%s", print_hw_addr(packet->raw->htype,
169
			    packet->raw->hlen, packet->raw->chaddr),
170
			    packet->raw->giaddr.s_addr ?
171
			    inet_ntoa(packet->raw->giaddr) :
172
			    packet->interface->name);
173
			return;
174
		}
175
176
		/*
177
		 * If a lease has already been assigned to this client and it's
178
		 * still okay to use dynamic bootp on that lease, reassign it.
179
		 */
180
		if (lease) {
181
			/*
182
			 * If this lease can be used for dynamic bootp, do so.
183
			 */
184
			if ((lease->flags & DYNAMIC_BOOTP_OK)) {
185
				/*
186
				 * If it's not a DYNAMIC_BOOTP lease, release
187
				 * it before reassigning it so that we don't
188
				 * get a lease conflict.
189
				 */
190
				if (!(lease->flags & BOOTP_LEASE))
191
					release_lease(lease);
192
193
				lease->host = host;
194
				ack_lease(packet, lease, 0, 0);
195
				return;
196
			}
197
198
			 /*
199
			  * If dynamic BOOTP is no longer allowed for this
200
			  * lease, set it free.
201
			  */
202
			release_lease(lease);
203
		}
204
205
		/*
206
		 * If there are dynamic bootp addresses that might be
207
		 * available, try to snag one.
208
		 */
209
		for (lease = s->last_lease;
210
		    lease && lease->ends <= cur_time;
211
		    lease = lease->prev) {
212
			if ((lease->flags & DYNAMIC_BOOTP_OK)) {
213
				lease->host = host;
214
				ack_lease(packet, lease, 0, 0);
215
				return;
216
			}
217
		}
218
		goto lose;
219
	}
220
221
	/* Make sure we're allowed to boot this client. */
222
	if (hp && (!hp->group->allow_booting)) {
223
		log_info("Ignoring excluded BOOTP client %s", hp->name);
224
		return;
225
	}
226
227
	/* Make sure we're allowed to boot this client with bootp. */
228
	if (hp && (!hp->group->allow_bootp)) {
229
		log_info("Ignoring BOOTP request from client %s", hp->name);
230
		return;
231
	}
232
233
	/* Set up the outgoing packet... */
234
	memset(&outgoing, 0, sizeof outgoing);
235
	memset(&raw, 0, sizeof raw);
236
	outgoing.raw = &raw;
237
238
	/*
239
	 * If we didn't get a known vendor magic number on the way in, just
240
	 * copy the input options to the output.
241
	 */
242
	if (!packet->options_valid && !subnet->group->always_reply_rfc1048 &&
243
	    (!hp || !hp->group->always_reply_rfc1048)) {
244
		memcpy(outgoing.raw->options, packet->raw->options,
245
		    DHCP_OPTION_LEN);
246
		outgoing.packet_length = BOOTP_MIN_LEN;
247
	} else {
248
		struct tree_cache netmask_tree;   /*  -- RBF */
249
250
		/*
251
		 * Come up with a list of options that we want to send to this
252
		 * client. Start with the per-subnet options, and then override
253
		 * those with client-specific options.
254
		 */
255
256
		memcpy(options, subnet->group->options, sizeof(options));
257
258
		for (i = 0; i < 256; i++)
259
			if (hp->group->options[i])
260
				options[i] = hp->group->options[i];
261
262
		/*
263
		 * Use the subnet mask from the subnet declaration if no other
264
		 * mask has been provided.
265
		 */
266
		if (!options[DHO_SUBNET_MASK]) {
267
			options[DHO_SUBNET_MASK] = &netmask_tree;
268
			netmask_tree.flags = TC_TEMPORARY;
269
			netmask_tree.value = lease->subnet->netmask.iabuf;
270
			netmask_tree.len = lease->subnet->netmask.len;
271
			netmask_tree.buf_size = lease->subnet->netmask.len;
272
			netmask_tree.timeout = -1;
273
			netmask_tree.tree = NULL;
274
		}
275
276
		/*
277
		 * Pack the options into the buffer. Unlike DHCP, we can't pack
278
		 * options into the filename and server name buffers.
279
		 */
280
281
		outgoing.packet_length = cons_options(packet, outgoing.raw,
282
		    0, options, 0, 0, 1, NULL, 0);
283
284
		if (outgoing.packet_length < BOOTP_MIN_LEN)
285
			outgoing.packet_length = BOOTP_MIN_LEN;
286
	}
287
288
	/* Take the fields that we care about... */
289
	raw.op = BOOTREPLY;
290
	raw.htype = packet->raw->htype;
291
	raw.hlen = packet->raw->hlen;
292
	memcpy(raw.chaddr, packet->raw->chaddr, sizeof(raw.chaddr));
293
	raw.hops = packet->raw->hops;
294
	raw.xid = packet->raw->xid;
295
	raw.secs = packet->raw->secs;
296
	raw.flags = packet->raw->flags;
297
	raw.ciaddr = packet->raw->ciaddr;
298
	memcpy(&raw.yiaddr, ip_address.iabuf, sizeof(raw.yiaddr));
299
300
	/* Figure out the address of the next server. */
301
	if (hp && hp->group->next_server.len)
302
		memcpy(&raw.siaddr, hp->group->next_server.iabuf, 4);
303
	else if (subnet->group->next_server.len)
304
		memcpy(&raw.siaddr, subnet->group->next_server.iabuf, 4);
305
	else if (subnet->interface_address.len)
306
		memcpy(&raw.siaddr, subnet->interface_address.iabuf, 4);
307
	else
308
		raw.siaddr = packet->interface->primary_address;
309
310
	raw.giaddr = packet->raw->giaddr;
311
	if (hp->group->server_name)
312
		strncpy(raw.sname, hp->group->server_name, sizeof(raw.sname));
313
	else if (subnet->group->server_name)
314
		strncpy(raw.sname, subnet->group->server_name,
315
		    sizeof(raw.sname));
316
317
	if (hp->group->filename)
318
		strncpy(raw.file, hp->group->filename, sizeof(raw.file));
319
	else if (subnet->group->filename)
320
		strncpy(raw.file, subnet->group->filename, sizeof(raw.file));
321
	else
322
		memcpy(raw.file, packet->raw->file, sizeof(raw.file));
323
324
	from = packet->interface->primary_address;
325
326
	/* Report what we're doing... */
327
	log_info("BOOTREPLY for %s to %s (%s) via %s", piaddr(ip_address),
328
	    hp->name, print_hw_addr(packet->raw->htype, packet->raw->hlen,
329
	    packet->raw->chaddr), packet->raw->giaddr.s_addr ?
330
	    inet_ntoa(packet->raw->giaddr) : packet->interface->name);
331
332
	/* Set up the parts of the address that are in common. */
333
	memset(&to, 0, sizeof(to));
334
	to.sin_family = AF_INET;
335
#ifdef HAVE_SA_LEN
336
	to.sin_len = sizeof(to);
337
#endif
338
339
	/* If this was gatewayed, send it back to the gateway... */
340
	if (raw.giaddr.s_addr) {
341
		to.sin_addr = raw.giaddr;
342
		to.sin_port = server_port;
343
344
		(void) packet->interface->send_packet(packet->interface, &raw,
345
		    outgoing.packet_length, from, &to, packet->haddr);
346
		return;
347
	}
348
349
	/*
350
	 * If it comes from a client that already knows its address and is not
351
	 * requesting a broadcast response, and we can unicast to a client
352
	 * without using the ARP protocol, sent it directly to that client.
353
	 */
354
	else if (!(raw.flags & htons(BOOTP_BROADCAST))) {
355
		to.sin_addr = raw.yiaddr;
356
		to.sin_port = client_port;
357
	} else {
358
		/* Otherwise, broadcast it on the local network. */
359
		to.sin_addr.s_addr = INADDR_BROADCAST;
360
		to.sin_port = client_port; /* XXX */
361
	}
362
363
	errno = 0;
364
	(void) packet->interface->send_packet(packet->interface, &raw,
365
	    outgoing.packet_length, from, &to, packet->haddr);
366
}