1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

ss: enforce balanced CONNECT vs DISCONNECT

This commit is contained in:
Andy Green 2020-12-27 16:05:48 +00:00
parent b5d656058f
commit 93f54c61c5
14 changed files with 145 additions and 38 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -27,6 +27,8 @@
const char *
lws_wsi_tag(struct lws *wsi)
{
if (!wsi)
return "[null wsi]";
return lws_lc_tag(&wsi->lc);
}

View file

@ -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 {

View file

@ -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__);
{

View file

@ -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...
*/

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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:

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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)
},