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