1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * dhcpcd: BPF arp and bootp filtering
4 * Copyright (c) 2006-2021 Roy Marples <roy@marples.name>
5 * All rights reserved
6
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/ioctl.h>
30 #include <sys/socket.h>
31
32 #include <arpa/inet.h>
33
34 #include <net/if.h>
35 #include <netinet/in.h>
36 #include <netinet/if_ether.h>
37
38 #ifdef __linux__
39 /* Special BPF snowflake. */
40 #include <linux/filter.h>
41 #define bpf_insn sock_filter
42 #else
43 #include <net/bpf.h>
44 #endif
45
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <paths.h>
49 #include <stddef.h>
50 #include <stdlib.h>
51 #include <string.h>
52
53 #include "common.h"
54 #include "arp.h"
55 #include "bpf.h"
56 #include "dhcp.h"
57 #include "if.h"
58 #include "logerr.h"
59
60 /* BPF helper macros */
61 #ifdef __linux__
62 #define BPF_WHOLEPACKET 0x7fffffff /* work around buggy LPF filters */
63 #else
64 #define BPF_WHOLEPACKET ~0U
65 #endif
66
67 /* Macros to update the BPF structure */
68 #define BPF_SET_STMT(insn, c, v) { \
69 (insn)->code = (c); \
70 (insn)->jt = 0; \
71 (insn)->jf = 0; \
72 (insn)->k = (uint32_t)(v); \
73 }
74
75 #define BPF_SET_JUMP(insn, c, v, t, f) { \
76 (insn)->code = (c); \
77 (insn)->jt = (t); \
78 (insn)->jf = (f); \
79 (insn)->k = (uint32_t)(v); \
80 }
81
82 size_t
bpf_frame_header_len(const struct interface * ifp)83 bpf_frame_header_len(const struct interface *ifp)
84 {
85
86 switch (ifp->hwtype) {
87 case ARPHRD_ETHER:
88 return sizeof(struct ether_header);
89 default:
90 return 0;
91 }
92 }
93
94 void *
bpf_frame_header_src(const struct interface * ifp,void * fh,size_t * len)95 bpf_frame_header_src(const struct interface *ifp, void *fh, size_t *len)
96 {
97 uint8_t *f = fh;
98
99 switch (ifp->hwtype) {
100 case ARPHRD_ETHER:
101 *len = sizeof(((struct ether_header *)0)->ether_shost);
102 return f + offsetof(struct ether_header, ether_shost);
103 default:
104 *len = 0;
105 errno = ENOTSUP;
106 return NULL;
107 }
108 }
109
110 void *
bpf_frame_header_dst(const struct interface * ifp,void * fh,size_t * len)111 bpf_frame_header_dst(const struct interface *ifp, void *fh, size_t *len)
112 {
113 uint8_t *f = fh;
114
115 switch (ifp->hwtype) {
116 case ARPHRD_ETHER:
117 *len = sizeof(((struct ether_header *)0)->ether_dhost);
118 return f + offsetof(struct ether_header, ether_dhost);
119 default:
120 *len = 0;
121 errno = ENOTSUP;
122 return NULL;
123 }
124 }
125
126 static const uint8_t etherbcastaddr[] =
127 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
128
129 int
bpf_frame_bcast(const struct interface * ifp,const void * frame)130 bpf_frame_bcast(const struct interface *ifp, const void *frame)
131 {
132
133 switch (ifp->hwtype) {
134 case ARPHRD_ETHER:
135 return memcmp((const char *)frame +
136 offsetof(struct ether_header, ether_dhost),
137 etherbcastaddr, sizeof(etherbcastaddr));
138 default:
139 return -1;
140 }
141 }
142
143 #ifndef __linux__
144 /* Linux is a special snowflake for opening, attaching and reading BPF.
145 * See if-linux.c for the Linux specific BPF functions. */
146
147 const char *bpf_name = "Berkley Packet Filter";
148
149 struct bpf *
bpf_open(const struct interface * ifp,int (* filter)(const struct bpf *,const struct in_addr *),const struct in_addr * ia)150 bpf_open(const struct interface *ifp,
151 int (*filter)(const struct bpf *, const struct in_addr *),
152 const struct in_addr *ia)
153 {
154 struct bpf *bpf;
155 struct bpf_version pv = { .bv_major = 0, .bv_minor = 0 };
156 struct ifreq ifr = { .ifr_flags = 0 };
157 int ibuf_len = 0;
158 #ifdef BIOCIMMEDIATE
159 unsigned int flags;
160 #endif
161 #ifndef O_CLOEXEC
162 int fd_opts;
163 #endif
164
165 bpf = calloc(1, sizeof(*bpf));
166 if (bpf == NULL)
167 return NULL;
168 bpf->bpf_ifp = ifp;
169
170 #ifdef _PATH_BPF
171 bpf->bpf_fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK
172 #ifdef O_CLOEXEC
173 | O_CLOEXEC
174 #endif
175 );
176 #else
177 char device[32];
178 int n = 0;
179
180 do {
181 snprintf(device, sizeof(device), "/dev/bpf%d", n++);
182 bpf->bpf_fd = open(device, O_RDWR | O_NONBLOCK
183 #ifdef O_CLOEXEC
184 | O_CLOEXEC
185 #endif
186 );
187 } while (bpf->bpf_fd == -1 && errno == EBUSY);
188 #endif
189
190 if (bpf->bpf_fd == -1)
191 goto eexit;
192
193 #ifndef O_CLOEXEC
194 if ((fd_opts = fcntl(bpf->bpf_fd, F_GETFD)) == -1 ||
195 fcntl(bpf->bpf_fd, F_SETFD, fd_opts | FD_CLOEXEC) == -1)
196 goto eexit;
197 #endif
198
199 if (ioctl(bpf->bpf_fd, BIOCVERSION, &pv) == -1)
200 goto eexit;
201 if (pv.bv_major != BPF_MAJOR_VERSION ||
202 pv.bv_minor < BPF_MINOR_VERSION) {
203 logerrx("BPF version mismatch - recompile");
204 goto eexit;
205 }
206
207 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
208 if (ioctl(bpf->bpf_fd, BIOCSETIF, &ifr) == -1)
209 goto eexit;
210
211 #ifdef BIOCIMMEDIATE
212 flags = 1;
213 if (ioctl(bpf->bpf_fd, BIOCIMMEDIATE, &flags) == -1)
214 goto eexit;
215 #endif
216
217 if (filter(bpf, ia) != 0)
218 goto eexit;
219
220 /* Get the required BPF buffer length from the kernel. */
221 if (ioctl(bpf->bpf_fd, BIOCGBLEN, &ibuf_len) == -1)
222 goto eexit;
223 bpf->bpf_size = (size_t)ibuf_len;
224 bpf->bpf_buffer = malloc(bpf->bpf_size);
225 if (bpf->bpf_buffer == NULL)
226 goto eexit;
227 return bpf;
228
229 eexit:
230 if (bpf->bpf_fd != -1)
231 close(bpf->bpf_fd);
232 free(bpf);
233 return NULL;
234 }
235
236 /* BPF requires that we read the entire buffer.
237 * So we pass the buffer in the API so we can loop on >1 packet. */
238 ssize_t
bpf_read(struct bpf * bpf,void * data,size_t len)239 bpf_read(struct bpf *bpf, void *data, size_t len)
240 {
241 ssize_t bytes;
242 struct bpf_hdr packet;
243 const char *payload;
244
245 bpf->bpf_flags &= ~BPF_EOF;
246 for (;;) {
247 if (bpf->bpf_len == 0) {
248 bytes = read(bpf->bpf_fd, bpf->bpf_buffer,
249 bpf->bpf_size);
250 #if defined(__sun)
251 /* After 2^31 bytes, the kernel offset overflows.
252 * To work around this bug, lseek 0. */
253 if (bytes == -1 && errno == EINVAL) {
254 lseek(bpf->bpf_fd, 0, SEEK_SET);
255 continue;
256 }
257 #endif
258 if (bytes == -1 || bytes == 0)
259 return bytes;
260 bpf->bpf_len = (size_t)bytes;
261 bpf->bpf_pos = 0;
262 }
263 bytes = -1;
264 payload = (const char *)bpf->bpf_buffer + bpf->bpf_pos;
265 memcpy(&packet, payload, sizeof(packet));
266 if (bpf->bpf_pos + packet.bh_caplen + packet.bh_hdrlen >
267 bpf->bpf_len)
268 goto next; /* Packet beyond buffer, drop. */
269 payload += packet.bh_hdrlen;
270 if (packet.bh_caplen > len)
271 bytes = (ssize_t)len;
272 else
273 bytes = (ssize_t)packet.bh_caplen;
274 if (bpf_frame_bcast(bpf->bpf_ifp, payload) == 0)
275 bpf->bpf_flags |= BPF_BCAST;
276 else
277 bpf->bpf_flags &= ~BPF_BCAST;
278 memcpy(data, payload, (size_t)bytes);
279 next:
280 bpf->bpf_pos += BPF_WORDALIGN(packet.bh_hdrlen +
281 packet.bh_caplen);
282 if (bpf->bpf_pos >= bpf->bpf_len) {
283 bpf->bpf_len = bpf->bpf_pos = 0;
284 bpf->bpf_flags |= BPF_EOF;
285 }
286 if (bytes != -1)
287 return bytes;
288 }
289
290 /* NOTREACHED */
291 }
292
293 int
bpf_attach(int fd,void * filter,unsigned int filter_len)294 bpf_attach(int fd, void *filter, unsigned int filter_len)
295 {
296 struct bpf_program pf = { .bf_insns = filter, .bf_len = filter_len };
297
298 /* Install the filter. */
299 return ioctl(fd, BIOCSETF, &pf);
300 }
301
302 #ifdef BIOCSETWF
303 static int
bpf_wattach(int fd,void * filter,unsigned int filter_len)304 bpf_wattach(int fd, void *filter, unsigned int filter_len)
305 {
306 struct bpf_program pf = { .bf_insns = filter, .bf_len = filter_len };
307
308 /* Install the filter. */
309 return ioctl(fd, BIOCSETWF, &pf);
310 }
311 #endif
312 #endif
313
314 #ifndef __sun
315 /* SunOS is special too - sending via BPF goes nowhere. */
316 ssize_t
bpf_send(const struct bpf * bpf,uint16_t protocol,const void * data,size_t len)317 bpf_send(const struct bpf *bpf, uint16_t protocol,
318 const void *data, size_t len)
319 {
320 struct iovec iov[2];
321 struct ether_header eh;
322
323 switch(bpf->bpf_ifp->hwtype) {
324 case ARPHRD_ETHER:
325 memset(&eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
326 memcpy(&eh.ether_shost, bpf->bpf_ifp->hwaddr,
327 sizeof(eh.ether_shost));
328 eh.ether_type = htons(protocol);
329 iov[0].iov_base = &eh;
330 iov[0].iov_len = sizeof(eh);
331 break;
332 default:
333 iov[0].iov_base = NULL;
334 iov[0].iov_len = 0;
335 break;
336 }
337 iov[1].iov_base = UNCONST(data);
338 iov[1].iov_len = len;
339 return writev(bpf->bpf_fd, iov, 2);
340 }
341 #endif
342
343 void
bpf_close(struct bpf * bpf)344 bpf_close(struct bpf *bpf)
345 {
346
347 close(bpf->bpf_fd);
348 free(bpf->bpf_buffer);
349 free(bpf);
350 }
351
352 #ifdef ARP
353 #define BPF_CMP_HWADDR_LEN ((((HWADDR_LEN / 4) + 2) * 2) + 1)
354 static unsigned int
bpf_cmp_hwaddr(struct bpf_insn * bpf,size_t bpf_len,size_t off,bool equal,const uint8_t * hwaddr,size_t hwaddr_len)355 bpf_cmp_hwaddr(struct bpf_insn *bpf, size_t bpf_len, size_t off,
356 bool equal, const uint8_t *hwaddr, size_t hwaddr_len)
357 {
358 struct bpf_insn *bp;
359 size_t maclen, nlft, njmps;
360 uint32_t mac32;
361 uint16_t mac16;
362 uint8_t jt, jf;
363
364 /* Calc the number of jumps */
365 if ((hwaddr_len / 4) >= 128) {
366 errno = EINVAL;
367 return 0;
368 }
369 njmps = (hwaddr_len / 4) * 2; /* 2 instructions per check */
370 /* We jump after the 1st check. */
371 if (njmps)
372 njmps -= 2;
373 nlft = hwaddr_len % 4;
374 if (nlft) {
375 njmps += (nlft / 2) * 2;
376 nlft = nlft % 2;
377 if (nlft)
378 njmps += 2;
379
380 }
381
382 /* Skip to positive finish. */
383 njmps++;
384 if (equal) {
385 jt = (uint8_t)njmps;
386 jf = 0;
387 } else {
388 jt = 0;
389 jf = (uint8_t)njmps;
390 }
391
392 bp = bpf;
393 for (; hwaddr_len > 0;
394 hwaddr += maclen, hwaddr_len -= maclen, off += maclen)
395 {
396 if (bpf_len < 3) {
397 errno = ENOBUFS;
398 return 0;
399 }
400 bpf_len -= 3;
401
402 if (hwaddr_len >= 4) {
403 maclen = sizeof(mac32);
404 memcpy(&mac32, hwaddr, maclen);
405 BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, off);
406 bp++;
407 BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
408 htonl(mac32), jt, jf);
409 } else if (hwaddr_len >= 2) {
410 maclen = sizeof(mac16);
411 memcpy(&mac16, hwaddr, maclen);
412 BPF_SET_STMT(bp, BPF_LD + BPF_H + BPF_IND, off);
413 bp++;
414 BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
415 htons(mac16), jt, jf);
416 } else {
417 maclen = sizeof(*hwaddr);
418 BPF_SET_STMT(bp, BPF_LD + BPF_B + BPF_IND, off);
419 bp++;
420 BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
421 *hwaddr, jt, jf);
422 }
423 if (jt)
424 jt = (uint8_t)(jt - 2);
425 if (jf)
426 jf = (uint8_t)(jf - 2);
427 bp++;
428 }
429
430 /* Last step is always return failure.
431 * Next step is a positive finish. */
432 BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
433 bp++;
434
435 return (unsigned int)(bp - bpf);
436 }
437 #endif
438
439 #ifdef ARP
440 static const struct bpf_insn bpf_arp_ether [] = {
441 /* Check this is an ARP packet. */
442 BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
443 offsetof(struct ether_header, ether_type)),
444 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 1, 0),
445 BPF_STMT(BPF_RET + BPF_K, 0),
446
447 /* Load frame header length into X */
448 BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, sizeof(struct ether_header)),
449
450 /* Make sure the hardware type matches. */
451 BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_hrd)),
452 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0),
453 BPF_STMT(BPF_RET + BPF_K, 0),
454
455 /* Make sure the hardware length matches. */
456 BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_hln)),
457 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
458 sizeof(((struct ether_arp *)0)->arp_sha), 1, 0),
459 BPF_STMT(BPF_RET + BPF_K, 0),
460 };
461 #define BPF_ARP_ETHER_LEN __arraycount(bpf_arp_ether)
462
463 static const struct bpf_insn bpf_arp_filter [] = {
464 /* Make sure this is for IP. */
465 BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_pro)),
466 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0),
467 BPF_STMT(BPF_RET + BPF_K, 0),
468 /* Make sure this is an ARP REQUEST. */
469 BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_op)),
470 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0),
471 /* or ARP REPLY. */
472 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0),
473 BPF_STMT(BPF_RET + BPF_K, 0),
474 /* Make sure the protocol length matches. */
475 BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_pln)),
476 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(in_addr_t), 1, 0),
477 BPF_STMT(BPF_RET + BPF_K, 0),
478 };
479 #define BPF_ARP_FILTER_LEN __arraycount(bpf_arp_filter)
480
481 /* One address is two checks of two statements. */
482 #define BPF_NADDRS 1
483 #define BPF_ARP_ADDRS_LEN 5 + ((BPF_NADDRS * 2) * 2)
484
485 #define BPF_ARP_LEN BPF_ARP_ETHER_LEN + BPF_ARP_FILTER_LEN + \
486 BPF_CMP_HWADDR_LEN + BPF_ARP_ADDRS_LEN
487
488 static int
bpf_arp_rw(const struct bpf * bpf,const struct in_addr * ia,bool recv)489 bpf_arp_rw(const struct bpf *bpf, const struct in_addr *ia, bool recv)
490 {
491 const struct interface *ifp = bpf->bpf_ifp;
492 struct bpf_insn buf[BPF_ARP_LEN + 1];
493 struct bpf_insn *bp;
494 uint16_t arp_len;
495
496 bp = buf;
497 /* Check frame header. */
498 switch(ifp->hwtype) {
499 case ARPHRD_ETHER:
500 memcpy(bp, bpf_arp_ether, sizeof(bpf_arp_ether));
501 bp += BPF_ARP_ETHER_LEN;
502 arp_len = sizeof(struct ether_header)+sizeof(struct ether_arp);
503 break;
504 default:
505 errno = EINVAL;
506 return -1;
507 }
508
509 /* Copy in the main filter. */
510 memcpy(bp, bpf_arp_filter, sizeof(bpf_arp_filter));
511 bp += BPF_ARP_FILTER_LEN;
512
513 /* Ensure it's not from us. */
514 bp += bpf_cmp_hwaddr(bp, BPF_CMP_HWADDR_LEN, sizeof(struct arphdr),
515 !recv, ifp->hwaddr, ifp->hwlen);
516
517 /* Match sender protocol address */
518 BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND,
519 sizeof(struct arphdr) + ifp->hwlen);
520 bp++;
521 BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htonl(ia->s_addr), 0, 1);
522 bp++;
523 BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
524 bp++;
525
526 /* If we didn't match sender, then we're only interested in
527 * ARP probes to us, so check the null host sender. */
528 BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, INADDR_ANY, 1, 0);
529 bp++;
530 BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
531 bp++;
532
533 /* Match target protocol address */
534 BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, (sizeof(struct arphdr) +
535 (size_t)(ifp->hwlen * 2) + sizeof(in_addr_t)));
536 bp++;
537 BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htonl(ia->s_addr), 0, 1);
538 bp++;
539 BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
540 bp++;
541
542 /* No match, drop it */
543 BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
544 bp++;
545
546 #ifdef BIOCSETWF
547 if (!recv)
548 return bpf_wattach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
549 #endif
550
551 return bpf_attach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
552 }
553
554 int
bpf_arp(const struct bpf * bpf,const struct in_addr * ia)555 bpf_arp(const struct bpf *bpf, const struct in_addr *ia)
556 {
557
558 #ifdef BIOCSETWF
559 if (bpf_arp_rw(bpf, ia, true) == -1 ||
560 bpf_arp_rw(bpf, ia, false) == -1 ||
561 ioctl(bpf->bpf_fd, BIOCLOCK) == -1)
562 return -1;
563 return 0;
564 #else
565 return bpf_arp_rw(bpf, ia, true);
566 #endif
567 }
568 #endif
569
570 #ifdef ARPHRD_NONE
571 static const struct bpf_insn bpf_bootp_none[] = {
572 };
573 #define BPF_BOOTP_NONE_LEN __arraycount(bpf_bootp_none)
574 #endif
575
576 static const struct bpf_insn bpf_bootp_ether[] = {
577 /* Make sure this is an IP packet. */
578 BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
579 offsetof(struct ether_header, ether_type)),
580 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0),
581 BPF_STMT(BPF_RET + BPF_K, 0),
582
583 /* Advance to the IP header. */
584 BPF_STMT(BPF_LDX + BPF_K, sizeof(struct ether_header)),
585 };
586 #define BPF_BOOTP_ETHER_LEN __arraycount(bpf_bootp_ether)
587
588 static const struct bpf_insn bpf_bootp_base[] = {
589 /* Make sure it's an IPv4 packet. */
590 BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0),
591 BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0xf0),
592 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x40, 1, 0),
593 BPF_STMT(BPF_RET + BPF_K, 0),
594
595 /* Make sure it's a UDP packet. */
596 BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct ip, ip_p)),
597 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0),
598 BPF_STMT(BPF_RET + BPF_K, 0),
599
600 /* Make sure this isn't a fragment. */
601 BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct ip, ip_off)),
602 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 0, 1),
603 BPF_STMT(BPF_RET + BPF_K, 0),
604
605 /* Advance to the UDP header. */
606 BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0),
607 BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x0f),
608 BPF_STMT(BPF_ALU + BPF_MUL + BPF_K, 4),
609 BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0),
610 BPF_STMT(BPF_MISC + BPF_TAX, 0),
611 };
612 #define BPF_BOOTP_BASE_LEN __arraycount(bpf_bootp_base)
613
614 static const struct bpf_insn bpf_bootp_read[] = {
615 /* Make sure it's from and to the right port. */
616 BPF_STMT(BPF_LD + BPF_W + BPF_IND, 0),
617 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (BOOTPS << 16) + BOOTPC, 1, 0),
618 BPF_STMT(BPF_RET + BPF_K, 0),
619 };
620 #define BPF_BOOTP_READ_LEN __arraycount(bpf_bootp_read)
621
622 #ifdef BIOCSETWF
623 static const struct bpf_insn bpf_bootp_write[] = {
624 /* Make sure it's from and to the right port. */
625 BPF_STMT(BPF_LD + BPF_W + BPF_IND, 0),
626 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (BOOTPC << 16) + BOOTPS, 1, 0),
627 BPF_STMT(BPF_RET + BPF_K, 0),
628 };
629 #define BPF_BOOTP_WRITE_LEN __arraycount(bpf_bootp_write)
630 #endif
631
632 #define BPF_BOOTP_CHADDR_LEN ((BOOTP_CHADDR_LEN / 4) * 3)
633 #define BPF_BOOTP_XID_LEN 4 /* BOUND check is 4 instructions */
634
635 #define BPF_BOOTP_LEN BPF_BOOTP_ETHER_LEN + \
636 BPF_BOOTP_BASE_LEN + BPF_BOOTP_READ_LEN + \
637 BPF_BOOTP_XID_LEN + BPF_BOOTP_CHADDR_LEN + 4
638
639 static int
bpf_bootp_rw(const struct bpf * bpf,bool read)640 bpf_bootp_rw(const struct bpf *bpf, bool read)
641 {
642 struct bpf_insn buf[BPF_BOOTP_LEN + 1];
643 struct bpf_insn *bp;
644
645 bp = buf;
646 /* Check frame header. */
647 switch(bpf->bpf_ifp->hwtype) {
648 #ifdef ARPHRD_NONE
649 case ARPHRD_NONE:
650 memcpy(bp, bpf_bootp_none, sizeof(bpf_bootp_none));
651 bp += BPF_BOOTP_NONE_LEN;
652 break;
653 #endif
654 case ARPHRD_ETHER:
655 memcpy(bp, bpf_bootp_ether, sizeof(bpf_bootp_ether));
656 bp += BPF_BOOTP_ETHER_LEN;
657 break;
658 default:
659 errno = EINVAL;
660 return -1;
661 }
662
663 /* Copy in the main filter. */
664 memcpy(bp, bpf_bootp_base, sizeof(bpf_bootp_base));
665 bp += BPF_BOOTP_BASE_LEN;
666
667 #ifdef BIOCSETWF
668 if (!read) {
669 memcpy(bp, bpf_bootp_write, sizeof(bpf_bootp_write));
670 bp += BPF_BOOTP_WRITE_LEN;
671
672 /* All passed, return the packet. */
673 BPF_SET_STMT(bp, BPF_RET + BPF_K, BPF_WHOLEPACKET);
674 bp++;
675
676 return bpf_wattach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
677 }
678 #else
679 UNUSED(read);
680 #endif
681
682 memcpy(bp, bpf_bootp_read, sizeof(bpf_bootp_read));
683 bp += BPF_BOOTP_READ_LEN;
684
685 /* All passed, return the packet. */
686 BPF_SET_STMT(bp, BPF_RET + BPF_K, BPF_WHOLEPACKET);
687 bp++;
688
689 return bpf_attach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
690 }
691
692 int
bpf_bootp(const struct bpf * bpf,__unused const struct in_addr * ia)693 bpf_bootp(const struct bpf *bpf, __unused const struct in_addr *ia)
694 {
695
696 #ifdef BIOCSETWF
697 if (bpf_bootp_rw(bpf, true) == -1 ||
698 bpf_bootp_rw(bpf, false) == -1 ||
699 ioctl(bpf->bpf_fd, BIOCLOCK) == -1)
700 return -1;
701 return 0;
702 #else
703 #ifdef PRIVSEP
704 #if defined(__sun) /* Solaris cannot send via BPF. */
705 #elif defined(BIOCSETF)
706 #warning No BIOCSETWF support - a compromised BPF can be used as a raw socket
707 #else
708 #warning A compromised PF_PACKET socket can be used as a raw socket
709 #endif
710 #endif
711 return bpf_bootp_rw(bpf, true);
712 #endif
713 }
714