GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/dhclient/bpf.c Lines: 0 134 0.0 %
Date: 2016-12-06 Branches: 0 62 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: bpf.c,v 1.42 2016/07/23 15:53:19 stsp 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/queue.h>
45
#include <sys/socket.h>
46
#include <sys/types.h>
47
48
#include <net/bpf.h>
49
#include <net/if.h>
50
51
#include <netinet/in.h>
52
#include <netinet/ip.h>
53
#include <netinet/udp.h>
54
#include <netinet/if_ether.h>
55
56
#include <errno.h>
57
#include <fcntl.h>
58
#include <signal.h>
59
#include <stdio.h>
60
#include <stdlib.h>
61
#include <string.h>
62
#include <unistd.h>
63
64
#include "dhcp.h"
65
#include "dhcpd.h"
66
67
int if_register_bpf(void);
68
69
/*
70
 * Called by get_interface_list for each interface that's discovered.
71
 * Opens a packet filter for each interface and adds it to the select
72
 * mask.
73
 */
74
int
75
if_register_bpf(void)
76
{
77
	struct ifreq ifr;
78
	int sock;
79
80
	if ((sock = open("/dev/bpf0", O_RDWR | O_CLOEXEC)) == -1)
81
		error("Can't open bpf: %s", strerror(errno));
82
83
	/* Set the BPF device to point at this interface. */
84
	strlcpy(ifr.ifr_name, ifi->name, IFNAMSIZ);
85
	if (ioctl(sock, BIOCSETIF, &ifr) < 0)
86
		error("Can't attach interface %s to /dev/bpf0: %s",
87
		    ifi->name, strerror(errno));
88
89
	return (sock);
90
}
91
92
void
93
if_register_send(void)
94
{
95
	int sock, on = 1;
96
97
	/*
98
	 * Use raw socket for unicast send.
99
	 */
100
	if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1)
101
		error("socket(SOCK_RAW): %s", strerror(errno));
102
	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on,
103
	    sizeof(on)) == -1)
104
		error("setsockopt(IP_HDRINCL): %s", strerror(errno));
105
	if (setsockopt(sock, IPPROTO_IP, SO_RTABLE, &ifi->rdomain,
106
	    sizeof(ifi->rdomain)) == -1)
107
		error("setsockopt(SO_RTABLE): %s", strerror(errno));
108
109
	ifi->ufdesc = sock;
110
}
111
112
/*
113
 * Packet filter program.
114
 *
115
 * XXX: Changes to the filter program may require changes to the
116
 * constant offsets used in if_register_receive to patch the BPF program!
117
 */
118
struct bpf_insn dhcp_bpf_filter[] = {
119
	/* Make sure this is an IP packet. */
120
	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
121
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
122
123
	/* Make sure it's a UDP packet. */
124
	BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
125
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
126
127
	/* Make sure this isn't a fragment. */
128
	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
129
	BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
130
131
	/* Get the IP header length. */
132
	BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
133
134
	/* Make sure it's to the right port. */
135
	BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
136
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),		/* patch */
137
138
	/* If we passed all the tests, ask for the whole packet. */
139
	BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
140
141
	/* Otherwise, drop it. */
142
	BPF_STMT(BPF_RET+BPF_K, 0),
143
};
144
145
int dhcp_bpf_filter_len = sizeof(dhcp_bpf_filter) / sizeof(struct bpf_insn);
146
147
/*
148
 * Packet write filter program:
149
 * 'ip and udp and src port bootps and dst port (bootps or bootpc)'
150
 */
151
struct bpf_insn dhcp_bpf_wfilter[] = {
152
	BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14),
153
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12),
154
155
	/* Make sure this is an IP packet. */
156
	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
157
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10),
158
159
	/* Make sure it's a UDP packet. */
160
	BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
161
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8),
162
163
	/* Make sure this isn't a fragment. */
164
	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
165
	BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0),	/* patched */
166
167
	/* Get the IP header length. */
168
	BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
169
170
	/* Make sure it's from the right port. */
171
	BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14),
172
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3),
173
174
	/* Make sure it is to the right ports. */
175
	BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
176
	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),
177
178
	/* If we passed all the tests, ask for the whole packet. */
179
	BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
180
181
	/* Otherwise, drop it. */
182
	BPF_STMT(BPF_RET+BPF_K, 0),
183
};
184
185
int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn);
186
187
void
188
if_register_receive(void)
189
{
190
	struct bpf_version v;
191
	struct bpf_program p;
192
	int flag = 1, sz;
193
194
	/* Open a BPF device and hang it on this interface. */
195
	ifi->bfdesc = if_register_bpf();
196
197
	/* Make sure the BPF version is in range. */
198
	if (ioctl(ifi->bfdesc, BIOCVERSION, &v) < 0)
199
		error("Can't get BPF version: %s", strerror(errno));
200
201
	if (v.bv_major != BPF_MAJOR_VERSION ||
202
	    v.bv_minor < BPF_MINOR_VERSION)
203
		error("Kernel BPF version out of range - recompile dhclient!");
204
205
	/*
206
	 * Set immediate mode so that reads return as soon as a packet
207
	 * comes in, rather than waiting for the input buffer to fill
208
	 * with packets.
209
	 */
210
	if (ioctl(ifi->bfdesc, BIOCIMMEDIATE, &flag) < 0)
211
		error("Can't set immediate mode on bpf device: %s",
212
		    strerror(errno));
213
214
	if (ioctl(ifi->bfdesc, BIOCSFILDROP, &flag) < 0)
215
		error("Can't set filter-drop mode on bpf device: %s",
216
		    strerror(errno));
217
218
	/* Get the required BPF buffer length from the kernel. */
219
	if (ioctl(ifi->bfdesc, BIOCGBLEN, &sz) < 0)
220
		error("Can't get bpf buffer length: %s", strerror(errno));
221
	ifi->rbuf_max = sz;
222
	ifi->rbuf = malloc(ifi->rbuf_max);
223
	if (!ifi->rbuf)
224
		error("Can't allocate %lu bytes for bpf input buffer.",
225
		    (unsigned long)ifi->rbuf_max);
226
	ifi->rbuf_offset = 0;
227
	ifi->rbuf_len = 0;
228
229
	/* Set up the bpf filter program structure. */
230
	p.bf_len = dhcp_bpf_filter_len;
231
	p.bf_insns = dhcp_bpf_filter;
232
233
	/* Patch the server port into the BPF program.
234
	 *
235
	 * XXX: changes to filter program may require changes to the
236
	 * insn number(s) used below!
237
	 */
238
	dhcp_bpf_filter[8].k = LOCAL_PORT;
239
240
	if (ioctl(ifi->bfdesc, BIOCSETF, &p) < 0)
241
		error("Can't install packet filter program: %s",
242
		    strerror(errno));
243
244
	/* Set up the bpf write filter program structure. */
245
	p.bf_len = dhcp_bpf_wfilter_len;
246
	p.bf_insns = dhcp_bpf_wfilter;
247
248
	if (dhcp_bpf_wfilter[7].k == 0x1fff)
249
		dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK);
250
251
	if (ioctl(ifi->bfdesc, BIOCSETWF, &p) < 0)
252
		error("Can't install write filter program: %s",
253
		    strerror(errno));
254
255
	if (ioctl(ifi->bfdesc, BIOCLOCK, NULL) < 0)
256
		error("Cannot lock bpf");
257
}
258
259
ssize_t
260
send_packet(struct in_addr from, struct in_addr to)
261
{
262
	struct sockaddr_in dest;
263
	struct ether_header eh;
264
	struct ip ip;
265
	struct udphdr udp;
266
	struct iovec iov[4];
267
	struct msghdr msg;
268
	unsigned char *data;
269
	ssize_t result;
270
	int iovcnt = 0, len;
271
272
	memset(&dest, 0, sizeof(dest));
273
	dest.sin_family = AF_INET;
274
	dest.sin_port = htons(REMOTE_PORT);
275
	dest.sin_addr.s_addr = to.s_addr;
276
277
	if (to.s_addr == INADDR_BROADCAST) {
278
		assemble_eh_header(&eh);
279
		iov[0].iov_base = &eh;
280
		iov[0].iov_len = sizeof(eh);
281
		iovcnt++;
282
	}
283
284
	data = (unsigned char *)&client->bootrequest_packet;
285
	len = client->bootrequest_packet_length;
286
287
	ip.ip_v = 4;
288
	ip.ip_hl = 5;
289
	ip.ip_tos = IPTOS_LOWDELAY;
290
	ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len);
291
	ip.ip_id = 0;
292
	ip.ip_off = 0;
293
	ip.ip_ttl = 128;
294
	ip.ip_p = IPPROTO_UDP;
295
	ip.ip_sum = 0;
296
	ip.ip_src.s_addr = from.s_addr;
297
	ip.ip_dst.s_addr = to.s_addr;
298
	ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0));
299
	iov[iovcnt].iov_base = &ip;
300
	iov[iovcnt].iov_len = sizeof(ip);
301
	iovcnt++;
302
303
	udp.uh_sport = htons(LOCAL_PORT);
304
	udp.uh_dport = htons(REMOTE_PORT);
305
	udp.uh_ulen = htons(sizeof(udp) + len);
306
	udp.uh_sum = 0;
307
	udp.uh_sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp),
308
	    checksum(data, len, checksum((unsigned char *)&ip.ip_src,
309
	    2 * sizeof(ip.ip_src),
310
	    IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen)))));
311
	iov[iovcnt].iov_base = &udp;
312
	iov[iovcnt].iov_len = sizeof(udp);
313
	iovcnt++;
314
315
	iov[iovcnt].iov_base = data;
316
	iov[iovcnt].iov_len = len;
317
	iovcnt++;
318
319
	if (to.s_addr == INADDR_BROADCAST) {
320
		result = writev(ifi->bfdesc, iov, iovcnt);
321
	} else {
322
		memset(&msg, 0, sizeof(msg));
323
		msg.msg_name = (struct sockaddr *)&dest;
324
		msg.msg_namelen = sizeof(to);
325
		msg.msg_iov = iov;
326
		msg.msg_iovlen = iovcnt;
327
		result = sendmsg(ifi->ufdesc, &msg, 0);
328
	}
329
330
	if (result == -1)
331
		warning("send_packet: %s", strerror(errno));
332
	return (result);
333
}
334
335
ssize_t
336
receive_packet(struct sockaddr_in *from, struct ether_addr *hfrom)
337
{
338
	int length = 0, offset = 0;
339
	struct bpf_hdr hdr;
340
341
	/*
342
	 * All this complexity is because BPF doesn't guarantee that
343
	 * only one packet will be returned at a time.  We're getting
344
	 * what we deserve, though - this is a terrible abuse of the BPF
345
	 * interface.  Sigh.
346
	 */
347
348
	/* Process packets until we get one we can return or until we've
349
	 * done a read and gotten nothing we can return.
350
	 */
351
	do {
352
		/* If the buffer is empty, fill it. */
353
		if (ifi->rbuf_offset == ifi->rbuf_len) {
354
			length = read(ifi->bfdesc, ifi->rbuf, ifi->rbuf_max);
355
			if (length <= 0)
356
				return (length);
357
			ifi->rbuf_offset = 0;
358
			ifi->rbuf_len = BPF_WORDALIGN(length);
359
		}
360
361
		/*
362
		 * If there isn't room for a whole bpf header, something
363
		 * went wrong, but we'll ignore it and hope it goes
364
		 * away. XXX
365
		 */
366
		if (ifi->rbuf_len - ifi->rbuf_offset < sizeof(hdr)) {
367
			ifi->rbuf_offset = ifi->rbuf_len;
368
			continue;
369
		}
370
371
		/* Copy out a bpf header. */
372
		memcpy(&hdr, &ifi->rbuf[ifi->rbuf_offset], sizeof(hdr));
373
374
		/*
375
		 * If the bpf header plus data doesn't fit in what's
376
		 * left of the buffer, stick head in sand yet again.
377
		 */
378
		if (ifi->rbuf_offset + hdr.bh_hdrlen + hdr.bh_caplen >
379
		    ifi->rbuf_len) {
380
			ifi->rbuf_offset = ifi->rbuf_len;
381
			continue;
382
		}
383
384
		/*
385
		 * If the captured data wasn't the whole packet, or if
386
		 * the packet won't fit in the input buffer, all we can
387
		 * do is drop it.
388
		 */
389
		if (hdr.bh_caplen != hdr.bh_datalen) {
390
			ifi->rbuf_offset = BPF_WORDALIGN(
391
			    ifi->rbuf_offset + hdr.bh_hdrlen +
392
			    hdr.bh_caplen);
393
			continue;
394
		}
395
396
		/* Skip over the BPF header. */
397
		ifi->rbuf_offset += hdr.bh_hdrlen;
398
399
		/* Decode the physical header. */
400
		offset = decode_hw_header(ifi->rbuf, ifi->rbuf_offset, hfrom);
401
402
		/*
403
		 * If a physical layer checksum failed (dunno of any
404
		 * physical layer that supports this, but WTH), skip
405
		 * this packet.
406
		 */
407
		if (offset < 0) {
408
			ifi->rbuf_offset = BPF_WORDALIGN(
409
			    ifi->rbuf_offset + hdr.bh_caplen);
410
			continue;
411
		}
412
		ifi->rbuf_offset += offset;
413
		hdr.bh_caplen -= offset;
414
415
		/* Decode the IP and UDP headers. */
416
		offset = decode_udp_ip_header(ifi->rbuf,
417
		    ifi->rbuf_offset, from, hdr.bh_caplen);
418
419
		/* If the IP or UDP checksum was bad, skip the packet. */
420
		if (offset < 0) {
421
			ifi->rbuf_offset = BPF_WORDALIGN(
422
			    ifi->rbuf_offset + hdr.bh_caplen);
423
			continue;
424
		}
425
		ifi->rbuf_offset += offset;
426
		hdr.bh_caplen -= offset;
427
428
		/*
429
		 * If there's not enough room to stash the packet data,
430
		 * we have to skip it (this shouldn't happen in real
431
		 * life, though).
432
		 */
433
		if (hdr.bh_caplen > sizeof(client->packet)) {
434
			ifi->rbuf_offset = BPF_WORDALIGN(
435
			    ifi->rbuf_offset + hdr.bh_caplen);
436
			continue;
437
		}
438
439
		/* Copy out the data in the packet. */
440
		memset(&client->packet, DHO_END, sizeof(client->packet));
441
		memcpy(&client->packet, ifi->rbuf + ifi->rbuf_offset,
442
		    hdr.bh_caplen);
443
		ifi->rbuf_offset = BPF_WORDALIGN(ifi->rbuf_offset +
444
		    hdr.bh_caplen);
445
		return (hdr.bh_caplen);
446
	} while (!length);
447
	return (0);
448
}