void broker_on_data_callback(Client *client, void *data) { Broker *broker = data; RemoteDSLink *link = client->sock_data; if (link) { link->ws->read_enabled = 1; wslay_event_recv(link->ws); if (link->pendingClose) { broker_close_link(link); } return; } HttpRequest req; char buf[1024]; { int read = dslink_socket_read(client->sock, buf, sizeof(buf) - 1); buf[read] = '\0'; broker_http_parse_req(&req, buf); } if (strcmp(req.uri.resource, "/conn") == 0) { if (strcmp(req.method, "POST") != 0) { log_info("invalid method on /conn \n"); broker_send_bad_request(client->sock); goto exit; } handle_conn(broker, &req, client->sock); } else if (strcmp(req.uri.resource, "/ws") == 0) { if (strcmp(req.method, "GET") != 0) { log_info("invalid method on /ws \n"); broker_send_bad_request(client->sock); goto exit; } handle_ws(broker, &req, client); return; } else { broker_send_not_found_error(client->sock); } exit: dslink_socket_close_nofree(client->sock); }
static ssize_t want_read_cb(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, int flags, void *user_data) { (void) flags; DSLink *link = user_data; int read = dslink_socket_read(link->_socket, (char *) buf, len); if (read == 0) { wslay_event_set_error(ctx, WSLAY_ERR_NO_MORE_MSG); return -1; } else if (read == DSLINK_SOCK_READ_ERR) { if (errno == MBEDTLS_ERR_SSL_WANT_READ || errno == MBEDTLS_ERR_SSL_TIMEOUT) { wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK); } else { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); } return -1; } return read; }
int dslink_handshake_connect_ws(Url *url, mbedtls_ecdh_context *key, const char *uri, const char *tempKey, const char *salt, const char *dsId, Socket **sock) { *sock = NULL; int ret = 0; unsigned char auth[90]; if ((ret = gen_auth_key(key, tempKey, salt, auth, sizeof(auth))) != 0) { goto exit; } char req[512]; size_t reqLen; { char builtUri[256]; snprintf(builtUri, sizeof(builtUri) - 1, "%s?auth=%s&dsId=%s", uri, auth, dsId); char wsKey[32]; if ((ret = gen_ws_key(wsKey, sizeof(wsKey))) != 0) { goto exit; } reqLen = snprintf(req, sizeof(req), DSLINK_WS_REQ, builtUri, url->host, url->port, wsKey); } if ((ret = dslink_socket_connect(sock, url->host, url->port, url->secure)) != 0) { *sock = NULL; goto exit; } dslink_socket_write(*sock, req, reqLen); char buf[1024]; size_t len = 0; memset(buf, 0, sizeof(buf)); while (len < (sizeof(buf) - 1)) { // Read 1 byte at a time to ensure that we don't accidentally // read web socket data int read = dslink_socket_read(*sock, buf + len, 1); if (read <= 0) { goto exit; } if (buf[len++] == '\n' && strstr(buf, "\r\n\r\n")) { if (!strstr(buf, "101 Switching Protocols")) { ret = DSLINK_HANDSHAKE_INVALID_RESPONSE; } if (strstr(buf, "401 Unauthorized")) { ret = DSLINK_HANDSHAKE_UNAUTHORIZED; } goto exit; } } // Failed to find the end of the HTTP response ret = DSLINK_HANDSHAKE_INVALID_RESPONSE; exit: if (ret != 0 && *sock) { dslink_socket_close(*sock); *sock = NULL; } return ret; }
int dslink_handshake_generate(Url *url, mbedtls_ecdh_context *key, const char *name, uint8_t isRequester, uint8_t isResponder, json_t **handshake, char **dsId) { *handshake = NULL; Socket *sock = NULL; char *resp = NULL; char *body = NULL; int ret = 0; unsigned char pubKeyBin[65]; size_t pubKeyBinLen = 0; unsigned char pubKey[90]; size_t pubKeyLen = 0; if ((errno = mbedtls_ecp_point_write_binary(&key->grp, &key->Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &pubKeyBinLen, pubKeyBin, sizeof(pubKeyBin))) != 0) { ret = DSLINK_CRYPT_KEY_ENCODE_ERR; goto exit; } if ((errno = dslink_base64_url_encode(pubKey, sizeof(pubKey), &pubKeyLen, pubKeyBin, pubKeyBinLen)) != 0) { ret = DSLINK_CRYPT_BASE64_URL_ENCODE_ERR; goto exit; } { // Generate dsId unsigned char sha[32]; mbedtls_sha256(pubKeyBin, pubKeyBinLen, sha, 0); unsigned char tmp[45]; size_t tmpLen = 0; if ((errno = dslink_base64_url_encode((unsigned char *) tmp, sizeof(tmp), &tmpLen, sha, sizeof(sha))) != 0) { ret = DSLINK_CRYPT_BASE64_URL_ENCODE_ERR; goto exit; } size_t nameLen = strlen(name); *dsId = malloc(nameLen + tmpLen + 2); if (!(*dsId)) { ret = DSLINK_ALLOC_ERR; goto exit; } memcpy(*dsId, name, nameLen); *(*dsId + nameLen) = '-'; memcpy((*dsId + nameLen + 1), (char *) tmp, tmpLen); *(*dsId + nameLen + tmpLen + 1) = '\0'; } { // Create the request body json_t *obj = json_object(); if (!obj) { ret = DSLINK_ALLOC_ERR; goto exit; } json_object_set_new(obj, "publicKey", json_string((char *) pubKey)); json_object_set_new(obj, "isRequester", json_boolean(isRequester)); json_object_set_new(obj, "isResponder", json_boolean(isResponder)); json_object_set_new(obj, "version", json_string("1.1.2")); body = json_dumps(obj, JSON_INDENT(2)); json_delete(obj); if (!body) { ret = DSLINK_ALLOC_ERR; goto exit; } } char req[512]; size_t reqLen; { char uri[128]; snprintf(uri, sizeof(uri), "%s?dsId=%s", url->uri, *dsId); reqLen = snprintf(req, sizeof(req), DSLINK_POST_REQ, uri, url->host, url->port, (int) strlen(body), body); } if ((ret = dslink_socket_connect(&sock, url->host, url->port, url->secure)) != 0) { goto exit; } dslink_socket_write(sock, req, reqLen); int respLen = 0; while (1) { char buf[1024]; int read = dslink_socket_read(sock, buf, sizeof(buf) - 1); if (read <= 0) { break; } if (resp == NULL) { resp = malloc((size_t) read + 1); if (!resp) { ret = DSLINK_ALLOC_ERR; goto exit; } respLen = read; memcpy(resp, buf, read); *(resp + respLen) = '\0'; } else { char *tmp = realloc(resp, (size_t) respLen + read + 1); if (!tmp) { free(resp); ret = DSLINK_ALLOC_ERR; goto exit; } resp = tmp; memcpy(resp + respLen, buf, read); respLen += read; *(resp + respLen) = '\0'; } } if (!resp) { ret = DSLINK_HANDSHAKE_NO_RESPONSE; goto exit; } char *index = strstr(resp, "401 Unauthorized"); if (index) { ret = DSLINK_HANDSHAKE_UNAUTHORIZED; goto exit; } index = strchr(resp, '{'); if (!index) { ret = DSLINK_HANDSHAKE_INVALID_RESPONSE; goto exit; } char *json = index; index = strrchr(json, '}'); if (!index) { ret = DSLINK_HANDSHAKE_INVALID_RESPONSE; goto exit; } *(index + 1) = '\0'; json_error_t jsonErr; *handshake = json_loads(json, 0, &jsonErr); if (!(*handshake)) { ret = DSLINK_ALLOC_ERR; goto exit; } const char *id = json_string_value(json_object_get(*handshake, "id")); if (id) { free(*dsId); size_t size = strlen(id) + 1; *dsId = malloc(size); if (!(*dsId)) { ret = DSLINK_ALLOC_ERR; json_delete(*handshake); *handshake = NULL; goto exit; } memcpy(*dsId, id, size); } exit: DSLINK_CHECKED_EXEC(free, body); DSLINK_CHECKED_EXEC(free, resp); DSLINK_CHECKED_EXEC(dslink_socket_close, sock); return ret; }