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