]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/dhclient/bpf.c
unbound: Vendor import 1.15.0
[FreeBSD/FreeBSD.git] / sbin / dhclient / bpf.c
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 }