Home | History | Annotate | Download | only in tcp
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/types.h>
     27 #include <sys/stream.h>
     28 #include <sys/strsubr.h>
     29 #include <sys/stropts.h>
     30 #include <sys/cmn_err.h>
     31 #include <sys/debug.h>
     32 #include <sys/vtrace.h>
     33 #include <sys/kmem.h>
     34 #include <sys/zone.h>
     35 #include <sys/tihdr.h>
     36 
     37 #include <netinet/in.h>
     38 #include <netinet/tcp.h>
     39 
     40 #include <inet/common.h>
     41 #include <inet/optcom.h>
     42 #include <inet/ipclassifier.h>
     43 #include <inet/ip.h>
     44 #include <inet/ip6.h>
     45 #include <inet/mib2.h>
     46 #include <inet/tcp.h>
     47 #include <inet/ipsec_impl.h>
     48 #include <inet/ipdrop.h>
     49 #include <inet/tcp_impl.h>
     50 
     51 #include <sys/squeue_impl.h>
     52 #include <sys/squeue.h>
     53 #include <inet/kssl/ksslapi.h>
     54 
     55 /*
     56  * For the Kernel SSL proxy
     57  *
     58  * Routines in this file are called on tcp's incoming path,
     59  * tcp_input_data() mainly, and right before the message is
     60  * to be putnext()'ed upstreams.
     61  */
     62 
     63 static void	tcp_kssl_input_callback(void *, mblk_t *, kssl_cmd_t);
     64 static void	tcp_kssl_input_asynch(void *, mblk_t *, void *,
     65     ip_recv_attr_t *);
     66 
     67 extern void	tcp_output(void *, mblk_t *, void *, ip_recv_attr_t *);
     68 extern void	tcp_send_conn_ind(void *, mblk_t *, void *);
     69 
     70 extern int tcp_squeue_flag;
     71 
     72 /*
     73  * tcp_input_data() calls this routine for all packet destined to a
     74  * connection to the SSL port, when the SSL kernel proxy is configured
     75  * to intercept and process those packets.
     76  * A packet may carry multiple SSL records, so the function
     77  * calls kssl_input() in a loop, until all records are
     78  * handled.
     79  * As long as this connection is in handshake, that is until the first
     80  * time kssl_input() returns a record to be delivered ustreams,
     81  * we maintain the tcp_kssl_inhandshake, and keep an extra reference on
     82  * the tcp/connp across the call to kssl_input(). The reason is, that
     83  * function may return KSSL_CMD_QUEUED after scheduling an asynchronous
     84  * request and cause tcp_kssl_callback() to be called on a different CPU,
     85  * which could decrement the conn/tcp reference before we get to increment it.
     86  */
     87 void
     88 tcp_kssl_input(tcp_t *tcp, mblk_t *mp, cred_t *cr)
     89 {
     90 	struct conn_s	*connp = tcp->tcp_connp;
     91 	tcp_t		*listener;
     92 	mblk_t		*ind_mp;
     93 	kssl_cmd_t	kssl_cmd;
     94 	mblk_t		*outmp;
     95 	struct		T_conn_ind *tci;
     96 	boolean_t	more = B_FALSE;
     97 	boolean_t	conn_held = B_FALSE;
     98 	boolean_t	is_v4;
     99 	void		*addr;
    100 
    101 	if (is_system_labeled() && mp != NULL) {
    102 		ASSERT(cr != NULL || msg_getcred(mp, NULL) != NULL);
    103 		/*
    104 		 * Provide for protocols above TCP such as RPC. NOPID leaves
    105 		 * db_cpid unchanged.
    106 		 * The cred could have already been set.
    107 		 */
    108 		if (cr != NULL)
    109 			mblk_setcred(mp, cr, NOPID);
    110 	}
    111 
    112 	/* First time here, allocate the SSL context */
    113 	if (tcp->tcp_kssl_ctx == NULL) {
    114 		ASSERT(tcp->tcp_kssl_pending);
    115 
    116 		is_v4 = (connp->conn_ipversion == IPV4_VERSION);
    117 		if (is_v4) {
    118 			addr = &connp->conn_faddr_v4;
    119 		} else {
    120 			addr = &connp->conn_faddr_v6;
    121 		}
    122 
    123 		if (kssl_init_context(tcp->tcp_kssl_ent,
    124 		    addr, is_v4, tcp->tcp_mss,
    125 		    &(tcp->tcp_kssl_ctx)) != KSSL_STS_OK) {
    126 			tcp->tcp_kssl_pending = B_FALSE;
    127 			kssl_release_ent(tcp->tcp_kssl_ent, NULL,
    128 			    KSSL_NO_PROXY);
    129 			tcp->tcp_kssl_ent = NULL;
    130 			goto no_can_do;
    131 		}
    132 		tcp->tcp_kssl_inhandshake = B_TRUE;
    133 
    134 		/* we won't be needing this one after now */
    135 		kssl_release_ent(tcp->tcp_kssl_ent, NULL, KSSL_NO_PROXY);
    136 		tcp->tcp_kssl_ent = NULL;
    137 
    138 	}
    139 
    140 	if (tcp->tcp_kssl_inhandshake) {
    141 		CONN_INC_REF(connp);
    142 		conn_held = B_TRUE;
    143 	}
    144 
    145 	do {
    146 		kssl_cmd = kssl_input(tcp->tcp_kssl_ctx, mp, &outmp,
    147 		    &more, tcp_kssl_input_callback, (void *)tcp);
    148 
    149 		switch (kssl_cmd) {
    150 		case KSSL_CMD_SEND:
    151 			DTRACE_PROBE(kssl_cmd_send);
    152 			/*
    153 			 * We need to increment tcp_squeue_bytes to account
    154 			 * for the extra bytes internally injected to the
    155 			 * outgoing flow. tcp_output() will decrement it
    156 			 * as they are sent out.
    157 			 */
    158 			mutex_enter(&tcp->tcp_non_sq_lock);
    159 			tcp->tcp_squeue_bytes += msgdsize(outmp);
    160 			mutex_exit(&tcp->tcp_non_sq_lock);
    161 			tcp_output(connp, outmp, NULL, NULL);
    162 
    163 		/* FALLTHROUGH */
    164 		case KSSL_CMD_NONE:
    165 			DTRACE_PROBE(kssl_cmd_none);
    166 			if (tcp->tcp_kssl_pending) {
    167 				mblk_t *ctxmp;
    168 
    169 				/*
    170 				 * SSL handshake successfully started -
    171 				 * pass up the T_CONN_IND
    172 				 */
    173 
    174 				mp = NULL;
    175 
    176 				listener = tcp->tcp_listener;
    177 				tcp->tcp_kssl_pending = B_FALSE;
    178 
    179 				ind_mp = tcp->tcp_conn.tcp_eager_conn_ind;
    180 				ASSERT(ind_mp != NULL);
    181 
    182 				ctxmp = allocb(sizeof (kssl_ctx_t), BPRI_MED);
    183 
    184 				/*
    185 				 * Give this session a chance to fall back to
    186 				 * userland SSL
    187 				 */
    188 				if (ctxmp == NULL)
    189 					goto no_can_do;
    190 
    191 				/*
    192 				 * attach the kssl_ctx to the conn_ind and
    193 				 * transform it to a T_SSL_PROXY_CONN_IND.
    194 				 * Hold it so that it stays valid till it
    195 				 * reaches the stream head.
    196 				 */
    197 				kssl_hold_ctx(tcp->tcp_kssl_ctx);
    198 				*((kssl_ctx_t *)ctxmp->b_rptr) =
    199 				    tcp->tcp_kssl_ctx;
    200 				ctxmp->b_wptr = ctxmp->b_rptr +
    201 				    sizeof (kssl_ctx_t);
    202 
    203 				ind_mp->b_cont = ctxmp;
    204 
    205 				tci = (struct T_conn_ind *)ind_mp->b_rptr;
    206 				tci->PRIM_type = T_SSL_PROXY_CONN_IND;
    207 
    208 				/*
    209 				 * The code below is copied from tcp_input_data
    210 				 * delivering the T_CONN_IND on a TCPS_SYN_RCVD,
    211 				 * and all conn ref cnt comments apply.
    212 				 */
    213 				tcp->tcp_conn.tcp_eager_conn_ind = NULL;
    214 				tcp->tcp_tconnind_started = B_TRUE;
    215 
    216 				CONN_INC_REF(connp);
    217 
    218 				CONN_INC_REF(listener->tcp_connp);
    219 				if (listener->tcp_connp->conn_sqp ==
    220 				    connp->conn_sqp) {
    221 					tcp_send_conn_ind(listener->tcp_connp,
    222 					    ind_mp,
    223 					    listener->tcp_connp->conn_sqp);
    224 					CONN_DEC_REF(listener->tcp_connp);
    225 				} else {
    226 					SQUEUE_ENTER_ONE(
    227 					    listener->tcp_connp->conn_sqp,
    228 					    ind_mp, tcp_send_conn_ind,
    229 					    listener->tcp_connp, NULL, SQ_FILL,
    230 					    SQTAG_TCP_CONN_IND);
    231 				}
    232 			}
    233 			break;
    234 
    235 		case KSSL_CMD_QUEUED:
    236 			DTRACE_PROBE(kssl_cmd_queued);
    237 			/*
    238 			 * We hold the conn_t here because an asynchronous
    239 			 * request have been queued and
    240 			 * tcp_kssl_input_callback() will be called later.
    241 			 * It will release the conn_t
    242 			 */
    243 			CONN_INC_REF(connp);
    244 			break;
    245 
    246 		case KSSL_CMD_DELIVER_PROXY:
    247 		case KSSL_CMD_DELIVER_SSL:
    248 			DTRACE_PROBE(kssl_cmd_proxy__ssl);
    249 			/*
    250 			 * Keep accumulating if not yet accepted.
    251 			 */
    252 			if (tcp->tcp_listener != NULL) {
    253 				DTRACE_PROBE1(kssl_mblk__input_rcv_enqueue,
    254 				    mblk_t *, outmp);
    255 				tcp_rcv_enqueue(tcp, outmp, msgdsize(outmp),
    256 				    NULL);
    257 			} else {
    258 				DTRACE_PROBE1(kssl_mblk__input_putnext,
    259 				    mblk_t *, outmp);
    260 				putnext(connp->conn_rq, outmp);
    261 			}
    262 			/*
    263 			 * We're at a phase where records are sent upstreams,
    264 			 * past the handshake
    265 			 */
    266 			tcp->tcp_kssl_inhandshake = B_FALSE;
    267 			break;
    268 
    269 		case KSSL_CMD_NOT_SUPPORTED:
    270 			DTRACE_PROBE(kssl_cmd_not_supported);
    271 			/*
    272 			 * Stop the SSL processing by the proxy, and
    273 			 * switch to the userland SSL
    274 			 */
    275 			if (tcp->tcp_kssl_pending) {
    276 
    277 				tcp->tcp_kssl_pending = B_FALSE;
    278 
    279 no_can_do:
    280 				DTRACE_PROBE1(kssl_no_can_do, tcp_t *, tcp);
    281 				listener = tcp->tcp_listener;
    282 				ind_mp = tcp->tcp_conn.tcp_eager_conn_ind;
    283 				ASSERT(ind_mp != NULL);
    284 
    285 				if (tcp->tcp_kssl_ctx != NULL) {
    286 					kssl_release_ctx(tcp->tcp_kssl_ctx);
    287 					tcp->tcp_kssl_ctx = NULL;
    288 				}
    289 
    290 				/*
    291 				 * Make this a T_SSL_PROXY_CONN_IND, for the
    292 				 * stream head to deliver it to the SSL
    293 				 * fall-back listener
    294 				 */
    295 				tci = (struct T_conn_ind *)ind_mp->b_rptr;
    296 				tci->PRIM_type = T_SSL_PROXY_CONN_IND;
    297 
    298 				/*
    299 				 * The code below is copied from tcp_input_data
    300 				 * delivering the T_CONN_IND on a TCPS_SYN_RCVD,
    301 				 * and all conn ref cnt comments apply.
    302 				 */
    303 				tcp->tcp_conn.tcp_eager_conn_ind = NULL;
    304 				tcp->tcp_tconnind_started = B_TRUE;
    305 
    306 				CONN_INC_REF(connp);
    307 
    308 				CONN_INC_REF(listener->tcp_connp);
    309 				if (listener->tcp_connp->conn_sqp ==
    310 				    connp->conn_sqp) {
    311 					tcp_send_conn_ind(listener->tcp_connp,
    312 					    ind_mp,
    313 					    listener->tcp_connp->conn_sqp);
    314 					CONN_DEC_REF(listener->tcp_connp);
    315 				} else {
    316 					SQUEUE_ENTER_ONE(
    317 					    listener->tcp_connp->conn_sqp,
    318 					    ind_mp, tcp_send_conn_ind,
    319 					    listener->tcp_connp, NULL,
    320 					    SQ_FILL, SQTAG_TCP_CONN_IND);
    321 				}
    322 			}
    323 			if (mp != NULL)
    324 				tcp_rcv_enqueue(tcp, mp, msgdsize(mp), NULL);
    325 			break;
    326 		}
    327 		mp = NULL;
    328 	} while (more);
    329 
    330 	if (conn_held) {
    331 		CONN_DEC_REF(connp);
    332 	}
    333 }
    334 
    335 /*
    336  * Callback function for the cases kssl_input() had to submit an asynchronous
    337  * job and need to come back when done to carry on the input processing.
    338  * This routine follows the conventions of timeout and interrupt handlers.
    339  * (no blocking, ...)
    340  */
    341 static void
    342 tcp_kssl_input_callback(void *arg, mblk_t *mp, kssl_cmd_t kssl_cmd)
    343 {
    344 	tcp_t	*tcp = (tcp_t *)arg;
    345 	conn_t	*connp;
    346 	mblk_t	*sqmp;
    347 
    348 	ASSERT(tcp != NULL);
    349 
    350 	connp = tcp->tcp_connp;
    351 
    352 	ASSERT(connp != NULL);
    353 
    354 	switch (kssl_cmd) {
    355 	case KSSL_CMD_SEND:
    356 		/* I'm coming from an outside perimeter */
    357 		if (mp != NULL) {
    358 			/*
    359 			 * See comment in tcp_kssl_input() call to tcp_output()
    360 			 */
    361 			mutex_enter(&tcp->tcp_non_sq_lock);
    362 			tcp->tcp_squeue_bytes += msgdsize(mp);
    363 			mutex_exit(&tcp->tcp_non_sq_lock);
    364 		}
    365 		CONN_INC_REF(connp);
    366 		SQUEUE_ENTER_ONE(connp->conn_sqp, mp, tcp_output, connp,
    367 		    NULL, tcp_squeue_flag, SQTAG_TCP_OUTPUT);
    368 
    369 	/* FALLTHROUGH */
    370 	case KSSL_CMD_NONE:
    371 		break;
    372 
    373 	case KSSL_CMD_DELIVER_PROXY:
    374 	case KSSL_CMD_DELIVER_SSL:
    375 		/*
    376 		 * Keep accumulating if not yet accepted.
    377 		 */
    378 		if (tcp->tcp_listener != NULL) {
    379 			tcp_rcv_enqueue(tcp, mp, msgdsize(mp), NULL);
    380 		} else {
    381 			putnext(connp->conn_rq, mp);
    382 		}
    383 		break;
    384 
    385 	case KSSL_CMD_NOT_SUPPORTED:
    386 		/* Stop the SSL processing */
    387 		kssl_release_ctx(tcp->tcp_kssl_ctx);
    388 		tcp->tcp_kssl_ctx = NULL;
    389 	}
    390 	/*
    391 	 * Process any input that may have accumulated while we're waiting for
    392 	 * the call-back.
    393 	 * We need to re-enter the squeue for this connp, and a new mp is
    394 	 * necessary.
    395 	 */
    396 	if ((sqmp = allocb(1, BPRI_MED)) != NULL) {
    397 		CONN_INC_REF(connp);
    398 		SQUEUE_ENTER_ONE(connp->conn_sqp, sqmp, tcp_kssl_input_asynch,
    399 		    connp, NULL, SQ_FILL, SQTAG_TCP_KSSL_INPUT);
    400 	} else {
    401 		DTRACE_PROBE(kssl_err__allocb_failed);
    402 	}
    403 	CONN_DEC_REF(connp);
    404 }
    405 
    406 /*
    407  * Needed by tcp_kssl_input_callback() to continue processing the incoming
    408  * flow on a tcp_t after an asynchronous callback call.
    409  */
    410 /* ARGSUSED */
    411 void
    412 tcp_kssl_input_asynch(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
    413 {
    414 	conn_t	*connp = (conn_t *)arg;
    415 	tcp_t *tcp = connp->conn_tcp;
    416 
    417 	ASSERT(connp != NULL);
    418 	freemsg(mp);
    419 
    420 	/*
    421 	 * NULL tcp_kssl_ctx means this connection is getting/was closed
    422 	 * while we're away
    423 	 */
    424 	if (tcp->tcp_kssl_ctx != NULL) {
    425 		tcp_kssl_input(tcp, NULL, NULL);
    426 	}
    427 }
    428