1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2018-2024 Netflix 5 * Author: Maksim Yevmenkin <maksim.yevmenkin@gmail.com> 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/cdefs.h> 30 #define ACCEPT_FILTER_MOD 31 32 #include <sys/param.h> 33 #include <sys/kernel.h> 34 #include <sys/mbuf.h> 35 #include <sys/module.h> 36 #include <sys/signalvar.h> 37 #include <sys/sysctl.h> 38 #include <sys/socketvar.h> 39 40 static int sbfull(struct sockbuf *sb); 41 static uint8_t sbmget8(struct mbuf *m, int offset); 42 static int so_hastls(struct socket *so, void *arg, int waitflag); 43 44 ACCEPT_FILTER_DEFINE(accf_tls, "tlsready", so_hastls, NULL, NULL, 1); 45 46 static int 47 sbfull(struct sockbuf *sb) 48 { 49 50 return (sbused(sb) >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax); 51 } 52 53 static uint8_t 54 sbmget8(struct mbuf *m, int offset) 55 { 56 struct mbuf *n = m->m_nextpkt; 57 58 while (m != NULL && offset >= m->m_len) { 59 offset -= m->m_len; 60 m = m->m_next; 61 if (m == NULL) { 62 m = n; 63 n = m->m_nextpkt; 64 } 65 } 66 67 return *(mtod(m, uint8_t *) + offset); 68 } 69 70 static int 71 so_hastls(struct socket *so, void *arg, int waitflag) 72 { 73 struct sockbuf *sb = &so->so_rcv; 74 int avail; 75 uint16_t reclen; 76 77 if ((sb->sb_state & SBS_CANTRCVMORE) || sbfull(sb)) 78 return (SU_ISCONNECTED); /* can't wait any longer */ 79 80 /* 81 * struct { 82 * ContentType type; - 1 byte, 0x16 handshake 83 * ProtocolVersion version; - 2 bytes (major, minor) 84 * uint16 length; - 2 bytes, NBO, 2^14 max 85 * opaque fragment[TLSPlaintext.length]; 86 * } TLSPlaintext; 87 */ 88 89 /* Did we get at least 5 bytes */ 90 avail = sbavail(sb); 91 if (avail < 5) 92 return (SU_OK); /* nope */ 93 94 /* Does this look like TLS handshake? */ 95 if (sbmget8(sb->sb_mb, 0) != 0x16) 96 return (SU_ISCONNECTED); /* nope */ 97 98 /* Did we get a complete TLS record? */ 99 reclen = (uint16_t) sbmget8(sb->sb_mb, 3) << 8; 100 reclen |= (uint16_t) sbmget8(sb->sb_mb, 4); 101 102 if (reclen <= 16384 && avail < (int) 5 + reclen) 103 return (SU_OK); /* nope */ 104 105 return (SU_ISCONNECTED); 106 } 107