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