1 /* $OpenBSD: bpf.c,v 1.3 2019/03/18 00:00:59 dlg 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/types.h> 44 #include <sys/ioctl.h> 45 #include <sys/socket.h> 46 47 #include <net/bpf.h> 48 #include <net/if.h> 49 50 #include <netinet/in.h> 51 #include <netinet/if_ether.h> 52 53 #include <errno.h> 54 #include <fcntl.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <unistd.h> 59 60 #include "dhcp.h" 61 #include "dhcpd.h" 62 #include "log.h" 63 64 ssize_t send_packet_layer3(struct interface_info *, 65 void *, size_t, struct packet_ctx *); 66 67 /* 68 * Called by get_interface_list for each interface that's discovered. 69 * Opens a packet filter for each interface and adds it to the select 70 * mask. 71 */ 72 int 73 if_register_bpf(struct interface_info *info) 74 { 75 int sock; 76 77 /* Open the BPF device */ 78 if ((sock = open("/dev/bpf", O_RDWR)) == -1) 79 fatal("Can't open bpf device"); 80 81 /* Set the BPF device to point at this interface. */ 82 if (ioctl(sock, BIOCSETIF, &info->ifr) == -1) 83 fatal("Can't attach interface %s to bpf device", info->name); 84 85 return (sock); 86 } 87 88 void 89 if_register_send(struct interface_info *info) 90 { 91 /* 92 * If we're using the bpf API for sending and receiving, we 93 * don't need to register this interface twice. 94 */ 95 info->wfdesc = info->rfdesc; 96 } 97 98 /* DHCPv6 BPF filters. */ 99 100 /* 101 * Packet filter program: 'ip6 and udp and dst port DHCP6_SERVER_PORT' 102 */ 103 struct bpf_insn dhcp6_bpf_sfilter[] = { 104 /* Make sure this is an IP packet... */ 105 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), 106 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IPV6, 0, 5), 107 108 /* Make sure this is an UDP packet. */ 109 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 20), 110 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 3), 111 112 /* Make sure it is the right port. */ 113 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 56), 114 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP6_SERVER_PORT, 0, 1), 115 116 /* If we passed all the tests, ask for the whole packet. */ 117 BPF_STMT(BPF_RET + BPF_K, (u_int)-1), 118 119 /* Otherwise, drop it. */ 120 BPF_STMT(BPF_RET + BPF_K, 0), 121 }; 122 123 int dhcp6_bpf_sfilter_len = sizeof(dhcp6_bpf_sfilter) / sizeof(struct bpf_insn); 124 125 /* 126 * Packet filter program: 'ip6 and udp' 127 */ 128 struct bpf_insn dhcp6_bpf_wfilter[] = { 129 /* Make sure this is an IP packet... */ 130 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), 131 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IPV6, 0, 3), 132 133 /* Make sure this is an UDP packet. */ 134 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 20), 135 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 1), 136 137 /* If we passed all the tests, ask for the whole packet. */ 138 BPF_STMT(BPF_RET + BPF_K, (u_int)-1), 139 140 /* Otherwise, drop it. */ 141 BPF_STMT(BPF_RET + BPF_K, 0), 142 }; 143 144 int dhcp6_bpf_wfilter_len = sizeof(dhcp6_bpf_wfilter) / sizeof(struct bpf_insn); 145 146 147 void 148 if_register_receive(struct interface_info *info) 149 { 150 struct bpf_version v; 151 struct bpf_program p; 152 int flag = 1, sz, cmplt = 0; 153 154 /* Open a BPF device and hang it on this interface... */ 155 info->rfdesc = if_register_bpf(info); 156 157 /* Make sure the BPF version is in range... */ 158 if (ioctl(info->rfdesc, BIOCVERSION, &v) == -1) 159 fatal("Can't get BPF version"); 160 161 if (v.bv_major != BPF_MAJOR_VERSION || 162 v.bv_minor < BPF_MINOR_VERSION) 163 fatalx("Kernel BPF version out of range - recompile dhcpd!"); 164 165 /* 166 * Set immediate mode so that reads return as soon as a packet 167 * comes in, rather than waiting for the input buffer to fill 168 * with packets. 169 */ 170 if (ioctl(info->rfdesc, BIOCIMMEDIATE, &flag) == -1) 171 fatal("Can't set immediate mode on bpf device"); 172 173 /* make sure kernel fills in the source ethernet address */ 174 if (ioctl(info->rfdesc, BIOCSHDRCMPLT, &cmplt) == -1) 175 fatal("Can't set header complete flag on bpf device"); 176 177 /* Get the required BPF buffer length from the kernel. */ 178 if (ioctl(info->rfdesc, BIOCGBLEN, &sz) == -1) 179 fatal("Can't get bpf buffer length"); 180 info->rbuf_max = sz; 181 info->rbuf = malloc(info->rbuf_max); 182 if (!info->rbuf) 183 fatalx("Can't allocate %lu bytes for bpf input buffer.", 184 (unsigned long)info->rbuf_max); 185 info->rbuf_offset = 0; 186 info->rbuf_len = 0; 187 188 /* Set up the bpf filter program structure. */ 189 p.bf_len = dhcp6_bpf_sfilter_len; 190 p.bf_insns = dhcp6_bpf_sfilter; 191 if (ioctl(info->rfdesc, BIOCSETF, &p) == -1) 192 fatal("Can't install packet filter program"); 193 194 /* Set up the bpf write filter program structure. */ 195 p.bf_len = dhcp6_bpf_wfilter_len; 196 p.bf_insns = dhcp6_bpf_wfilter; 197 if (ioctl(info->rfdesc, BIOCSETWF, &p) == -1) 198 fatal("Can't install write filter program"); 199 200 /* Only get input packets. */ 201 flag = BPF_DIRECTION_OUT; 202 if (ioctl(info->rfdesc, BIOCSDIRFILT , &flag) == -1) 203 fatal("Can't set BPF direction capture"); 204 205 /* Drop them so they don't go up in the network stack. */ 206 flag = BPF_FILDROP_CAPTURE; 207 if (ioctl(info->rfdesc, BIOCSFILDROP, &flag) == -1) 208 fatal("Can't set BPF filter drop"); 209 210 /* make sure these settings cannot be changed after dropping privs */ 211 if (ioctl(info->rfdesc, BIOCLOCK) == -1) 212 fatal("Failed to lock bpf descriptor"); 213 } 214 215 ssize_t 216 send_packet_layer3(struct interface_info *intf, void *raw, size_t len, 217 struct packet_ctx *pc) 218 { 219 struct cmsghdr *cmsg; 220 ssize_t sendlen; 221 struct msghdr msg; 222 struct in6_pktinfo *ipi6; 223 struct sockaddr_storage ss; 224 struct iovec iov[2]; 225 uint8_t cmsgbuf[ 226 CMSG_SPACE(sizeof(struct in6_pktinfo)) 227 ]; 228 229 log_debug(" sending %ld bytes to %s:%d via %s", 230 len, v6addr2str(&ss2sin6(&pc->pc_dst)->sin6_addr), 231 ntohs(ss2sin6(&pc->pc_dst)->sin6_port), intf->name); 232 233 memset(&msg, 0, sizeof(msg)); 234 iov[0].iov_base = raw; 235 iov[0].iov_len = len; 236 msg.msg_iov = iov; 237 msg.msg_iovlen = 1; 238 239 ss = pc->pc_dst; 240 ss2sin6(&ss)->sin6_scope_id = intf->index; 241 msg.msg_name = &ss; 242 msg.msg_namelen = ss.ss_len; 243 244 /* If binded to multicast we should select an interface. */ 245 if (IN6_IS_ADDR_MULTICAST(&ss2sin6(&ss)->sin6_addr)) { 246 memset(cmsgbuf, 0, sizeof(cmsgbuf)); 247 msg.msg_control = cmsgbuf; 248 msg.msg_controllen = sizeof(cmsgbuf); 249 250 /* Use the IPV6_PKTINFO to select the interface. */ 251 cmsg = (struct cmsghdr *)CMSG_FIRSTHDR(&msg); 252 cmsg->cmsg_len = CMSG_LEN(sizeof(*ipi6)); 253 cmsg->cmsg_level = IPPROTO_IPV6; 254 cmsg->cmsg_type = IPV6_PKTINFO; 255 256 ipi6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); 257 ipi6->ipi6_ifindex = intf->index; 258 } 259 260 if ((sendlen = sendmsg(pc->pc_sd, &msg, 0)) == -1) { 261 log_warn(" failed to send message"); 262 return -1; 263 } 264 if (sendlen < (ssize_t)len) 265 log_warnx(" sent less bytes than expected (%ld < %ld)", 266 sendlen, len); 267 268 return sendlen; 269 } 270 271 ssize_t 272 send_packet(struct interface_info *interface, 273 void *raw, size_t len, struct packet_ctx *pc) 274 { 275 unsigned char buf[256]; 276 struct iovec iov[2]; 277 int result, bufp = 0; 278 279 if (pc->pc_sd != 0) 280 return send_packet_layer3(interface, raw, len, pc); 281 282 /* Assemble the headers... */ 283 assemble_hw_header(buf, &bufp, pc); 284 assemble_udp_ip6_header(buf, &bufp, pc, raw, len); 285 286 /* Fire it off */ 287 iov[0].iov_base = (char *)buf; 288 iov[0].iov_len = bufp; 289 iov[1].iov_base = (char *)raw; 290 iov[1].iov_len = len; 291 292 result = writev(interface->wfdesc, iov, 2); 293 if (result == -1) 294 log_warn("send_packet"); 295 296 return (result); 297 } 298 299 ssize_t 300 receive_packet(struct interface_info *interface, unsigned char *buf, 301 size_t len, struct packet_ctx *pc) 302 { 303 int length = 0, offset = 0; 304 struct bpf_hdr hdr; 305 306 /* 307 * All this complexity is because BPF doesn't guarantee that 308 * only one packet will be returned at a time. We're getting 309 * what we deserve, though - this is a terrible abuse of the BPF 310 * interface. Sigh. 311 */ 312 313 /* Process packets until we get one we can return or until we've 314 * done a read and gotten nothing we can return... 315 */ 316 do { 317 /* If the buffer is empty, fill it. */ 318 if (interface->rbuf_offset == interface->rbuf_len) { 319 length = read(interface->rfdesc, interface->rbuf, 320 interface->rbuf_max); 321 if (length <= 0) 322 return (length); 323 interface->rbuf_offset = 0; 324 interface->rbuf_len = length; 325 } 326 327 /* 328 * If there isn't room for a whole bpf header, something 329 * went wrong, but we'll ignore it and hope it goes 330 * away... XXX 331 */ 332 if (interface->rbuf_len - interface->rbuf_offset < 333 sizeof(hdr)) { 334 interface->rbuf_offset = interface->rbuf_len; 335 continue; 336 } 337 338 /* Copy out a bpf header... */ 339 memcpy(&hdr, &interface->rbuf[interface->rbuf_offset], 340 sizeof(hdr)); 341 342 /* 343 * If the bpf header plus data doesn't fit in what's 344 * left of the buffer, stick head in sand yet again... 345 */ 346 if (interface->rbuf_offset + hdr.bh_hdrlen + hdr.bh_caplen > 347 interface->rbuf_len) { 348 interface->rbuf_offset = interface->rbuf_len; 349 continue; 350 } 351 352 /* 353 * If the captured data wasn't the whole packet, or if 354 * the packet won't fit in the input buffer, all we can 355 * do is drop it. 356 */ 357 if (hdr.bh_caplen != hdr.bh_datalen) { 358 interface->rbuf_offset += hdr.bh_hdrlen = 359 hdr.bh_caplen; 360 continue; 361 } 362 363 /* Skip over the BPF header... */ 364 interface->rbuf_offset += hdr.bh_hdrlen; 365 366 /* Decode the physical header... */ 367 offset = decode_hw_header(interface->rbuf, 368 interface->rbuf_offset, pc); 369 370 /* 371 * If a physical layer checksum failed (dunno of any 372 * physical layer that supports this, but WTH), skip 373 * this packet. 374 */ 375 if (offset < 0) { 376 interface->rbuf_offset += hdr.bh_caplen; 377 continue; 378 } 379 interface->rbuf_offset += offset; 380 hdr.bh_caplen -= offset; 381 382 /* Decode the IP and UDP headers... */ 383 offset = decode_udp_ip6_header(interface->rbuf, 384 interface->rbuf_offset, pc, hdr.bh_caplen); 385 386 /* If the IP or UDP checksum was bad, skip the packet... */ 387 if (offset < 0) { 388 interface->rbuf_offset += hdr.bh_caplen; 389 continue; 390 } 391 interface->rbuf_offset += offset; 392 hdr.bh_caplen -= offset; 393 394 /* 395 * If there's not enough room to stash the packet data, 396 * we have to skip it (this shouldn't happen in real 397 * life, though). 398 */ 399 if (hdr.bh_caplen > len) { 400 interface->rbuf_offset += hdr.bh_caplen; 401 continue; 402 } 403 404 /* Copy out the data in the packet... */ 405 memcpy(buf, interface->rbuf + interface->rbuf_offset, 406 hdr.bh_caplen); 407 interface->rbuf_offset += hdr.bh_caplen; 408 return (hdr.bh_caplen); 409 } while (!length); 410 return (0); 411 } 412