1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "comms.h"
22 #include "zbxjson.h"
23 
24 #include "zabbix_stats.h"
25 
26 /******************************************************************************
27  *                                                                            *
28  * Function: check_response                                                   *
29  *                                                                            *
30  * Purpose: Check whether JSON response is "success" or "failed"              *
31  *                                                                            *
32  * Parameters: response - [IN] the request                                    *
33  *             result   - [OUT] check result                                  *
34  *                                                                            *
35  * Return value:  SUCCEED - processed successfully                            *
36  *                FAIL - an error occurred                                    *
37  *                                                                            *
38  ******************************************************************************/
check_response(const char * response,AGENT_RESULT * result)39 static int	check_response(const char *response, AGENT_RESULT *result)
40 {
41 	struct zbx_json_parse	jp;
42 	char			buffer[MAX_STRING_LEN];
43 
44 	if (SUCCEED != zbx_json_open(response, &jp))
45 	{
46 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Value should be a JSON object."));
47 		return FAIL;
48 	}
49 
50 	if (SUCCEED != zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_RESPONSE, buffer, sizeof(buffer), NULL))
51 	{
52 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot find tag: %s.", ZBX_PROTO_TAG_RESPONSE));
53 		return FAIL;
54 	}
55 
56 	if (0 != strcmp(buffer, ZBX_PROTO_VALUE_SUCCESS))
57 	{
58 		if (SUCCEED != zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_INFO, buffer, sizeof(buffer), NULL))
59 			SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot find tag: %s.", ZBX_PROTO_TAG_INFO));
60 		else
61 			SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain internal statistics: %s", buffer));
62 
63 		return FAIL;
64 	}
65 
66 	return SUCCEED;
67 }
68 
69 /******************************************************************************
70  *                                                                            *
71  * Function: get_remote_zabbix_stats                                          *
72  *                                                                            *
73  * Purpose: send Zabbix stats request and receive the result data             *
74  *                                                                            *
75  * Parameters: json   - [IN] the request                                      *
76  *             ip     - [IN] external Zabbix instance hostname                *
77  *             port   - [IN] external Zabbix instance port                    *
78  *             result - [OUT] check result                                    *
79  *                                                                            *
80  ******************************************************************************/
get_remote_zabbix_stats(const struct zbx_json * json,const char * ip,unsigned short port,AGENT_RESULT * result)81 static void	get_remote_zabbix_stats(const struct zbx_json *json, const char *ip, unsigned short port,
82 		AGENT_RESULT *result)
83 {
84 	zbx_socket_t	s;
85 
86 	if (SUCCEED == zbx_tcp_connect(&s, CONFIG_SOURCE_IP, ip, port, CONFIG_TIMEOUT, ZBX_TCP_SEC_UNENCRYPTED,
87 			NULL, NULL))
88 	{
89 		if (SUCCEED == zbx_tcp_send(&s, json->buffer))
90 		{
91 			if (SUCCEED == zbx_tcp_recv(&s) && NULL != s.buffer)
92 			{
93 				if ('\0' == *s.buffer)
94 				{
95 					SET_MSG_RESULT(result, zbx_strdup(NULL,
96 							"Cannot obtain internal statistics: received empty response."));
97 				}
98 				else if (SUCCEED == check_response(s.buffer, result))
99 					set_result_type(result, ITEM_VALUE_TYPE_TEXT, s.buffer);
100 			}
101 			else
102 			{
103 				SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain internal statistics: %s",
104 						zbx_socket_strerror()));
105 			}
106 		}
107 		else
108 		{
109 			SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain internal statistics: %s",
110 					zbx_socket_strerror()));
111 		}
112 
113 		zbx_tcp_close(&s);
114 	}
115 	else
116 	{
117 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain internal statistics: %s",
118 				zbx_socket_strerror()));
119 	}
120 }
121 
122 /******************************************************************************
123  *                                                                            *
124  * Function: zbx_get_remote_zabbix_stats                                      *
125  *                                                                            *
126  * Purpose: create Zabbix stats request                                       *
127  *                                                                            *
128  * Parameters: ip     - [IN] external Zabbix instance hostname                *
129  *             port   - [IN] external Zabbix instance port                    *
130  *             result - [OUT] check result                                    *
131  *                                                                            *
132  * Return value:  SUCCEED - processed successfully                            *
133  *                FAIL - an error occurred                                    *
134  *                                                                            *
135  ******************************************************************************/
zbx_get_remote_zabbix_stats(const char * ip,unsigned short port,AGENT_RESULT * result)136 int	zbx_get_remote_zabbix_stats(const char *ip, unsigned short port, AGENT_RESULT *result)
137 {
138 	struct zbx_json	json;
139 
140 	zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
141 	zbx_json_addstring(&json, ZBX_PROTO_TAG_REQUEST, ZBX_PROTO_VALUE_ZABBIX_STATS, ZBX_JSON_TYPE_STRING);
142 
143 	get_remote_zabbix_stats(&json, ip, port, result);
144 
145 	zbx_json_free(&json);
146 
147 	return 0 == ISSET_MSG(result) ? SUCCEED : FAIL;
148 }
149 
150 /******************************************************************************
151  *                                                                            *
152  * Function: zbx_get_remote_zabbix_stats_queue                                *
153  *                                                                            *
154  * Purpose: create Zabbix stats queue request                                 *
155  *                                                                            *
156  * Parameters: ip     - [IN] external Zabbix instance hostname                *
157  *             port   - [IN] external Zabbix instance port                    *
158  *             from   - [IN] lower limit for delay                            *
159  *             to     - [IN] upper limit for delay                            *
160  *             result - [OUT] check result                                    *
161  *                                                                            *
162  * Return value:  SUCCEED - processed successfully                            *
163  *                FAIL - an error occurred                                    *
164  *                                                                            *
165  ******************************************************************************/
zbx_get_remote_zabbix_stats_queue(const char * ip,unsigned short port,const char * from,const char * to,AGENT_RESULT * result)166 int	zbx_get_remote_zabbix_stats_queue(const char *ip, unsigned short port, const char *from, const char *to,
167 		AGENT_RESULT *result)
168 {
169 	struct zbx_json	json;
170 
171 	zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
172 	zbx_json_addstring(&json, ZBX_PROTO_TAG_REQUEST, ZBX_PROTO_VALUE_ZABBIX_STATS, ZBX_JSON_TYPE_STRING);
173 	zbx_json_addstring(&json, ZBX_PROTO_TAG_TYPE, ZBX_PROTO_VALUE_ZABBIX_STATS_QUEUE, ZBX_JSON_TYPE_STRING);
174 
175 	zbx_json_addobject(&json, ZBX_PROTO_TAG_PARAMS);
176 
177 	if (NULL != from && '\0' != *from)
178 		zbx_json_addstring(&json, ZBX_PROTO_TAG_FROM, from, ZBX_JSON_TYPE_STRING);
179 	if (NULL != to && '\0' != *to)
180 		zbx_json_addstring(&json, ZBX_PROTO_TAG_TO, to, ZBX_JSON_TYPE_STRING);
181 
182 	zbx_json_close(&json);
183 
184 	get_remote_zabbix_stats(&json, ip, port, result);
185 
186 	zbx_json_free(&json);
187 
188 	return 0 == ISSET_MSG(result) ? SUCCEED : FAIL;
189 }
190 
ZABBIX_STATS(AGENT_REQUEST * request,AGENT_RESULT * result)191 int	ZABBIX_STATS(AGENT_REQUEST *request, AGENT_RESULT *result)
192 {
193 	const char	*ip_str, *port_str, *queue_str;
194 	unsigned short	port_number;
195 
196 	if (5 < request->nparam)
197 	{
198 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
199 		return SYSINFO_RET_FAIL;
200 	}
201 
202 	if (NULL == (ip_str = get_rparam(request, 0)) || '\0' == *ip_str)
203 		ip_str = "127.0.0.1";
204 
205 	if (NULL == (port_str = get_rparam(request, 1)) || '\0' == *port_str)
206 	{
207 		port_number = ZBX_DEFAULT_SERVER_PORT;
208 	}
209 	else if (SUCCEED != is_ushort(port_str, &port_number))
210 	{
211 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
212 		return SYSINFO_RET_FAIL;
213 	}
214 
215 	queue_str = get_rparam(request, 2);
216 
217 	if (3 > request->nparam)
218 	{
219 		if (SUCCEED != zbx_get_remote_zabbix_stats(ip_str, port_number, result))
220 			return SYSINFO_RET_FAIL;
221 	}
222 	else if (NULL != queue_str && 0 == strcmp(queue_str, ZBX_PROTO_VALUE_ZABBIX_STATS_QUEUE))
223 	{
224 		if (SUCCEED != zbx_get_remote_zabbix_stats_queue(ip_str, port_number, get_rparam(request, 3),
225 				get_rparam(request, 4), result))
226 		{
227 			return SYSINFO_RET_FAIL;
228 		}
229 	}
230 	else
231 	{
232 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
233 		return SYSINFO_RET_FAIL;
234 	}
235 
236 	return SYSINFO_RET_OK;
237 }
238