From 37d599cb65cb3c433dfd9aa2a129261c53e1f72a Mon Sep 17 00:00:00 2001 From: Timotej S <6674623+underhood@users.noreply.github.com> Date: Tue, 1 Dec 2020 18:27:03 +0100 Subject: adds child query support to ACLK (#10030) * allows cloud to query children --- aclk/aclk_common.h | 2 -- aclk/aclk_query.c | 12 ++++++--- aclk/aclk_query.h | 5 ++++ aclk/aclk_rx_msgs.c | 78 +++++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 74 insertions(+), 23 deletions(-) (limited to 'aclk') diff --git a/aclk/aclk_common.h b/aclk/aclk_common.h index 015e4b8bbd..f03ec3b5ed 100644 --- a/aclk/aclk_common.h +++ b/aclk/aclk_common.h @@ -98,8 +98,6 @@ const char *aclk_proxy_type_to_s(ACLK_PROXY_TYPE *type); #define ACLK_PROXY_ENV "env" #define ACLK_PROXY_CONFIG_VAR "proxy" -#define ACLK_CLOUD_REQ_V2_PREFIX "GET /api/v1/" - ACLK_PROXY_TYPE aclk_verify_proxy(const char *string); const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type); void safe_log_proxy_censor(char *proxy); diff --git a/aclk/aclk_query.c b/aclk/aclk_query.c index be58c2209b..09934754e3 100644 --- a/aclk/aclk_query.c +++ b/aclk/aclk_query.c @@ -60,8 +60,11 @@ static void aclk_query_free(struct aclk_query *this_query) freez(this_query->topic); if (likely(this_query->query)) freez(this_query->query); - if(this_query->data && this_query->cmd == ACLK_CMD_CLOUD_QUERY_2) - freez(this_query->data); + if(this_query->data && this_query->cmd == ACLK_CMD_CLOUD_QUERY_2) { + struct aclk_cloud_req_v2 *del = (struct aclk_cloud_req_v2 *)this_query->data; + freez(del->data); + freez(del); + } if (likely(this_query->msg_id)) freez(this_query->msg_id); freez(this_query); @@ -396,6 +399,7 @@ static int aclk_execute_query_v2(struct aclk_query *this_query) int retval = 0; usec_t t; BUFFER *local_buffer = NULL; + struct aclk_cloud_req_v2 *cloud_req = (struct aclk_cloud_req_v2 *)this_query->data; #ifdef NETDATA_WITH_ZLIB int z_ret; @@ -422,11 +426,11 @@ static int aclk_execute_query_v2(struct aclk_query *this_query) mysep = strrchr(this_query->query, '/'); // execute the query - t = aclk_web_api_request_v1(localhost, w, mysep ? mysep + 1 : "noop", this_query->created_boot_time); + t = aclk_web_api_request_v1(cloud_req->host, w, mysep ? mysep + 1 : "noop", this_query->created_boot_time); #ifdef NETDATA_WITH_ZLIB // check if gzip encoding can and should be used - if ((start = strstr((char *)this_query->data, WEB_HDR_ACCEPT_ENC))) { + if ((start = strstr(cloud_req->data, WEB_HDR_ACCEPT_ENC))) { start += strlen(WEB_HDR_ACCEPT_ENC); end = strstr(start, "\x0D\x0A"); start = strstr(start, "gzip"); diff --git a/aclk/aclk_query.h b/aclk/aclk_query.h index 8c7d7cbd07..53eef13922 100644 --- a/aclk/aclk_query.h +++ b/aclk/aclk_query.h @@ -25,6 +25,11 @@ struct aclk_query_threads { int count; }; +struct aclk_cloud_req_v2 { + char *data; + RRDHOST *host; +}; + void *aclk_query_main_thread(void *ptr); int aclk_queue_query(char *token, void *data, char *msg_type, char *query, int run_after, int internal, ACLK_CMD cmd); diff --git a/aclk/aclk_rx_msgs.c b/aclk/aclk_rx_msgs.c index b90f60d9a8..73c1f8673f 100644 --- a/aclk/aclk_rx_msgs.c +++ b/aclk/aclk_rx_msgs.c @@ -15,18 +15,55 @@ static inline int aclk_extract_v2_data(char *payload, char **data) return 0; } -static inline int aclk_v2_payload_get_query(const char *payload, struct aclk_request *req) +#define ACLK_GET_REQ "GET " +#define ACLK_CHILD_REQ "/host/" +#define ACLK_CLOUD_REQ_V2_PREFIX "/api/v1/" +#define STRNCMP_CONSTANT_PREFIX(str, const_pref) strncmp(str, const_pref, strlen(const_pref)) +static inline int aclk_v2_payload_get_query(struct aclk_cloud_req_v2 *cloud_req, struct aclk_request *req) { - const char *start, *end; + const char *start, *end, *ptr; + char uuid_str[UUID_STR_LEN]; + uuid_t uuid; - if(strncmp(payload, ACLK_CLOUD_REQ_V2_PREFIX, strlen(ACLK_CLOUD_REQ_V2_PREFIX))) { - errno = 0; + errno = 0; + + if(STRNCMP_CONSTANT_PREFIX(cloud_req->data, ACLK_GET_REQ)) { + error("Only accepting GET HTTP requests from CLOUD"); + return 1; + } + start = ptr = cloud_req->data + strlen(ACLK_GET_REQ); + + if(!STRNCMP_CONSTANT_PREFIX(ptr, ACLK_CHILD_REQ)) { + ptr += strlen(ACLK_CHILD_REQ); + if(strlen(ptr) < UUID_STR_LEN) { + error("the child id in URL too short \"%s\"", start); + return 1; + } + + strncpyz(uuid_str, ptr, UUID_STR_LEN - 1); + + for(int i = 0; i < UUID_STR_LEN && uuid_str[i]; i++) + uuid_str[i] = tolower(uuid_str[i]); + + if(ptr[0] && uuid_parse(uuid_str, uuid)) { + error("Got Child query (/host/XXX/...) host id \"%s\" doesn't look like valid GUID", uuid_str); + return 1; + } + ptr += UUID_STR_LEN - 1; + + cloud_req->host = rrdhost_find_by_guid(uuid_str, 0); + if(!cloud_req->host) { + error("Cannot find host with GUID \"%s\"", uuid_str); + return 1; + } + } + + if(STRNCMP_CONSTANT_PREFIX(ptr, ACLK_CLOUD_REQ_V2_PREFIX)) { error("Only accepting requests that start with \"%s\" from CLOUD.", ACLK_CLOUD_REQ_V2_PREFIX); return 1; } - start = payload + 4; - if(!(end = strstr(payload, " HTTP/1.1\x0D\x0A"))) { + if(!(end = strstr(ptr, " HTTP/1.1\x0D\x0A"))) { errno = 0; error("Doesn't look like HTTP GET request."); return 1; @@ -88,6 +125,7 @@ static int aclk_handle_cloud_request_v2(struct aclk_request *cloud_to_agent, cha { HTTP_CHECK_AGENT_INITIALIZED(); + struct aclk_cloud_req_v2 *cloud_req; char *data; errno = 0; @@ -104,32 +142,38 @@ static int aclk_handle_cloud_request_v2(struct aclk_request *cloud_to_agent, cha return 1; } - if (unlikely(aclk_v2_payload_get_query(data, cloud_to_agent))) { + cloud_req = mallocz(sizeof(struct aclk_cloud_req_v2)); + cloud_req->data = data; + cloud_req->host = localhost; + + if (unlikely(aclk_v2_payload_get_query(cloud_req, cloud_to_agent))) { error("Could not extract payload from query"); - freez(data); - return 1; + goto cleanup; } if (unlikely(!cloud_to_agent->callback_topic)) { error("Missing callback_topic"); - freez(data); - return 1; + goto cleanup; } if (unlikely(!cloud_to_agent->msg_id)) { error("Missing msg_id"); - freez(data); - return 1; + goto cleanup; } // aclk_queue_query takes ownership of data pointer if (unlikely(aclk_queue_query( - cloud_to_agent->callback_topic, data, cloud_to_agent->msg_id, cloud_to_agent->payload, 0, 0, - ACLK_CMD_CLOUD_QUERY_2))) - debug(D_ACLK, "ACLK failed to queue incoming \"http\" message"); + cloud_to_agent->callback_topic, cloud_req, cloud_to_agent->msg_id, cloud_to_agent->payload, 0, 0, + ACLK_CMD_CLOUD_QUERY_2))) { + error("ACLK failed to queue incoming \"http\" v2 message"); + goto cleanup; + } - UNUSED(cloud_to_agent); return 0; +cleanup: + freez(cloud_req->data); + freez(cloud_req); + return 1; } // This handles `version` message from cloud used to negotiate -- cgit v1.2.3