/* ** Copyright (C) 2001-2025 Zabbix SIA ** ** This program is free software: you can redistribute it and/or modify it under the terms of ** the GNU Affero General Public License as published by the Free Software Foundation, version 3. ** ** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; ** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** See the GNU Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License along with this program. ** If not, see <https://www.gnu.org/licenses/>. **/ #include "trapper_server.h" #include "proxydata.h" #include "taskmanager/taskmanager_server.h" #include "cachehistory/cachehistory_server.h" #include "discovery/discovery_server.h" #include "autoreg/autoreg_server.h" #include "zbxdbwrap.h" #include "zbxnix.h" #include "zbxcommshigh.h" #include "zbxjson.h" #include "zbxtasks.h" int zbx_send_proxy_data_response(const zbx_dc_proxy_t *proxy, zbx_socket_t *sock, const char *info, int status, int upload_status, int config_timeout) { struct zbx_json json; zbx_vector_tm_task_t tasks; int ret; unsigned char flags = ZBX_TCP_PROTOCOL; zbx_vector_tm_task_create(&tasks); zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN); switch (upload_status) { case ZBX_PROXY_UPLOAD_DISABLED: zbx_json_addstring(&json, ZBX_PROTO_TAG_HISTORY_UPLOAD, ZBX_PROTO_VALUE_HISTORY_UPLOAD_DISABLED, ZBX_JSON_TYPE_STRING); break; case ZBX_PROXY_UPLOAD_ENABLED: zbx_json_addstring(&json, ZBX_PROTO_TAG_HISTORY_UPLOAD, ZBX_PROTO_VALUE_HISTORY_UPLOAD_ENABLED, ZBX_JSON_TYPE_STRING); break; } if (SUCCEED == status) { zbx_json_addstring(&json, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_SUCCESS, ZBX_JSON_TYPE_STRING); zbx_tm_get_remote_tasks(&tasks, proxy->proxyid, proxy->compatibility); } else zbx_json_addstring(&json, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_FAILED, ZBX_JSON_TYPE_STRING); if (NULL != info && '\0' != *info) zbx_json_addstring(&json, ZBX_PROTO_TAG_INFO, info, ZBX_JSON_TYPE_STRING); if (0 != tasks.values_num) zbx_tm_json_serialize_tasks(&json, &tasks); flags |= ZBX_TCP_COMPRESS; if (SUCCEED == (ret = zbx_tcp_send_ext(sock, json.buffer, strlen(json.buffer), 0, flags, config_timeout))) { if (0 != tasks.values_num) zbx_tm_update_task_status(&tasks, ZBX_TM_STATUS_INPROGRESS); } zbx_json_free(&json); zbx_vector_tm_task_clear_ext(&tasks, zbx_tm_task_free); zbx_vector_tm_task_destroy(&tasks); return ret; } /****************************************************************************** * * * Purpose: checks if 'proxy data' packet has historical data * * * * Return value: SUCCEED - 'proxy data' contains no historical records * * FAIL - otherwise * * * ******************************************************************************/ static int proxy_data_no_history(const struct zbx_json_parse *jp) { struct zbx_json_parse jp_data; if (SUCCEED == zbx_json_brackets_by_name(jp, ZBX_PROTO_TAG_HISTORY_DATA, &jp_data)) return FAIL; if (SUCCEED == zbx_json_brackets_by_name(jp, ZBX_PROTO_TAG_DISCOVERY_DATA, &jp_data)) return FAIL; if (SUCCEED == zbx_json_brackets_by_name(jp, ZBX_PROTO_TAG_AUTOREGISTRATION, &jp_data)) return FAIL; if (SUCCEED == zbx_json_brackets_by_name(jp, ZBX_PROTO_TAG_INTERFACE_AVAILABILITY, &jp_data)) return FAIL; return SUCCEED; } /****************************************************************************** * * * Purpose: receives 'proxy data' request from proxy * * * * Parameters: sock - [IN] connection socket * * jp - [IN] received JSON data * * ts - [IN] connection timestamp * * events_cbs - [IN] * * config_timeout - [IN] * * proxydata_frequency - [IN] * * * ******************************************************************************/ void recv_proxy_data(zbx_socket_t *sock, const struct zbx_json_parse *jp, const zbx_timespec_t *ts, const zbx_events_funcs_t *events_cbs, int config_timeout, int proxydata_frequency) { int ret = FAIL, upload_status = 0, status, version_int, responded = 0; char *error = NULL, *version_str = NULL; zbx_dc_proxy_t proxy; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); if (SUCCEED != (status = zbx_get_active_proxy_from_request(jp, &proxy, &error))) { zabbix_log(LOG_LEVEL_WARNING, "cannot parse proxy data from active proxy at \"%s\": %s", sock->peer, error); goto out; } if (SUCCEED != (status = zbx_proxy_check_permissions(&proxy, sock, &error))) { zabbix_log(LOG_LEVEL_WARNING, "cannot accept connection from proxy \"%s\" at \"%s\", allowed address:" " \"%s\": %s", proxy.name, sock->peer, proxy.allowed_addresses, error); goto out; } version_str = zbx_get_proxy_protocol_version_str(jp); version_int = zbx_get_proxy_protocol_version_int(version_str); if (SUCCEED != zbx_check_protocol_version(&proxy, version_int)) { upload_status = ZBX_PROXY_UPLOAD_DISABLED; error = zbx_strdup(error, "current proxy version is not supported by server"); goto reply; } if (FAIL == (ret = zbx_hc_check_proxy(proxy.proxyid)) || SUCCEED == zbx_vps_monitor_capped()) { upload_status = ZBX_PROXY_UPLOAD_DISABLED; ret = proxy_data_no_history(jp); } else upload_status = ZBX_PROXY_UPLOAD_ENABLED; if (SUCCEED == ret) { if (SUCCEED != (ret = zbx_process_proxy_data(&proxy, jp, ts, PROXY_OPERATING_MODE_ACTIVE, events_cbs, proxydata_frequency, zbx_discovery_update_host_server, zbx_discovery_update_service_server, zbx_discovery_update_service_down_server, zbx_discovery_find_host_server, zbx_discovery_update_drule_server, zbx_autoreg_host_free_server, zbx_autoreg_flush_hosts_server, zbx_autoreg_prepare_host_server, NULL, &error))) { zabbix_log(LOG_LEVEL_WARNING, "received invalid proxy data from proxy \"%s\" at \"%s\": %s", proxy.name, sock->peer, error); goto out; } } if (!ZBX_IS_RUNNING()) { error = zbx_strdup(error, "Zabbix server shutdown in progress"); zabbix_log(LOG_LEVEL_WARNING, "cannot process proxy data from active proxy at \"%s\": %s", sock->peer, error); ret = FAIL; goto out; } reply: zbx_send_proxy_data_response(&proxy, sock, error, ret, upload_status, config_timeout); responded = 1; out: if (SUCCEED == status) /* moved the unpredictable long operation to the end */ /* we are trying to save info about lastaccess to detect communication problem */ { time_t lastaccess; if (ZBX_PROXY_UPLOAD_DISABLED == upload_status) lastaccess = (int)time(NULL); else lastaccess = ts->sec; zbx_update_proxy_data(&proxy, version_str, version_int, lastaccess, 0); } if (0 == responded) { int flags = ZBX_TCP_PROTOCOL; if (0 != (sock->protocol & ZBX_TCP_COMPRESS)) flags |= ZBX_TCP_COMPRESS; zbx_send_response_ext(sock, ret, error, NULL, flags, config_timeout); } zbx_free(error); zbx_free(version_str); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); }