diff --git a/lib/core-net/client/connect.c b/lib/core-net/client/connect.c index 377579eb1..a544edb65 100644 --- a/lib/core-net/client/connect.c +++ b/lib/core-net/client/connect.c @@ -318,7 +318,9 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i) i->opaque_user_data; #if defined(LWS_WITH_SECURE_STREAMS) - wsi->for_ss = !!(i->ssl_connection & LCCSCF_SECSTREAM_CLIENT); + wsi->for_ss = !!(i->ssl_connection & (LCCSCF_SECSTREAM_CLIENT | LCCSCF_SECSTREAM_PROXY_LINK | LCCSCF_SECSTREAM_PROXY_ONWARD)); + + wsi->client_bound_sspc = !!(i->ssl_connection & LCCSCF_SECSTREAM_PROXY_LINK); /* so wsi close understands need to remove sspc ptr to wsi */ /* implies our opaque user ptr is the ss handle */ if (wsi->for_ss) { /* it's related to ss... the options are @@ -335,6 +337,9 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i) #endif &wsi->lc, "%s/%s/%s/(%s)", i->method ? i->method : "WS", wsi->role_ops->name, i->address, +#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) + wsi->client_bound_sspc ? lws_sspc_tag((lws_sspc_handle_t *)i->opaque_user_data) : +#endif lws_ss_tag(((lws_ss_handle_t *)i->opaque_user_data))); } else #endif diff --git a/lib/core-net/close.c b/lib/core-net/close.c index 68520d16c..946b0ccec 100644 --- a/lib/core-net/close.c +++ b/lib/core-net/close.c @@ -520,11 +520,27 @@ just_kill_connection: * good, but we have to invalidate any pointer the related ss * handle may be holding on us */ - lws_ss_handle_t *h = (lws_ss_handle_t *)wsi->a.opaque_user_data; +#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) + if (wsi->client_bound_sspc) { + lws_sspc_handle_t *h = (lws_sspc_handle_t *)wsi->a.opaque_user_data; - if (h && (h->info.flags & LWSSSINFLAGS_ACCEPTED)) { - h->wsi = NULL; - wsi->a.opaque_user_data = NULL; + if (h) { // && (h->info.flags & LWSSSINFLAGS_ACCEPTED)) { + h->cwsi = NULL; + wsi->a.opaque_user_data = NULL; + } + } else +#endif + { + lws_ss_handle_t *h = (lws_ss_handle_t *)wsi->a.opaque_user_data; + + if (h) { // && (h->info.flags & LWSSSINFLAGS_ACCEPTED)) { + + if (h->ss_dangling_connected) + (void)lws_ss_event_helper(h, LWSSSCS_DISCONNECTED); + + h->wsi = NULL; + wsi->a.opaque_user_data = NULL; + } } } #endif diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index 4f7dedea3..edeaa71d0 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -843,6 +843,8 @@ struct lws { unsigned int shadow:1; /* we do not control fd lifecycle at all */ #if defined(LWS_WITH_SECURE_STREAMS) unsigned int for_ss:1; + unsigned int bound_ss_proxy_conn:1; + unsigned int client_bound_sspc:1; #endif #ifdef LWS_WITH_ACCESS_LOG diff --git a/lib/core-net/wsi.c b/lib/core-net/wsi.c index 23e024a5e..f494af1e1 100644 --- a/lib/core-net/wsi.c +++ b/lib/core-net/wsi.c @@ -27,6 +27,8 @@ const char * lws_wsi_tag(struct lws *wsi) { + if (!wsi) + return "[null wsi]"; return lws_lc_tag(&wsi->lc); } diff --git a/lib/secure-streams/private-lib-secure-streams.h b/lib/secure-streams/private-lib-secure-streams.h index 524019911..ecbeed943 100644 --- a/lib/secure-streams/private-lib-secure-streams.h +++ b/lib/secure-streams/private-lib-secure-streams.h @@ -160,6 +160,7 @@ typedef struct lws_ss_handle { uint8_t inside_msg:1; uint8_t being_serialized:1; /* we are not the consumer */ uint8_t destroying:1; + uint8_t ss_dangling_connected:1; } lws_ss_handle_t; /* connection helper that doesn't need to hang around after connection starts */ @@ -300,6 +301,7 @@ typedef struct lws_sspc_handle { uint8_t pending_timeout_update:1; uint8_t pending_writeable_len:1; uint8_t creating_cb_done:1; + uint8_t ss_dangling_connected:1; } lws_sspc_handle_t; typedef struct backoffs { diff --git a/lib/secure-streams/protocols/ss-h1.c b/lib/secure-streams/protocols/ss-h1.c index 2e96911c9..713079096 100644 --- a/lib/secure-streams/protocols/ss-h1.c +++ b/lib/secure-streams/protocols/ss-h1.c @@ -394,6 +394,10 @@ secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user, break; case LWS_CALLBACK_CLIENT_HTTP_REDIRECT: + + if (!h) + return -1; + if (h->policy->u.http.fail_redirect) lws_system_cpd_set(lws_get_context(wsi), LWS_CPD_CAPTIVE_PORTAL); @@ -435,7 +439,11 @@ secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user, case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: - status = lws_http_client_http_response(wsi); + + if (!h) + return -1; + + status = (int)lws_http_client_http_response(wsi); lwsl_info("%s: LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: %d\n", __func__, status); // if (!status) /* it's just telling use we connected / joined the nwsi */ @@ -587,6 +595,8 @@ malformed: #endif case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: + if (!h) + return -1; if (h->writeable_len) wsi->http.writeable_len = h->writeable_len; @@ -706,6 +716,10 @@ malformed: case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: lwsl_debug("%s: LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n", __func__); + + if (!h) + return -1; + if (h->hanging_som) { h->info.rx(ss_to_userobj(h), NULL, 0, LWSSS_FLAG_EOM); h->hanging_som = 0; @@ -859,6 +873,9 @@ malformed: #if defined(LWS_WITH_SERVER) case LWS_CALLBACK_HTTP: + if (!h) + return -1; + lwsl_notice("%s: LWS_CALLBACK_HTTP\n", __func__); { diff --git a/lib/secure-streams/protocols/ss-h2.c b/lib/secure-streams/protocols/ss-h2.c index 4055e65a2..96d309839 100644 --- a/lib/secure-streams/protocols/ss-h2.c +++ b/lib/secure-streams/protocols/ss-h2.c @@ -40,6 +40,9 @@ secstream_h2(struct lws *wsi, enum lws_callback_reasons reason, void *user, case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: + if (!h) + return -1; + #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) if (h->being_serialized) { /* @@ -68,6 +71,10 @@ secstream_h2(struct lws *wsi, enum lws_callback_reasons reason, void *user, break; case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: + + if (!h) + return -1; + // lwsl_err("%s: h2 COMPLETED_CLIENT_HTTP\n", __func__); if (h->hanging_som) r = h->info.rx(ss_to_userobj(h), NULL, 0, LWSSS_FLAG_EOM); @@ -81,6 +88,10 @@ secstream_h2(struct lws *wsi, enum lws_callback_reasons reason, void *user, break; case LWS_CALLBACK_WSI_TX_CREDIT_GET: + + if (!h) + return -1; + /* * The peer has sent us additional tx credit... */ diff --git a/lib/secure-streams/secure-streams-client.c b/lib/secure-streams/secure-streams-client.c index a30cd2547..ef854db0f 100644 --- a/lib/secure-streams/secure-streams-client.c +++ b/lib/secure-streams/secure-streams-client.c @@ -535,6 +535,11 @@ lws_sspc_destroy(lws_sspc_handle_t **ph) h->destroying = 1; + if (h->ss_dangling_connected && h->ssi.state) { + h->ssi.state(m, NULL, LWSSSCS_DISCONNECTED, 0); + h->ss_dangling_connected = 0; + } + lws_sul_cancel(&h->sul_retry); lws_dll2_remove(&h->client_list); @@ -843,5 +848,7 @@ lws_sspc_change_handlers(struct lws_sspc_handle *h, const char * lws_sspc_tag(struct lws_sspc_handle *h) { + if (!h) + return "[null sspc]"; return lws_lc_tag(&h->lc); } diff --git a/lib/secure-streams/secure-streams-process.c b/lib/secure-streams/secure-streams-process.c index 2f6622781..530afd8c2 100644 --- a/lib/secure-streams/secure-streams-process.c +++ b/lib/secure-streams/secure-streams-process.c @@ -55,6 +55,9 @@ * Because both sides of the connection share the conn, we allocate it * during accepted adoption, and both sides point to it. * + * When .ss or .wsi close, they must NULL their entry here so no dangling + * refereneces. + * * The last one of the accepted side and the onward side to close frees it. */ @@ -62,7 +65,7 @@ struct conn { struct lws_ss_serialization_parser parser; lws_dsh_t *dsh; /* unified buffer for both sides */ - struct lws *wsi; /* the client side */ + struct lws *wsi; /* the proxy's client side */ lws_ss_handle_t *ss; /* the onward, ss side */ lws_ss_conn_states_t state; @@ -284,6 +287,7 @@ callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason, } pss->conn->wsi = wsi; + wsi->bound_ss_proxy_conn = 1; pss->conn->state = LPCSPROX_WAIT_INITIAL_TX; /* @@ -310,17 +314,39 @@ callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason, * still live... */ + assert(conn->wsi == wsi); + conn->wsi = NULL; + + lwsl_notice("%s: cli->prox link %s closing\n", + __func__, lws_wsi_tag(wsi)); + + /* sever relationship with conn */ + lws_set_opaque_user_data(wsi, NULL); + + /* + * The current wsi is decoupled from the pss / conn and + * the conn no longer has a pointer on it + */ + if (conn->ss) { struct lws *cw = conn->ss->wsi; /* - * The onward connection is around + * conn->ss is the onward connection SS */ + lwsl_info("%s: destroying %s, wsi %s\n", __func__, lws_ss_tag(conn->ss), lws_wsi_tag(conn->ss->wsi)); /* sever relationship with ss about to be deleted */ lws_set_opaque_user_data(wsi, NULL); - if (cw && wsi != cw) + conn->ss->wsi = NULL; + + if (cw && wsi != cw) { + + /* disconnect onward SS from its wsi */ + + lws_set_opaque_user_data(cw, NULL); + /* * The wsi doing the onward connection can no * longer relate to the conn... otherwise when @@ -328,11 +354,13 @@ callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason, * the ss we are about to delete */ lws_wsi_close(cw, LWS_TO_KILL_ASYNC); - conn->wsi = NULL; - conn->ss->wsi = NULL; + } lws_ss_destroy(&conn->ss); - /* conn may have gone */ + /* + * Conn may have gone, at ss destroy handler in + * ssi.state for proxied ss + */ break; } diff --git a/lib/secure-streams/secure-streams-serialize.c b/lib/secure-streams/secure-streams-serialize.c index 968169aff..bebd447fb 100644 --- a/lib/secure-streams/secure-streams-serialize.c +++ b/lib/secure-streams/secure-streams-serialize.c @@ -1311,15 +1311,25 @@ payload_ff: h->creating_cb_done = 1; } - n = ssi->state(client_pss_to_userdata(pss), - NULL, par->ctr, par->flags); - switch (n) { - case LWSSSSRET_OK: - break; - case LWSSSSRET_DISCONNECT_ME: - goto hangup; - case LWSSSSRET_DESTROY_ME: - return LWSSSSRET_DESTROY_ME; + if (ssi->state) { + h = lws_container_of(par, lws_sspc_handle_t, parser); + lws_ss_constate_t cs = (lws_ss_constate_t)par->ctr; + + if (cs == LWSSSCS_CONNECTED) + h->ss_dangling_connected = 1; + if (cs == LWSSSCS_DISCONNECTED) + h->ss_dangling_connected = 0; + + n = ssi->state(client_pss_to_userdata(pss), + NULL, (lws_ss_constate_t)par->ctr, par->flags); + switch (n) { + case LWSSSSRET_OK: + break; + case LWSSSSRET_DISCONNECT_ME: + goto hangup; + case LWSSSSRET_DESTROY_ME: + return LWSSSSRET_DESTROY_ME; + } } swallow: diff --git a/lib/secure-streams/secure-streams.c b/lib/secure-streams/secure-streams.c index a7e8e1ccc..fc5e69b9d 100644 --- a/lib/secure-streams/secure-streams.c +++ b/lib/secure-streams/secure-streams.c @@ -88,6 +88,11 @@ lws_ss_event_helper(lws_ss_handle_t *h, lws_ss_constate_t cs) if (!h) return LWSSSSRET_OK; + if (cs == LWSSSCS_CONNECTED) + h->ss_dangling_connected = 1; + if (cs == LWSSSCS_DISCONNECTED) + h->ss_dangling_connected = 0; + #if defined(LWS_WITH_SEQUENCER) /* * A parent sequencer for the ss is optional, if we have one, keep it @@ -904,6 +909,9 @@ lws_ss_destroy(lws_ss_handle_t **ppss) v = lws_get_vhost_by_name(h->context, h->policy->streamtype); #endif + if (h->ss_dangling_connected) + (void)lws_ss_event_helper(h, LWSSSCS_DISCONNECTED); + (void)lws_ss_event_helper(h, LWSSSCS_DESTROYING); lws_pt_unlock(pt); @@ -1174,5 +1182,7 @@ lws_ss_change_handlers(struct lws_ss_handle *h, const char * lws_ss_tag(struct lws_ss_handle *h) { + if (!h) + return "[null ss]"; return lws_lc_tag(&h->lc); } diff --git a/lib/secure-streams/system/auth-api.amazon.com/auth.c b/lib/secure-streams/system/auth-api.amazon.com/auth.c index 7a8fa4e0b..ccccdd35b 100644 --- a/lib/secure-streams/system/auth-api.amazon.com/auth.c +++ b/lib/secure-streams/system/auth-api.amazon.com/auth.c @@ -56,6 +56,7 @@ lws_ss_sys_auth_api_amazon_com_kick(lws_sorted_usec_list_t *sul) struct lws_context *context = lws_container_of(sul, struct lws_context, sul_api_amazon_com_kick); + lwsl_notice("%s\n", __func__); lws_state_transition_steps(&context->mgr_system, LWS_SYSTATE_OPERATIONAL); } @@ -122,7 +123,7 @@ ss_api_amazon_auth_rx(void *userobj, const uint8_t *buf, size_t len, int flags) ab = lws_system_get_blob(context, LWS_SYSBLOB_TYPE_AUTH, AUTH_IDX_LWA); /* coverity */ if (!ab) - return -1; + return LWSSSSRET_DISCONNECT_ME; if (buf) { if (flags & LWSSS_FLAG_SOM) { @@ -140,11 +141,11 @@ ss_api_amazon_auth_rx(void *userobj, const uint8_t *buf, size_t len, int flags) LWS_SYSBLOB_TYPE_AUTH, AUTH_IDX_LWA)); - return -1; + return LWSSSSRET_DISCONNECT_ME; } } if (!(flags & LWSSS_FLAG_EOM)) - return 0; + return LWSSSSRET_OK; /* we should have the auth token now */ @@ -156,7 +157,7 @@ ss_api_amazon_auth_rx(void *userobj, const uint8_t *buf, size_t len, int flags) /* we move the system state at auth connection close */ - return 0; + return LWSSSSRET_DISCONNECT_ME; } static lws_ss_state_return_t @@ -182,7 +183,7 @@ ss_api_amazon_auth_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, n = lws_system_blob_get(ab, buf, len, m->pos); if (n < 0) - return 1; + return LWSSSSRET_TX_DONT_SEND; if (!m->pos) *flags |= LWSSS_FLAG_SOM; @@ -194,7 +195,7 @@ ss_api_amazon_auth_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, m->pos = 0; /* for next time */ } - return 0; + return LWSSSSRET_OK; } static lws_ss_state_return_t @@ -253,7 +254,7 @@ ss_api_amazon_auth_state(void *userobj, void *sh, lws_ss_constate_t state, break; } - return 0; + return LWSSSSRET_OK; } int diff --git a/lib/secure-streams/system/fetch-policy/fetch-policy.c b/lib/secure-streams/system/fetch-policy/fetch-policy.c index 3dcd4d415..e84174dd2 100644 --- a/lib/secure-streams/system/fetch-policy/fetch-policy.c +++ b/lib/secure-streams/system/fetch-policy/fetch-policy.c @@ -56,14 +56,14 @@ ss_fetch_policy_rx(void *userobj, const uint8_t *buf, size_t len, int flags) if (flags & LWSSS_FLAG_EOM) m->partway = 2; - return 0; + return LWSSSSRET_OK; } static lws_ss_state_return_t ss_fetch_policy_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len, int *flags) { - return 1; + return LWSSSSRET_TX_DONT_SEND; } static void @@ -111,20 +111,16 @@ ss_fetch_policy_state(void *userobj, void *sh, lws_ss_constate_t state, switch (m->partway) { case 2: lws_sul_schedule(context, 0, &m->sul, policy_set, 1); + m->partway = 0; break; } break; case LWSSSCS_DISCONNECTED: lwsl_notice("%s: DISCONNECTED\n", __func__); - switch (m->partway) { - case 1: + if (m->partway == 1) { lws_ss_policy_parse_abandon(context); break; - - case 2: - lws_sul_schedule(context, 0, &m->sul, policy_set, 1); - break; } m->partway = 0; break; @@ -133,7 +129,7 @@ ss_fetch_policy_state(void *userobj, void *sh, lws_ss_constate_t state, break; } - return 0; + return LWSSSSRET_OK; } int diff --git a/minimal-examples/secure-streams/minimal-secure-streams-testsfail/minimal-secure-streams-testsfail.c b/minimal-examples/secure-streams/minimal-secure-streams-testsfail/minimal-secure-streams-testsfail.c index 857a0f74c..355cdf025 100644 --- a/minimal-examples/secure-streams/minimal-secure-streams-testsfail/minimal-secure-streams-testsfail.c +++ b/minimal-examples/secure-streams/minimal-secure-streams-testsfail/minimal-secure-streams-testsfail.c @@ -472,7 +472,7 @@ struct tests_seq { { "h1:80 NXDOMAIN", - "nxd_h1", 35 * LWS_US_PER_SEC, LWSSSCS_UNREACHABLE, + "nxd_h1", 65 * LWS_US_PER_SEC, LWSSSCS_UNREACHABLE, (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) | (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_ALL_RETRIES_FAILED) },