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