1 /* 2 * dhcpcd: BPF arp and bootp filtering 3 * SPDX-License-Identifier: BSD-2-Clause 4 * Copyright (c) 2006-2025 Roy Marples <roy (at) 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 <net/if.h> 33 #include <netinet/in.h> 34 #include <netinet/if_ether.h> 35 36 #include <arpa/inet.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <stddef.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 #include "config.h" // IWYU pragma: keep 44 #ifdef USE_LIBPCAP 45 #include <pcap/bpf.h> 46 #elif defined(__linux__) 47 #include <linux/filter.h> 48 #define bpf_insn sock_filter 49 #else 50 #include <net/bpf.h> 51 #endif 52 53 #include "arp.h" 54 #include "bpf.h" 55 #include "common.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 { \ 70 (insn)->code = (c); \ 71 (insn)->jt = 0; \ 72 (insn)->jf = 0; \ 73 (insn)->k = (uint32_t)(v); \ 74 } 75 76 #define BPF_SET_JUMP(insn, c, v, t, f) \ 77 { \ 78 (insn)->code = (c); \ 79 (insn)->jt = (t); \ 80 (insn)->jf = (f); \ 81 (insn)->k = (uint32_t)(v); \ 82 } 83 84 size_t 85 bpf_frame_header_len(const struct interface *ifp) 86 { 87 switch (ifp->hwtype) { 88 case ARPHRD_ETHER: 89 return sizeof(struct ether_header); 90 default: 91 return 0; 92 } 93 } 94 95 void * 96 bpf_frame_header_src(const struct interface *ifp, void *fh, size_t *len) 97 { 98 uint8_t *f = fh; 99 100 switch (ifp->hwtype) { 101 case ARPHRD_ETHER: 102 *len = sizeof(((struct ether_header *)0)->ether_shost); 103 return f + offsetof(struct ether_header, ether_shost); 104 default: 105 *len = 0; 106 errno = ENOTSUP; 107 return NULL; 108 } 109 } 110 111 void * 112 bpf_frame_header_dst(const struct interface *ifp, void *fh, size_t *len) 113 { 114 uint8_t *f = fh; 115 116 switch (ifp->hwtype) { 117 case ARPHRD_ETHER: 118 *len = sizeof(((struct ether_header *)0)->ether_dhost); 119 return f + offsetof(struct ether_header, ether_dhost); 120 default: 121 *len = 0; 122 errno = ENOTSUP; 123 return NULL; 124 } 125 } 126 127 static const uint8_t etherbcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 128 129 int 130 bpf_frame_bcast(const struct interface *ifp, const void *frame) 131 { 132 switch (ifp->hwtype) { 133 case ARPHRD_ETHER: 134 return memcmp((const char *)frame + 135 offsetof(struct ether_header, ether_dhost), 136 etherbcastaddr, sizeof(etherbcastaddr)); 137 default: 138 return -1; 139 } 140 } 141 142 ssize_t 143 bpf_send(const struct bpf *bpf, uint16_t protocol, const void *data, size_t len) 144 { 145 struct iovec iov[2]; 146 struct ether_header eh; 147 148 switch (bpf->bpf_ifp->hwtype) { 149 case ARPHRD_ETHER: 150 memset(&eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); 151 memcpy(&eh.ether_shost, bpf->bpf_ifp->hwaddr, 152 sizeof(eh.ether_shost)); 153 eh.ether_type = htons(protocol); 154 iov[0].iov_base = &eh; 155 iov[0].iov_len = sizeof(eh); 156 break; 157 default: 158 iov[0].iov_base = NULL; 159 iov[0].iov_len = 0; 160 break; 161 } 162 iov[1].iov_base = UNCONST(data); 163 iov[1].iov_len = len; 164 165 return bpf_writev(bpf, iov, __arraycount(iov)); 166 } 167 168 #ifdef ARP 169 #define BPF_CMP_HWADDR_LEN ((((HWADDR_LEN / 4) + 2) * 2) + 1) 170 static unsigned int 171 bpf_cmp_hwaddr(struct bpf_insn *bpf, size_t bpf_len, size_t off, bool equal, 172 const uint8_t *hwaddr, size_t hwaddr_len) 173 { 174 struct bpf_insn *bp; 175 size_t maclen, nlft, njmps; 176 uint32_t mac32; 177 uint16_t mac16; 178 uint8_t jt, jf; 179 180 /* Calc the number of jumps */ 181 if ((hwaddr_len / 4) >= 128) { 182 errno = EINVAL; 183 return 0; 184 } 185 njmps = (hwaddr_len / 4) * 2; /* 2 instructions per check */ 186 /* We jump after the 1st check. */ 187 if (njmps) 188 njmps -= 2; 189 nlft = hwaddr_len % 4; 190 if (nlft) { 191 njmps += (nlft / 2) * 2; 192 nlft = nlft % 2; 193 if (nlft) 194 njmps += 2; 195 } 196 197 /* Skip to positive finish. */ 198 njmps++; 199 if (equal) { 200 jt = (uint8_t)njmps; 201 jf = 0; 202 } else { 203 jt = 0; 204 jf = (uint8_t)njmps; 205 } 206 207 bp = bpf; 208 for (; hwaddr_len > 0; 209 hwaddr += maclen, hwaddr_len -= maclen, off += maclen) { 210 if (bpf_len < 3) { 211 errno = ENOBUFS; 212 return 0; 213 } 214 bpf_len -= 3; 215 216 if (hwaddr_len >= 4) { 217 maclen = sizeof(mac32); 218 memcpy(&mac32, hwaddr, maclen); 219 BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, off); 220 bp++; 221 BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, 222 htonl(mac32), jt, jf); 223 } else if (hwaddr_len >= 2) { 224 maclen = sizeof(mac16); 225 memcpy(&mac16, hwaddr, maclen); 226 BPF_SET_STMT(bp, BPF_LD + BPF_H + BPF_IND, off); 227 bp++; 228 BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, 229 htons(mac16), jt, jf); 230 } else { 231 maclen = sizeof(*hwaddr); 232 BPF_SET_STMT(bp, BPF_LD + BPF_B + BPF_IND, off); 233 bp++; 234 BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, *hwaddr, jt, 235 jf); 236 } 237 if (jt) 238 jt = (uint8_t)(jt - 2); 239 if (jf) 240 jf = (uint8_t)(jf - 2); 241 bp++; 242 } 243 244 /* Last step is always return failure. 245 * Next step is a positive finish. */ 246 BPF_SET_STMT(bp, BPF_RET + BPF_K, 0); 247 bp++; 248 249 return (unsigned int)(bp - bpf); 250 } 251 #endif 252 253 #ifdef ARP 254 static const struct bpf_insn bpf_arp_ether[] = { 255 /* Check this is an ARP packet. */ 256 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 257 offsetof(struct ether_header, ether_type)), 258 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 1, 0), 259 BPF_STMT(BPF_RET + BPF_K, 0), 260 261 /* Load frame header length into X */ 262 BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, sizeof(struct ether_header)), 263 264 /* Make sure the hardware type matches. */ 265 BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_hrd)), 266 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), 267 BPF_STMT(BPF_RET + BPF_K, 0), 268 269 /* Make sure the hardware length matches. */ 270 BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_hln)), 271 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 272 sizeof(((struct ether_header *)0)->ether_shost), 1, 0), 273 BPF_STMT(BPF_RET + BPF_K, 0), 274 }; 275 #define BPF_ARP_ETHER_LEN __arraycount(bpf_arp_ether) 276 277 static const struct bpf_insn bpf_arp_filter[] = { 278 /* Make sure this is for IP. */ 279 BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_pro)), 280 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), 281 BPF_STMT(BPF_RET + BPF_K, 0), 282 /* Make sure this is an ARP REQUEST. */ 283 BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_op)), 284 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0), 285 /* or ARP REPLY. */ 286 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), 287 BPF_STMT(BPF_RET + BPF_K, 0), 288 /* Make sure the protocol length matches. */ 289 BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_pln)), 290 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(in_addr_t), 1, 0), 291 BPF_STMT(BPF_RET + BPF_K, 0), 292 }; 293 #define BPF_ARP_FILTER_LEN __arraycount(bpf_arp_filter) 294 295 /* One address is two checks of two statements. */ 296 #define BPF_NADDRS 1 297 #define BPF_ARP_ADDRS_LEN 5 + ((BPF_NADDRS * 2) * 2) 298 299 #define BPF_ARP_LEN \ 300 BPF_ARP_ETHER_LEN + BPF_ARP_FILTER_LEN + BPF_CMP_HWADDR_LEN + \ 301 BPF_ARP_ADDRS_LEN 302 303 static int 304 bpf_arp_rw(const struct bpf *bpf, const struct in_addr *ia, bool recv) 305 { 306 const struct interface *ifp = bpf->bpf_ifp; 307 struct bpf_insn buf[BPF_ARP_LEN + 1]; 308 struct bpf_insn *bp; 309 uint16_t arp_len; 310 unsigned int len; 311 312 bp = buf; 313 /* Check frame header. */ 314 switch (ifp->hwtype) { 315 case ARPHRD_ETHER: 316 memcpy(bp, bpf_arp_ether, sizeof(bpf_arp_ether)); 317 bp += BPF_ARP_ETHER_LEN; 318 arp_len = sizeof(struct ether_header) + sizeof(struct arphdr) + 319 ((sizeof(((struct ether_header *)0)->ether_shost) + 320 sizeof(uint32_t)) * 321 2); 322 break; 323 default: 324 errno = EINVAL; 325 return -1; 326 } 327 328 /* Copy in the main filter. */ 329 memcpy(bp, bpf_arp_filter, sizeof(bpf_arp_filter)); 330 bp += BPF_ARP_FILTER_LEN; 331 332 /* Ensure it's not from us. */ 333 bp += bpf_cmp_hwaddr(bp, BPF_CMP_HWADDR_LEN, sizeof(struct arphdr), 334 !recv, ifp->hwaddr, ifp->hwlen); 335 336 /* Match sender protocol address */ 337 BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, 338 sizeof(struct arphdr) + ifp->hwlen); 339 bp++; 340 BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htonl(ia->s_addr), 0, 1); 341 bp++; 342 BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len); 343 bp++; 344 345 /* If we didn't match sender, then we're only interested in 346 * ARP probes to us, so check the null host sender. */ 347 BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, INADDR_ANY, 1, 0); 348 bp++; 349 BPF_SET_STMT(bp, BPF_RET + BPF_K, 0); 350 bp++; 351 352 /* Match target protocol address */ 353 BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, 354 (sizeof(struct arphdr) + (size_t)(ifp->hwlen * 2) + 355 sizeof(in_addr_t))); 356 bp++; 357 BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htonl(ia->s_addr), 0, 1); 358 bp++; 359 BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len); 360 bp++; 361 362 /* No match, drop it */ 363 BPF_SET_STMT(bp, BPF_RET + BPF_K, 0); 364 bp++; 365 366 len = (unsigned int)(bp - buf); 367 if (recv) 368 return bpf_setfilter(bpf, buf, len); 369 return bpf_setwfilter(bpf, buf, len); 370 } 371 372 int 373 bpf_filter_arp(const struct bpf *bpf, const struct in_addr *ia) 374 { 375 if (bpf_arp_rw(bpf, ia, true) == -1) 376 return -1; 377 if (bpf_arp_rw(bpf, ia, false) == -1 && errno != ENOSYS) 378 return -1; 379 if (bpf_lockfilter(bpf) == -1 && errno != ENOSYS) 380 return -1; 381 return 0; 382 } 383 #endif 384 385 #ifdef ARPHRD_NONE 386 static const struct bpf_insn bpf_bootp_none[] = {}; 387 #define BPF_BOOTP_NONE_LEN __arraycount(bpf_bootp_none) 388 #endif 389 390 static const struct bpf_insn bpf_bootp_ether[] = { 391 /* Make sure this is an IP packet. */ 392 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 393 offsetof(struct ether_header, ether_type)), 394 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), 395 BPF_STMT(BPF_RET + BPF_K, 0), 396 397 /* Advance to the IP header. */ 398 BPF_STMT(BPF_LDX + BPF_K, sizeof(struct ether_header)), 399 }; 400 #define BPF_BOOTP_ETHER_LEN __arraycount(bpf_bootp_ether) 401 402 static const struct bpf_insn bpf_bootp_base[] = { 403 /* Make sure it's an IPv4 packet. */ 404 BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0), 405 BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0xf0), 406 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x40, 1, 0), 407 BPF_STMT(BPF_RET + BPF_K, 0), 408 409 /* Make sure it's a UDP packet. */ 410 BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct ip, ip_p)), 411 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0), 412 BPF_STMT(BPF_RET + BPF_K, 0), 413 414 /* Make sure this isn't a fragment. */ 415 BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct ip, ip_off)), 416 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 0, 1), 417 BPF_STMT(BPF_RET + BPF_K, 0), 418 419 /* Advance to the UDP header. */ 420 BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0), 421 BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x0f), 422 BPF_STMT(BPF_ALU + BPF_MUL + BPF_K, 4), 423 BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0), 424 BPF_STMT(BPF_MISC + BPF_TAX, 0), 425 }; 426 #define BPF_BOOTP_BASE_LEN __arraycount(bpf_bootp_base) 427 428 static const struct bpf_insn bpf_bootp_read[] = { 429 /* Make sure it's to the right port. 430 * RFC2131 makes no mention of enforcing a source port. */ 431 BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct udphdr, uh_dport)), 432 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTPC, 1, 0), 433 BPF_STMT(BPF_RET + BPF_K, 0), 434 }; 435 #define BPF_BOOTP_READ_LEN __arraycount(bpf_bootp_read) 436 437 static const struct bpf_insn bpf_bootp_write[] = { 438 /* Make sure it's from and to the right port. 439 * RFC2131 makes no mention of encforcing a source port, 440 * but dhcpcd does enforce it for sending. */ 441 BPF_STMT(BPF_LD + BPF_W + BPF_IND, 0), 442 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (BOOTPC << 16) + BOOTPS, 1, 0), 443 BPF_STMT(BPF_RET + BPF_K, 0), 444 }; 445 #define BPF_BOOTP_WRITE_LEN __arraycount(bpf_bootp_write) 446 447 #define BPF_BOOTP_CHADDR_LEN ((BOOTP_CHADDR_LEN / 4) * 3) 448 #define BPF_BOOTP_XID_LEN 4 /* BOUND check is 4 instructions */ 449 450 #define BPF_BOOTP_LEN \ 451 BPF_BOOTP_ETHER_LEN + BPF_BOOTP_BASE_LEN + BPF_BOOTP_READ_LEN + \ 452 BPF_BOOTP_XID_LEN + BPF_BOOTP_CHADDR_LEN + 4 453 454 static int 455 bpf_bootp_rw(const struct bpf *bpf, bool read) 456 { 457 struct bpf_insn buf[BPF_BOOTP_LEN + 1]; 458 struct bpf_insn *bp; 459 460 bp = buf; 461 /* Check frame header. */ 462 switch (bpf->bpf_ifp->hwtype) { 463 #ifdef ARPHRD_NONE 464 case ARPHRD_NONE: 465 memcpy(bp, bpf_bootp_none, sizeof(bpf_bootp_none)); 466 bp += BPF_BOOTP_NONE_LEN; 467 break; 468 #endif 469 case ARPHRD_ETHER: 470 memcpy(bp, bpf_bootp_ether, sizeof(bpf_bootp_ether)); 471 bp += BPF_BOOTP_ETHER_LEN; 472 break; 473 default: 474 errno = EINVAL; 475 return -1; 476 } 477 478 /* Copy in the main filter. */ 479 memcpy(bp, bpf_bootp_base, sizeof(bpf_bootp_base)); 480 bp += BPF_BOOTP_BASE_LEN; 481 482 if (!read) { 483 memcpy(bp, bpf_bootp_write, sizeof(bpf_bootp_write)); 484 bp += BPF_BOOTP_WRITE_LEN; 485 486 /* All passed, return the packet. */ 487 BPF_SET_STMT(bp, BPF_RET + BPF_K, BPF_WHOLEPACKET); 488 bp++; 489 490 return bpf_setwfilter(bpf, buf, (unsigned int)(bp - buf)); 491 } 492 493 memcpy(bp, bpf_bootp_read, sizeof(bpf_bootp_read)); 494 bp += BPF_BOOTP_READ_LEN; 495 496 /* All passed, return the packet. */ 497 BPF_SET_STMT(bp, BPF_RET + BPF_K, BPF_WHOLEPACKET); 498 bp++; 499 500 return bpf_setfilter(bpf, buf, (unsigned int)(bp - buf)); 501 } 502 503 int 504 bpf_filter_bootp(const struct bpf *bpf, __unused const struct in_addr *ia) 505 { 506 if (bpf_bootp_rw(bpf, true) == -1) 507 return -1; 508 if (bpf_bootp_rw(bpf, false) == -1 && errno != ENOSYS) 509 return -1; 510 if (bpf_lockfilter(bpf) == -1 && errno != ENOSYS) 511 return -1; 512 return 0; 513 } 514