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