diff options
Diffstat (limited to 'usr/src/uts/common/inet/kssl/ksslfilter.c')
-rw-r--r-- | usr/src/uts/common/inet/kssl/ksslfilter.c | 615 |
1 files changed, 0 insertions, 615 deletions
diff --git a/usr/src/uts/common/inet/kssl/ksslfilter.c b/usr/src/uts/common/inet/kssl/ksslfilter.c deleted file mode 100644 index ea9e2f9232..0000000000 --- a/usr/src/uts/common/inet/kssl/ksslfilter.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - */ - -#include <sys/systm.h> -#include <sys/cmn_err.h> -#include <sys/stropts.h> -#include <sys/strsun.h> -#include <sys/socketvar.h> -#include <sys/sockfilter.h> -#include <inet/kssl/ksslapi.h> -#include <sys/note.h> -#include <sys/taskq.h> - -/* - * Name of the KSSL filter - */ -#define KSSL_FILNAME "ksslf" - -static struct modlmisc ksslf_modlmisc = { - &mod_miscops, - "Kernel SSL socket filter" -}; - -static struct modlinkage ksslf_modlinkage = { - MODREV_1, - &ksslf_modlmisc, - NULL -}; - -/* - * kssl filter cookie - */ -typedef struct ksslf { - boolean_t ksslf_pending; /* waiting for 1st SSL rec. */ - boolean_t ksslf_inhandshake; /* during SSL handshake */ - kssl_ent_t ksslf_ent; /* SSL table entry */ - kssl_ctx_t ksslf_ctx; /* SSL session */ - kssl_endpt_type_t ksslf_type; /* is proxy/is proxied/none */ - struct sockaddr_in6 ksslf_laddr; /* local address */ - socklen_t ksslf_laddrlen; - struct ksslf *ksslf_listener; -} ksslf_t; - -static void kssl_input_callback(void *, mblk_t *, kssl_cmd_t); - -/* - * Allocate kssl state - */ -sof_rval_t -kssl_attach_passive_cb(sof_handle_t handle, sof_handle_t ph, - void *parg, struct sockaddr *laddr, socklen_t laddrlen, - struct sockaddr *faddr, socklen_t faddrlen, void **cookiep) -{ - ksslf_t *listener = (ksslf_t *)parg; - ksslf_t *new; - - _NOTE(ARGUNUSED(handle, ph, faddrlen, laddr, laddrlen)); - - if (listener == NULL || listener->ksslf_ent == NULL) - return (SOF_RVAL_DETACH); - /* - * Only way for a fallback listener to receive connections is when - * a handshake fails and socket is moved from the proxy to the fallback. - * Connections that come in directly on the fallback are denied. - */ - if (listener->ksslf_type == KSSL_HAS_PROXY) - return (SOF_RVAL_EACCES); - - /* Allocate the SSL context for the new connection */ - new = kmem_zalloc(sizeof (ksslf_t), KM_NOSLEEP); - if (new == NULL) - return (SOF_RVAL_ENOMEM); - - /* - * The mss is initialized to SSL3_MAX_RECORD_LEN, but might be - * updated by the mblk_prop callback. - */ - if (kssl_init_context(listener->ksslf_ent, faddr, SSL3_MAX_RECORD_LEN, - &new->ksslf_ctx) != KSSL_STS_OK) - return (SOF_RVAL_ENOMEM); - - new->ksslf_pending = B_TRUE; - new->ksslf_inhandshake = B_TRUE; - ASSERT(laddrlen <= sizeof (new->ksslf_laddr)); - new->ksslf_laddrlen = laddrlen; - bcopy(laddr, &new->ksslf_laddr, laddrlen); - new->ksslf_laddr.sin6_port = listener->ksslf_laddr.sin6_port; - new->ksslf_listener = listener; - - *cookiep = new; - /* - * We are in handshake, defer the notification of this connection - * until it is completed. - */ - return (SOF_RVAL_DEFER); -} - -void -kssl_detach_cb(sof_handle_t handle, void *cookie, cred_t *cr) -{ - ksslf_t *kssl = (ksslf_t *)cookie; - - _NOTE(ARGUNUSED(handle, cr)); - - if (kssl == NULL) - return; - - if (kssl->ksslf_ent != NULL) { - kssl_release_ent(kssl->ksslf_ent, handle, kssl->ksslf_type); - kssl->ksslf_ent = NULL; - } - if (kssl->ksslf_ctx != NULL) { - kssl_release_ctx(kssl->ksslf_ctx); - kssl->ksslf_ctx = NULL; - } - - kmem_free(kssl, sizeof (ksslf_t)); -} - -sof_rval_t -kssl_bind_cb(sof_handle_t handle, void *cookie, struct sockaddr *name, - socklen_t *namelen, cred_t *cr) -{ - kssl_ent_t ent; - kssl_endpt_type_t type; - ksslf_t *kssl; - in_port_t origport; - - _NOTE(ARGUNUSED(cr)); - - if (cookie != NULL) - return (SOF_RVAL_EINVAL); - - if (*namelen < sizeof (struct sockaddr_in)) { - sof_bypass(handle); - return (SOF_RVAL_CONTINUE); - } - - origport = ((struct sockaddr_in *)name)->sin_port; - /* Check if KSSL has been configured for this address */ - type = kssl_check_proxy(name, *namelen, handle, &ent); - - switch (type) { - case KSSL_NO_PROXY: - sof_bypass(handle); - break; - case KSSL_HAS_PROXY: - case KSSL_IS_PROXY: - kssl = kmem_zalloc(sizeof (ksslf_t), KM_SLEEP); - kssl->ksslf_type = type; - kssl->ksslf_ent = ent; - - /* - * In the unlikely event that there are multiple simultaneous - * bind requests, and the cookie was already swapped out, then - * just drop this cookie and let the bind continue unmodified. - */ - if (sof_cas_cookie(handle, cookie, kssl) != cookie) { - kssl_release_ent(ent, handle, type); - kmem_free(kssl, sizeof (ksslf_t)); - ((struct sockaddr_in *)name)->sin_port = origport; - break; - } - - kssl->ksslf_laddrlen = *namelen; - bcopy(name, &kssl->ksslf_laddr, kssl->ksslf_laddrlen); - kssl->ksslf_laddr.sin6_port = origport; - /* - * kssl_check_proxy updated the sockaddr, so just - * pass it along to the protocol. - */ - return ((type == KSSL_HAS_PROXY) ? SOF_RVAL_RETURN : - SOF_RVAL_CONTINUE); - } - return (SOF_RVAL_CONTINUE); -} - -sof_rval_t -kssl_listen_cb(sof_handle_t handle, void *cookie, int *backlog, cred_t *cr) -{ - ksslf_t *kssl = (ksslf_t *)cookie; - - _NOTE(ARGUNUSED(backlog, cr)); - - /* - * The cookie can be NULL in the unlikely event of an application doing - * listen() without binding to an address. Those listeners are of no - * interest. - */ - if (kssl == NULL) { - sof_bypass(handle); - return (SOF_RVAL_CONTINUE); - } - - return (SOF_RVAL_CONTINUE); - -} - -/* - * Outgoing connections are not of interest, so just bypass the filter. - */ -sof_rval_t -kssl_connect_cb(sof_handle_t handle, void *cookie, struct sockaddr *name, - socklen_t *namelen, cred_t *cr) -{ - _NOTE(ARGUNUSED(cookie, name, namelen, cr)); - - sof_bypass(handle); - return (SOF_RVAL_CONTINUE); -} - -static void -kssl_mblk_prop_cb(sof_handle_t handle, void *cookie, ssize_t *maxblk, - ushort_t *wroff, ushort_t *tail) -{ - ksslf_t *kssl = (ksslf_t *)cookie; - - _NOTE(ARGUNUSED(handle)); - - /* only care about passively opened sockets */ - if (kssl == NULL || !kssl->ksslf_pending) - return; - /* - * If this is endpoint is handling SSL, then reserve extra - * offset and space at the end. Also have sockfs allocate - * SSL3_MAX_RECORD_LEN packets, overriding the previous setting. - * The extra cost of signing and encrypting multiple MSS-size - * records (12 of them with Ethernet), instead of a single - * contiguous one by the stream head largely outweighs the - * statistical reduction of ACKs, when applicable. The peer - * will also save on decryption and verification costs. - */ - if (*maxblk == INFPSZ || *maxblk > SSL3_MAX_RECORD_LEN) - *maxblk = SSL3_MAX_RECORD_LEN; - else - kssl_set_mss(kssl->ksslf_ctx, *maxblk); - *wroff += SSL3_WROFFSET; - *tail += SSL3_MAX_TAIL_LEN; -} - -sof_rval_t -kssl_getsockname_cb(sof_handle_t handle, void *cookie, struct sockaddr *addr, - socklen_t *addrlen, cred_t *cr) -{ - ksslf_t *kssl = (ksslf_t *)cookie; - - _NOTE(ARGUNUSED(handle, cr)); - - if (kssl == NULL) - return (SOF_RVAL_CONTINUE); - - if (*addrlen < kssl->ksslf_laddrlen) - return (SOF_RVAL_EINVAL); - - *addrlen = kssl->ksslf_laddrlen; - bcopy(&kssl->ksslf_laddr, addr, kssl->ksslf_laddrlen); - - return (SOF_RVAL_RETURN); -} - -/* - * Called for every packet sent to the protocol. - * If the message is successfully processed, then it is returned. - */ -mblk_t * -kssl_data_out_cb(sof_handle_t handle, void *cookie, mblk_t *mp, - struct nmsghdr *msg, cred_t *cr, sof_rval_t *rv) -{ - ksslf_t *kssl = (ksslf_t *)cookie; - mblk_t *recmp; - - _NOTE(ARGUNUSED(handle, msg, cr)); - - *rv = SOF_RVAL_CONTINUE; - if (kssl == NULL || kssl->ksslf_ctx == NULL) - return (mp); - - if ((recmp = kssl_build_record(kssl->ksslf_ctx, mp)) == NULL) { - freemsg(mp); - *rv = SOF_RVAL_EINVAL; - return (NULL); - } - return (recmp); -} - -/* - * Called from shutdown() processing. This will produce close_notify message - * to indicate the end of data to the client. - */ -sof_rval_t -kssl_shutdown_cb(sof_handle_t handle, void *cookie, int *howp, cred_t *cr) -{ - ksslf_t *kssl = (ksslf_t *)cookie; - mblk_t *outmp; - boolean_t flowctrld; - struct nmsghdr msg; - - _NOTE(ARGUNUSED(cr)); - - if (kssl == NULL || kssl->ksslf_ctx == NULL) - return (SOF_RVAL_CONTINUE); - - /* - * We only want to send close_notify when doing SHUT_WR/SHUT_RDWR - * because it signals that server is done writing data. - */ - if (*howp == SHUT_RD) - return (SOF_RVAL_CONTINUE); - - /* Go on if we fail to build the record. */ - if ((outmp = kssl_build_record(kssl->ksslf_ctx, NULL)) == NULL) - return (SOF_RVAL_CONTINUE); - - bzero(&msg, sizeof (msg)); - (void) sof_inject_data_out(handle, outmp, &msg, - &flowctrld); - - return (SOF_RVAL_CONTINUE); -} - -/* - * Called for each incoming segment. - * - * A packet may carry multiple SSL records, so the function calls - * kssl_input() in a loop, until all records are handled. - */ -mblk_t * -kssl_data_in_cb(sof_handle_t handle, void *cookie, mblk_t *mp, int flags, - size_t *lenp) -{ - ksslf_t *kssl = cookie; - kssl_cmd_t kssl_cmd; - mblk_t *outmp, *retmp = NULL, **tail = &retmp; - boolean_t more = B_FALSE; - boolean_t flowctrld; - - _NOTE(ARGUNUSED(flags)); - - if (kssl == NULL || kssl->ksslf_ctx == NULL) { - sof_bypass(handle); - return (mp); - } - - *lenp = 0; - do { - kssl_cmd = kssl_input(kssl->ksslf_ctx, mp, &outmp, - &more, kssl_input_callback, (void *)handle); - - switch (kssl_cmd) { - case KSSL_CMD_SEND: { - struct nmsghdr msg; - - DTRACE_PROBE(kssl_cmd_send); - bzero(&msg, sizeof (msg)); - (void) sof_inject_data_out(handle, outmp, &msg, - &flowctrld); - } - /* FALLTHROUGH */ - case KSSL_CMD_NONE: - DTRACE_PROBE(kssl_cmd_none); - if (kssl->ksslf_pending) { - kssl->ksslf_pending = B_FALSE; - sof_newconn_ready(handle); - } - break; - - case KSSL_CMD_QUEUED: - DTRACE_PROBE(kssl_cmd_queued); - break; - - case KSSL_CMD_DELIVER_PROXY: - case KSSL_CMD_DELIVER_SSL: - DTRACE_PROBE(kssl_cmd_proxy__ssl); - /* - * We're at a phase where records are sent upstreams, - * past the handshake - */ - kssl->ksslf_inhandshake = B_FALSE; - - *tail = outmp; - *lenp += MBLKL(outmp); - while (outmp->b_cont != NULL) { - outmp = outmp->b_cont; - *lenp += MBLKL(outmp); - } - tail = &outmp->b_cont; - break; - - case KSSL_CMD_NOT_SUPPORTED: { - ksslf_t *listener = kssl->ksslf_listener; - sof_handle_t fallback; - - DTRACE_PROBE(kssl_cmd_not_supported); - /* - * Stop the SSL processing by the proxy, and - * switch to the userland SSL - */ - if (kssl->ksslf_pending) { - kssl->ksslf_pending = B_FALSE; - - DTRACE_PROBE1(kssl_no_can_do, sof_handle_t, - handle); - - sof_bypass(handle); - - ASSERT(listener->ksslf_ent != NULL); - fallback = - kssl_find_fallback(listener->ksslf_ent); - /* - * No fallback: the remote will timeout and - * disconnect. - */ - if (fallback != NULL && - sof_newconn_move(handle, fallback)) - sof_newconn_ready(handle); - } - if (mp != NULL) { - *tail = mp; - *lenp += MBLKL(mp); - while (mp->b_cont != NULL) { - mp = mp->b_cont; - *lenp += MBLKL(mp); - } - tail = &mp->b_cont; - } - break; - } - } - mp = NULL; - } while (more); - - return (retmp); -} - -/* - * Process queued data before it's copied by the user. - * - * If the message is successfully processed, then it is returned. - * A failed message will be freed. - */ -mblk_t * -kssl_data_in_proc_cb(sof_handle_t handle, void *cookie, mblk_t *mp, - cred_t *cr, size_t *lenp) -{ - ksslf_t *kssl = (ksslf_t *)cookie; - kssl_cmd_t kssl_cmd; - mblk_t *out; - - _NOTE(ARGUNUSED(cr)); - - if (kssl == NULL || kssl->ksslf_ctx) - return (mp); - - *lenp = 0; - - kssl_cmd = kssl_handle_mblk(kssl->ksslf_ctx, &mp, &out); - - switch (kssl_cmd) { - case KSSL_CMD_NONE: - return (NULL); - case KSSL_CMD_DELIVER_PROXY: - *lenp = msgdsize(mp); - return (mp); - case KSSL_CMD_SEND: { - struct nmsghdr msg; - boolean_t flowctrld; - - ASSERT(out != NULL); - bzero(&msg, sizeof (msg)); - - (void) sof_inject_data_out(handle, out, &msg, - &flowctrld); - return (NULL); - } - default: - /* transient error. */ - return (NULL); - } -} - -/* - * Continue processing the incoming flow after an asynchronous callback. - */ -static void -kssl_input_asynch(void *arg) -{ - sof_handle_t handle = (sof_handle_t)arg; - ksslf_t *kssl = (ksslf_t *)sof_get_cookie(handle); - size_t len = 0; - boolean_t flowctrld; - mblk_t *mp; - - if ((mp = kssl_data_in_cb(handle, kssl, NULL, 0, &len)) != NULL) { - ASSERT(len != 0); - (void) sof_inject_data_in(handle, mp, len, 0, &flowctrld); - } - kssl_async_done(kssl->ksslf_ctx); -} - -/* - * Callback function for the cases kssl_input() had to submit an asynchronous - * job and need to come back when done to carry on the input processing. - * This routine follows the conentions of timeout and interrupt handlers. - * (no blocking, ...) - */ -static void -kssl_input_callback(void *arg, mblk_t *mp, kssl_cmd_t kssl_cmd) -{ - sof_handle_t handle = (sof_handle_t)arg; - ksslf_t *kssl = (ksslf_t *)sof_get_cookie(handle); - boolean_t flowctrld; - - ASSERT(kssl != NULL); - - switch (kssl_cmd) { - case KSSL_CMD_SEND: { - struct nmsghdr msg; - - if (mp == NULL) - break; - bzero(&msg, sizeof (msg)); - - (void) sof_inject_data_out(handle, mp, &msg, &flowctrld); - } - /* FALLTHROUGH */ - case KSSL_CMD_NONE: - break; - - case KSSL_CMD_DELIVER_PROXY: - case KSSL_CMD_DELIVER_SSL: - (void) sof_inject_data_in(handle, mp, msgdsize(mp), 0, - &flowctrld); - break; - - case KSSL_CMD_NOT_SUPPORTED: - /* Stop the SSL processing */ - sof_bypass(handle); - } - /* - * Process any input that may have accumulated while we're waiting for - * the call-back. This must be done by a taskq because kssl_input might - * block when handling client_finish messages. - */ - if (taskq_dispatch(system_taskq, kssl_input_asynch, handle, - TQ_NOSLEEP) == TASKQID_INVALID) { - DTRACE_PROBE(kssl_err__taskq_dispatch_failed); - kssl_async_done(kssl->ksslf_ctx); - } -} - -sof_ops_t ksslf_ops = { - .sofop_attach_passive = kssl_attach_passive_cb, - .sofop_detach = kssl_detach_cb, - .sofop_bind = kssl_bind_cb, - .sofop_connect = kssl_connect_cb, - .sofop_listen = kssl_listen_cb, - .sofop_data_in = kssl_data_in_cb, - .sofop_data_in_proc = kssl_data_in_proc_cb, - .sofop_data_out = kssl_data_out_cb, - .sofop_mblk_prop = kssl_mblk_prop_cb, - .sofop_getsockname = kssl_getsockname_cb, - .sofop_shutdown = kssl_shutdown_cb, -}; - -int -_init(void) -{ - int error; - - if ((error = sof_register(SOF_VERSION, KSSL_FILNAME, - &ksslf_ops, 0)) != 0) - return (error); - if ((error = mod_install(&ksslf_modlinkage)) != 0) - (void) sof_unregister(KSSL_FILNAME); - - return (error); -} - -int -_fini(void) -{ - int error; - - if ((error = sof_unregister(KSSL_FILNAME)) != 0) - return (error); - - return (mod_remove(&ksslf_modlinkage)); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&ksslf_modlinkage, modinfop)); -} |