1 /* $OpenBSD: bpf.c,v 1.13 2004/05/05 14:28:58 deraadt Exp $ */ 2 3 /* BPF socket interface code, originally contributed by Archie Cobbs. */ 4 5 /*- 6 * SPDX-License-Identifier: BSD-3-Clause 7 * 8 * Copyright (c) 2021 Franco Fichtner <franco@opnsense.org> 9 * Copyright (c) 1995, 1996, 1998, 1999 10 * The Internet Software Consortium. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of The Internet Software Consortium nor the names 22 * of its contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 26 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 27 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 28 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 30 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 33 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 34 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 36 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * This software has been written for the Internet Software Consortium 40 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 41 * Enterprises. To learn more about the Internet Software Consortium, 42 * see ``http://www.vix.com/isc''. To learn more about Vixie 43 * Enterprises, see ``http://www.vix.com''. 44 */ 45 46 #include <sys/cdefs.h> 47 __FBSDID("$FreeBSD$"); 48 49 #include "dhcpd.h" 50 #include "privsep.h" 51 #include <sys/capsicum.h> 52 #include <sys/ioctl.h> 53 #include <sys/uio.h> 54 55 #include <net/bpf.h> 56 #include <netinet/in_systm.h> 57 #include <netinet/ip.h> 58 #include <netinet/udp.h> 59 #include <netinet/if_ether.h> 60 61 #include <capsicum_helpers.h> 62 63 #define BPF_FORMAT "/dev/bpf%d" 64 65 /* 66 * Called by get_interface_list for each interface that's discovered. 67 * Opens a packet filter for each interface and adds it to the select 68 * mask. 69 */ 70 int 71 if_register_bpf(struct interface_info *info, int flags) 72 { 73 char filename[50]; 74 int sock, b; 75 76 /* Open a BPF device */ 77 for (b = 0;; b++) { 78 snprintf(filename, sizeof(filename), BPF_FORMAT, b); 79 sock = open(filename, flags); 80 if (sock < 0) { 81 if (errno == EBUSY) 82 continue; 83 else 84 error("Can't find free bpf: %m"); 85 } else 86 break; 87 } 88 89 /* Set the BPF device to point at this interface. */ 90 if (ioctl(sock, BIOCSETIF, info->ifp) < 0) 91 error("Can't attach interface %s to bpf device %s: %m", 92 info->name, filename); 93 94 /* Tag the packets with the proper VLAN PCP setting. */ 95 if (info->client->config->vlan_pcp != 0) { 96 if (ioctl(sock, BIOCSETVLANPCP, 97 &info->client->config->vlan_pcp) < 0) 98 error( "Can't set the VLAN PCP tag on interface %s: %m", 99 info->name); 100 } 101 102 return (sock); 103 } 104 105 /* 106 * Packet write filter program: 107 * 'ip and udp and src port bootps and dst port (bootps or bootpc)' 108 */ 109 static const struct bpf_insn dhcp_bpf_wfilter[] = { 110 BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14), 111 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12), 112 113 /* Make sure this is an IP packet... */ 114 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), 115 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10), 116 117 /* Make sure it's a UDP packet... */ 118 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23), 119 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8), 120 121 /* Make sure this isn't a fragment... */ 122 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), 123 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, IP_MF|IP_OFFMASK, 6, 0), 124 125 /* Get the IP header length... */ 126 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14), 127 128 /* Make sure it's from the right port... */ 129 BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14), 130 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, LOCAL_PORT, 0, 3), 131 132 /* Make sure it is to the right ports ... */ 133 BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16), 134 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, REMOTE_PORT, 0, 1), 135 136 /* If we passed all the tests, ask for the whole packet. */ 137 BPF_STMT(BPF_RET+BPF_K, (u_int)-1), 138 139 /* Otherwise, drop it. */ 140 BPF_STMT(BPF_RET+BPF_K, 0), 141 }; 142 143 void 144 if_register_send(struct interface_info *info) 145 { 146 cap_rights_t rights; 147 struct bpf_version v; 148 struct bpf_program p; 149 int sock, on = 1; 150 151 /* Open a BPF device and hang it on this interface... */ 152 info->wfdesc = if_register_bpf(info, O_WRONLY); 153 154 /* Make sure the BPF version is in range... */ 155 if (ioctl(info->wfdesc, BIOCVERSION, &v) < 0) 156 error("Can't get BPF version: %m"); 157 158 if (v.bv_major != BPF_MAJOR_VERSION || 159 v.bv_minor < BPF_MINOR_VERSION) 160 error("Kernel BPF version out of range - recompile dhcpd!"); 161 162 /* Set up the bpf write filter program structure. */ 163 p.bf_insns = __DECONST(struct bpf_insn *, dhcp_bpf_wfilter); 164 p.bf_len = nitems(dhcp_bpf_wfilter); 165 166 if (ioctl(info->wfdesc, BIOCSETWF, &p) < 0) 167 error("Can't install write filter program: %m"); 168 169 if (ioctl(info->wfdesc, BIOCLOCK, NULL) < 0) 170 error("Cannot lock bpf"); 171 172 cap_rights_init(&rights, CAP_WRITE); 173 if (caph_rights_limit(info->wfdesc, &rights) < 0) 174 error("Can't limit bpf descriptor: %m"); 175 176 /* 177 * Use raw socket for unicast send. 178 */ 179 if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1) 180 error("socket(SOCK_RAW): %m"); 181 if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, 182 sizeof(on)) == -1) 183 error("setsockopt(IP_HDRINCL): %m"); 184 info->ufdesc = sock; 185 } 186 187 /* 188 * Packet filter program... 189 */ 190 static const struct bpf_insn dhcp_bpf_filter[] = { 191 /* Use relative index (0) for IP packet... */ 192 BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, 0), 193 194 /* 195 * Test whether this is a VLAN packet... 196 * 197 * In case the server packet is using a VLAN ID 198 * of 0, meaning an untagged priority was set, the 199 * response shall be read and replied to. 200 */ 201 BPF_STMT(BPF_LD + BPF_H + BPF_IND, 12), 202 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_VLAN, 0, 4), 203 204 /* Test whether it has a VID of 0 */ 205 BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14), 206 BPF_STMT(BPF_ALU + BPF_AND + BPF_K, EVL_VLID_MASK), 207 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 17), 208 209 /* Correct the relative index for VLAN packet (4)... */ 210 BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, 4), 211 212 /* Make sure this is an IP packet... */ 213 BPF_STMT(BPF_LD + BPF_H + BPF_IND, 12), 214 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 14), 215 216 /* Make sure it's a UDP packet... */ 217 BPF_STMT(BPF_LD + BPF_B + BPF_IND, 23), 218 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 12), 219 220 /* Make sure this isn't a fragment... */ 221 BPF_STMT(BPF_LD + BPF_H + BPF_IND, 20), 222 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, IP_MF|IP_OFFMASK, 10, 0), 223 224 /* 225 * Get the IP header length... 226 * 227 * To find the correct position of the IP header 228 * length field store the index (0 or 4) in the 229 * accumulator and compare it with 0. 230 */ 231 BPF_STMT(BPF_MISC + BPF_TXA, 0), 232 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 2), 233 /* Store IP header length of IP packet in index. */ 234 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14), 235 /* Skip over following VLAN handling instruction. */ 236 BPF_JUMP(BPF_JMP + BPF_JA, 1, 0, 0), 237 /* Store IP header length of VLAN packet in index. */ 238 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 18), 239 /* Add IP header length to previous relative index. */ 240 BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0), 241 /* Move result back to index to reach UDP header below. */ 242 BPF_STMT(BPF_MISC + BPF_TAX, 0), 243 244 /* Make sure it's to the right port... */ 245 BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16), 246 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, LOCAL_PORT, 0, 1), 247 248 /* If we passed all the tests, ask for the whole packet. */ 249 BPF_STMT(BPF_RET+BPF_K, (u_int)-1), 250 251 /* Otherwise, drop it. */ 252 BPF_STMT(BPF_RET+BPF_K, 0), 253 }; 254 255 void 256 if_register_receive(struct interface_info *info) 257 { 258 static const unsigned long cmds[2] = { SIOCGIFFLAGS, SIOCGIFMEDIA }; 259 cap_rights_t rights; 260 struct bpf_version v; 261 struct bpf_program p; 262 int flag = 1, sz; 263 264 /* Open a BPF device and hang it on this interface... */ 265 info->rfdesc = if_register_bpf(info, O_RDONLY); 266 267 /* Make sure the BPF version is in range... */ 268 if (ioctl(info->rfdesc, BIOCVERSION, &v) < 0) 269 error("Can't get BPF version: %m"); 270 271 if (v.bv_major != BPF_MAJOR_VERSION || 272 v.bv_minor < BPF_MINOR_VERSION) 273 error("Kernel BPF version out of range - recompile dhcpd!"); 274 275 /* 276 * Set immediate mode so that reads return as soon as a packet 277 * comes in, rather than waiting for the input buffer to fill 278 * with packets. 279 */ 280 if (ioctl(info->rfdesc, BIOCIMMEDIATE, &flag) < 0) 281 error("Can't set immediate mode on bpf device: %m"); 282 283 /* Get the required BPF buffer length from the kernel. */ 284 if (ioctl(info->rfdesc, BIOCGBLEN, &sz) < 0) 285 error("Can't get bpf buffer length: %m"); 286 info->rbuf_max = sz; 287 info->rbuf = malloc(info->rbuf_max); 288 if (!info->rbuf) 289 error("Can't allocate %lu bytes for bpf input buffer.", 290 (unsigned long)info->rbuf_max); 291 info->rbuf_offset = 0; 292 info->rbuf_len = 0; 293 294 /* Set up the bpf filter program structure. */ 295 p.bf_insns = __DECONST(struct bpf_insn *, dhcp_bpf_filter); 296 p.bf_len = nitems(dhcp_bpf_filter); 297 298 if (ioctl(info->rfdesc, BIOCSETF, &p) < 0) 299 error("Can't install packet filter program: %m"); 300 301 if (ioctl(info->rfdesc, BIOCLOCK, NULL) < 0) 302 error("Cannot lock bpf"); 303 304 cap_rights_init(&rights, CAP_IOCTL, CAP_EVENT, CAP_READ); 305 if (caph_rights_limit(info->rfdesc, &rights) < 0) 306 error("Can't limit bpf descriptor: %m"); 307 if (caph_ioctls_limit(info->rfdesc, cmds, 2) < 0) 308 error("Can't limit ioctls for bpf descriptor: %m"); 309 } 310 311 void 312 send_packet_unpriv(int privfd, struct dhcp_packet *raw, size_t len, 313 struct in_addr from, struct in_addr to) 314 { 315 struct imsg_hdr hdr; 316 struct buf *buf; 317 int errs; 318 319 hdr.code = IMSG_SEND_PACKET; 320 hdr.len = sizeof(hdr) + 321 sizeof(size_t) + len + 322 sizeof(from) + sizeof(to); 323 324 if ((buf = buf_open(hdr.len)) == NULL) 325 error("buf_open: %m"); 326 327 errs = 0; 328 errs += buf_add(buf, &hdr, sizeof(hdr)); 329 errs += buf_add(buf, &len, sizeof(len)); 330 errs += buf_add(buf, raw, len); 331 errs += buf_add(buf, &from, sizeof(from)); 332 errs += buf_add(buf, &to, sizeof(to)); 333 if (errs) 334 error("buf_add: %m"); 335 336 if (buf_close(privfd, buf) == -1) 337 error("buf_close: %m"); 338 } 339 340 void 341 send_packet_priv(struct interface_info *interface, struct imsg_hdr *hdr, int fd) 342 { 343 unsigned char buf[256]; 344 struct iovec iov[2]; 345 struct msghdr msg; 346 struct dhcp_packet raw; 347 size_t len; 348 struct in_addr from, to; 349 int result, bufp = 0; 350 351 if (hdr->len < sizeof(*hdr) + sizeof(size_t)) 352 error("corrupted message received"); 353 buf_read(fd, &len, sizeof(len)); 354 if (hdr->len != sizeof(*hdr) + sizeof(size_t) + len + 355 sizeof(from) + sizeof(to)) { 356 error("corrupted message received"); 357 } 358 if (len > sizeof(raw)) 359 error("corrupted message received"); 360 buf_read(fd, &raw, len); 361 buf_read(fd, &from, sizeof(from)); 362 buf_read(fd, &to, sizeof(to)); 363 364 /* Assemble the headers... */ 365 if (to.s_addr == INADDR_BROADCAST) 366 assemble_hw_header(interface, buf, &bufp); 367 assemble_udp_ip_header(buf, &bufp, from.s_addr, to.s_addr, 368 htons(REMOTE_PORT), (unsigned char *)&raw, len); 369 370 iov[0].iov_base = buf; 371 iov[0].iov_len = bufp; 372 iov[1].iov_base = &raw; 373 iov[1].iov_len = len; 374 375 /* Fire it off */ 376 if (to.s_addr == INADDR_BROADCAST) 377 result = writev(interface->wfdesc, iov, 2); 378 else { 379 struct sockaddr_in sato; 380 381 sato.sin_addr = to; 382 sato.sin_port = htons(REMOTE_PORT); 383 sato.sin_family = AF_INET; 384 sato.sin_len = sizeof(sato); 385 386 memset(&msg, 0, sizeof(msg)); 387 msg.msg_name = (struct sockaddr *)&sato; 388 msg.msg_namelen = sizeof(sato); 389 msg.msg_iov = iov; 390 msg.msg_iovlen = 2; 391 result = sendmsg(interface->ufdesc, &msg, 0); 392 } 393 394 if (result < 0) 395 warning("send_packet: %m"); 396 } 397 398 ssize_t 399 receive_packet(struct interface_info *interface, unsigned char *buf, 400 size_t len, struct sockaddr_in *from, struct hardware *hfrom) 401 { 402 int length = 0, offset = 0; 403 struct bpf_hdr hdr; 404 405 /* 406 * All this complexity is because BPF doesn't guarantee that 407 * only one packet will be returned at a time. We're getting 408 * what we deserve, though - this is a terrible abuse of the BPF 409 * interface. Sigh. 410 */ 411 412 /* Process packets until we get one we can return or until we've 413 * done a read and gotten nothing we can return... 414 */ 415 do { 416 /* If the buffer is empty, fill it. */ 417 if (interface->rbuf_offset >= interface->rbuf_len) { 418 length = read(interface->rfdesc, interface->rbuf, 419 interface->rbuf_max); 420 if (length <= 0) 421 return (length); 422 interface->rbuf_offset = 0; 423 interface->rbuf_len = length; 424 } 425 426 /* 427 * If there isn't room for a whole bpf header, something 428 * went wrong, but we'll ignore it and hope it goes 429 * away... XXX 430 */ 431 if (interface->rbuf_len - interface->rbuf_offset < 432 sizeof(hdr)) { 433 interface->rbuf_offset = interface->rbuf_len; 434 continue; 435 } 436 437 /* Copy out a bpf header... */ 438 memcpy(&hdr, &interface->rbuf[interface->rbuf_offset], 439 sizeof(hdr)); 440 441 /* 442 * If the bpf header plus data doesn't fit in what's 443 * left of the buffer, stick head in sand yet again... 444 */ 445 if (interface->rbuf_offset + hdr.bh_hdrlen + hdr.bh_caplen > 446 interface->rbuf_len) { 447 interface->rbuf_offset = interface->rbuf_len; 448 continue; 449 } 450 451 /* Skip over the BPF header... */ 452 interface->rbuf_offset += hdr.bh_hdrlen; 453 454 /* 455 * If the captured data wasn't the whole packet, or if 456 * the packet won't fit in the input buffer, all we can 457 * do is drop it. 458 */ 459 if (hdr.bh_caplen != hdr.bh_datalen) { 460 interface->rbuf_offset = 461 BPF_WORDALIGN(interface->rbuf_offset + 462 hdr.bh_caplen); 463 continue; 464 } 465 466 /* Decode the physical header... */ 467 offset = decode_hw_header(interface->rbuf, 468 interface->rbuf_offset, hfrom); 469 470 /* 471 * If a physical layer checksum failed (dunno of any 472 * physical layer that supports this, but WTH), skip 473 * this packet. 474 */ 475 if (offset < 0) { 476 interface->rbuf_offset = 477 BPF_WORDALIGN(interface->rbuf_offset + 478 hdr.bh_caplen); 479 continue; 480 } 481 interface->rbuf_offset += offset; 482 hdr.bh_caplen -= offset; 483 484 /* Decode the IP and UDP headers... */ 485 offset = decode_udp_ip_header(interface->rbuf, 486 interface->rbuf_offset, from, NULL, hdr.bh_caplen); 487 488 /* If the IP or UDP checksum was bad, skip the packet... */ 489 if (offset < 0) { 490 interface->rbuf_offset = 491 BPF_WORDALIGN(interface->rbuf_offset + 492 hdr.bh_caplen); 493 continue; 494 } 495 interface->rbuf_offset += offset; 496 hdr.bh_caplen -= offset; 497 498 /* 499 * If there's not enough room to stash the packet data, 500 * we have to skip it (this shouldn't happen in real 501 * life, though). 502 */ 503 if (hdr.bh_caplen > len) { 504 interface->rbuf_offset = 505 BPF_WORDALIGN(interface->rbuf_offset + 506 hdr.bh_caplen); 507 continue; 508 } 509 510 /* Copy out the data in the packet... */ 511 memcpy(buf, interface->rbuf + interface->rbuf_offset, 512 hdr.bh_caplen); 513 interface->rbuf_offset = 514 BPF_WORDALIGN(interface->rbuf_offset + 515 hdr.bh_caplen); 516 return (hdr.bh_caplen); 517 } while (!length); 518 return (0); 519 } 520