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

Line Branch Exec Source
1
/*	$OpenBSD: bpf.c,v 1.19 2017/04/19 05:36:12 natano Exp $	*/
2
3
/* BPF socket interface code, originally contributed by Archie Cobbs. */
4
5
/*
6
 * Copyright (c) 1995, 1996, 1998, 1999
7
 * The Internet Software Consortium.    All rights reserved.
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 *
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. Neither the name of The Internet Software Consortium nor the names
19
 *    of its contributors may be used to endorse or promote products derived
20
 *    from this software without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23
 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
 * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34
 * SUCH DAMAGE.
35
 *
36
 * This software has been written for the Internet Software Consortium
37
 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38
 * Enterprises.  To learn more about the Internet Software Consortium,
39
 * see ``http://www.vix.com/isc''.  To learn more about Vixie
40
 * Enterprises, see ``http://www.vix.com''.
41
 */
42
43
#include <sys/ioctl.h>
44
#include <sys/types.h>
45
#include <sys/socket.h>
46
47
#include <arpa/inet.h>
48
49
#include <net/bpf.h>
50
#include <net/if.h>
51
52
#include <netinet/if_ether.h>
53
#include <netinet/in.h>
54
55
#include <errno.h>
56
#include <fcntl.h>
57
#include <stdio.h>
58
#include <stdlib.h>
59
#include <string.h>
60
#include <unistd.h>
61
62
#include "dhcp.h"
63
#include "tree.h"
64
#include "dhcpd.h"
65
#include "log.h"
66
67
ssize_t send_packet	 (struct interface_info *, struct dhcp_packet *,
68
    size_t, struct in_addr, struct sockaddr_in *, struct hardware *);
69
70
/*
71
 * Called by get_interface_list for each interface that's discovered.
72
 * Opens a packet filter for each interface and adds it to the select
73
 * mask.
74
 */
75
int
76
if_register_bpf(struct interface_info *info)
77
{
78
	int sock;
79
80
	if ((sock = open("/dev/bpf", O_RDWR)) == -1)
81
		fatal("Can't open bpf device");
82
83
	/* Set the BPF device to point at this interface. */
84
	if (ioctl(sock, BIOCSETIF, info->ifp) == -1)
85
		fatal("Can't attach interface %s to bpf device", info->name);
86
87
	info->send_packet = send_packet;
88
	return (sock);
89
}
90
91
void
92
if_register_send(struct interface_info *info)
93
{
94
	/*
95
	 * If we're using the bpf API for sending and receiving, we
96
	 * don't need to register this interface twice.
97
	 */
98
	info->wfdesc = info->rfdesc;
99
}
100
101
/*
102
 * Packet read filter program: 'ip and udp and dst port bootps'
103
 */
104
struct bpf_insn dhcp_bpf_filter[] = {
105
	/* Make sure this is an IP packet... */
106
	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
107
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
108
109
	/* Make sure it's a UDP packet... */
110
	BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
111
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
112
113
	/* Make sure this isn't a fragment... */
114
	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
115
	BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
116
117
	/* Get the IP header length... */
118
	BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
119
120
	/* Make sure it's to the right port... */
121
	BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
122
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SERVER_PORT, 0, 1),
123
124
	/* If we passed all the tests, ask for the whole packet. */
125
	BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
126
127
	/* Otherwise, drop it. */
128
	BPF_STMT(BPF_RET+BPF_K, 0),
129
};
130
131
int dhcp_bpf_filter_len = sizeof(dhcp_bpf_filter) / sizeof(struct bpf_insn);
132
133
134
/*
135
 * Packet write filter program:
136
 * 'ip and udp and src port bootps and dst port (bootps or bootpc)'
137
 */
138
struct bpf_insn dhcp_bpf_wfilter[] = {
139
	/* Make sure this is an IP packet... */
140
	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
141
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 11),
142
143
	/* Make sure it's a UDP packet... */
144
	BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
145
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
146
147
	/* Make sure this isn't a fragment... */
148
	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
149
	BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
150
151
	/* Get the IP header length... */
152
	BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
153
154
	/* Make sure it's from the right port... */
155
	BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14),
156
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SERVER_PORT, 0, 4),
157
158
	/* Make sure it is to the right ports ... */
159
	BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
160
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, CLIENT_PORT, 1, 0),
161
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SERVER_PORT, 0, 1),
162
163
	/* If we passed all the tests, ask for the whole packet. */
164
	BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
165
166
	/* Otherwise, drop it. */
167
	BPF_STMT(BPF_RET+BPF_K, 0),
168
};
169
170
int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn);
171
172
void
173
if_register_receive(struct interface_info *info)
174
{
175
	struct bpf_version v;
176
	struct bpf_program p;
177
	int flag = 1, sz, cmplt = 0;
178
179
	/* Open a BPF device and hang it on this interface... */
180
	info->rfdesc = if_register_bpf(info);
181
182
	/* Make sure the BPF version is in range... */
183
	if (ioctl(info->rfdesc, BIOCVERSION, &v) == -1)
184
		fatal("Can't get BPF version");
185
186
	if (v.bv_major != BPF_MAJOR_VERSION ||
187
	    v.bv_minor < BPF_MINOR_VERSION)
188
		fatalx("Kernel BPF version out of range - recompile dhcpd!");
189
190
	/*
191
	 * Set immediate mode so that reads return as soon as a packet
192
	 * comes in, rather than waiting for the input buffer to fill
193
	 * with packets.
194
	 */
195
	if (ioctl(info->rfdesc, BIOCIMMEDIATE, &flag) == -1)
196
		fatal("Can't set immediate mode on bpf device");
197
198
	if (ioctl(info->rfdesc, BIOCSFILDROP, &flag) == -1)
199
		fatal("Can't set filter-drop mode on bpf device");
200
201
	/* make sure kernel fills in the source ethernet address */
202
	if (ioctl(info->rfdesc, BIOCSHDRCMPLT, &cmplt) == -1)
203
		fatal("Can't set header complete flag on bpf device");
204
205
	/* Get the required BPF buffer length from the kernel. */
206
	if (ioctl(info->rfdesc, BIOCGBLEN, &sz) == -1)
207
		fatal("Can't get bpf buffer length");
208
	info->rbuf_max = sz;
209
	info->rbuf = malloc(info->rbuf_max);
210
	if (!info->rbuf)
211
		fatalx("Can't allocate %lu bytes for bpf input buffer.",
212
		    (unsigned long)info->rbuf_max);
213
	info->rbuf_offset = 0;
214
	info->rbuf_len = 0;
215
216
	/* Set up the bpf filter program structure. */
217
	p.bf_len = dhcp_bpf_filter_len;
218
	p.bf_insns = dhcp_bpf_filter;
219
220
	if (ioctl(info->rfdesc, BIOCSETF, &p) == -1)
221
		fatal("Can't install packet filter program");
222
223
	/* Set up the bpf write filter program structure. */
224
	p.bf_len = dhcp_bpf_wfilter_len;
225
	p.bf_insns = dhcp_bpf_wfilter;
226
227
	if (ioctl(info->rfdesc, BIOCSETWF, &p) == -1)
228
		fatal("Can't install write filter program");
229
230
	/* make sure these settings cannot be changed after dropping privs */
231
	if (ioctl(info->rfdesc, BIOCLOCK) == -1)
232
		fatal("Failed to lock bpf descriptor");
233
}
234
235
ssize_t
236
send_packet(struct interface_info *interface, struct dhcp_packet *raw,
237
    size_t len, struct in_addr from, struct sockaddr_in *to,
238
    struct hardware *hto)
239
{
240
	unsigned char buf[256];
241
	struct iovec iov[2];
242
	ssize_t result;
243
	int bufp = 0;
244
245
	/* Assemble the headers... */
246
	assemble_hw_header(interface, buf, &bufp, hto);
247
	assemble_udp_ip_header(interface, buf, &bufp, from.s_addr,
248
	    to->sin_addr.s_addr, to->sin_port, (unsigned char *)raw, len);
249
250
	/* Fire it off */
251
	iov[0].iov_base = (char *)buf;
252
	iov[0].iov_len = bufp;
253
	iov[1].iov_base = (char *)raw;
254
	iov[1].iov_len = len;
255
256
	result = writev(interface->wfdesc, iov, 2);
257
	if (result == -1)
258
		log_warn("send_packet");
259
	return (result);
260
}
261
262
ssize_t
263
receive_packet(struct interface_info *interface, unsigned char *buf,
264
    size_t len, struct sockaddr_in *from, struct hardware *hfrom)
265
{
266
	int length = 0, offset = 0;
267
	struct bpf_hdr hdr;
268
269
	/*
270
	 * All this complexity is because BPF doesn't guarantee that
271
	 * only one packet will be returned at a time.  We're getting
272
	 * what we deserve, though - this is a terrible abuse of the BPF
273
	 * interface.  Sigh.
274
	 */
275
276
	/* Process packets until we get one we can return or until we've
277
	 * done a read and gotten nothing we can return...
278
	 */
279
	do {
280
		/* If the buffer is empty, fill it. */
281
		if (interface->rbuf_offset >= interface->rbuf_len) {
282
			length = read(interface->rfdesc, interface->rbuf,
283
			    interface->rbuf_max);
284
			if (length <= 0)
285
				return (length);
286
			interface->rbuf_offset = 0;
287
			interface->rbuf_len = length;
288
		}
289
290
		/*
291
		 * If there isn't room for a whole bpf header, something
292
		 * went wrong, but we'll ignore it and hope it goes
293
		 * away... XXX
294
		 */
295
		if (interface->rbuf_len - interface->rbuf_offset <
296
		    sizeof(hdr)) {
297
			interface->rbuf_offset = interface->rbuf_len;
298
			continue;
299
		}
300
301
		/* Copy out a bpf header... */
302
		memcpy(&hdr, &interface->rbuf[interface->rbuf_offset],
303
		    sizeof(hdr));
304
305
		/*
306
		 * If the bpf header plus data doesn't fit in what's
307
		 * left of the buffer, stick head in sand yet again...
308
		 */
309
		if (interface->rbuf_offset + hdr.bh_hdrlen + hdr.bh_caplen >
310
		    interface->rbuf_len) {
311
			interface->rbuf_offset = interface->rbuf_len;
312
			continue;
313
		}
314
315
		/*
316
		 * If the captured data wasn't the whole packet, or if
317
		 * the packet won't fit in the input buffer, all we can
318
		 * do is drop it.
319
		 */
320
		if (hdr.bh_caplen != hdr.bh_datalen) {
321
			interface->rbuf_offset = BPF_WORDALIGN(
322
			    interface->rbuf_offset + hdr.bh_hdrlen +
323
			    hdr.bh_caplen);
324
			continue;
325
		}
326
327
		/* Skip over the BPF header... */
328
		interface->rbuf_offset += hdr.bh_hdrlen;
329
330
		/* Decode the physical header... */
331
		offset = decode_hw_header(interface->rbuf +
332
		    interface->rbuf_offset, hdr.bh_caplen, hfrom);
333
334
		/*
335
		 * If a physical layer checksum failed (dunno of any
336
		 * physical layer that supports this, but WTH), skip
337
		 * this packet.
338
		 */
339
		if (offset < 0) {
340
			interface->rbuf_offset = BPF_WORDALIGN(
341
			    interface->rbuf_offset + hdr.bh_caplen);
342
			continue;
343
		}
344
		interface->rbuf_offset += offset;
345
		hdr.bh_caplen -= offset;
346
347
		/* Decode the IP and UDP headers... */
348
		offset = decode_udp_ip_header(interface->rbuf +
349
		    interface->rbuf_offset, hdr.bh_caplen, from);
350
351
		/* If the IP or UDP checksum was bad, skip the packet... */
352
		if (offset < 0) {
353
			interface->rbuf_offset = BPF_WORDALIGN(
354
			    interface->rbuf_offset + hdr.bh_caplen);
355
			continue;
356
		}
357
		interface->rbuf_offset += offset;
358
		hdr.bh_caplen -= offset;
359
360
		/*
361
		 * If there's not enough room to stash the packet data,
362
		 * we have to skip it (this shouldn't happen in real
363
		 * life, though).
364
		 */
365
		if (hdr.bh_caplen > len) {
366
			interface->rbuf_offset = BPF_WORDALIGN(
367
			    interface->rbuf_offset + hdr.bh_caplen);
368
			continue;
369
		}
370
371
		/* Copy out the data in the packet... */
372
		memcpy(buf, interface->rbuf + interface->rbuf_offset,
373
		    hdr.bh_caplen);
374
		interface->rbuf_offset = BPF_WORDALIGN(interface->rbuf_offset +
375
		    hdr.bh_caplen);
376
		return (hdr.bh_caplen);
377
	} while (!length);
378
	return (0);
379
}