1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * dhcpcd: BPF arp and bootp filtering 4 * Copyright (c) 2006-2020 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 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 * 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 * 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 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 * 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 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 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 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 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 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 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 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 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 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 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