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 "sysinfo.h"
22 #include "zbxregexp.h"
23 
24 #include "comms.h"
25 #include "cfg.h"
26 
27 #include "http.h"
28 
29 #define ZBX_MAX_WEBPAGE_SIZE	(1 * 1024 * 1024)
30 static const char URI_PROHIBIT_CHARS[] = {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF,0x10,0x11,0x12,\
31 	0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x7F,0};
32 
get_http_page(const char * host,const char * path,unsigned short port,char * buffer,size_t max_buffer_len,char ** error)33 static int	get_http_page(const char *host, const char *path, unsigned short port, char *buffer,
34 		size_t max_buffer_len, char **error)
35 {
36 	int		ret;
37 	char		*wrong_chr;
38 	char		request[MAX_STRING_LEN];
39 	zbx_socket_t	s;
40 
41 	if (NULL != (wrong_chr = strpbrk(host, URI_PROHIBIT_CHARS)))
42 	{
43 		*error = zbx_dsprintf(NULL, "Incorrect hostname expression. Check hostname part after: %.*s.",
44 				(int)(wrong_chr - host), host);
45 		return SYSINFO_RET_FAIL;
46 	}
47 
48 	if (NULL != (wrong_chr = strpbrk(path, URI_PROHIBIT_CHARS)))
49 	{
50 		*error = zbx_dsprintf(NULL, "Incorrect path expression. Check path part after: %.*s.",
51 				(int)(wrong_chr - path), path);
52 		return SYSINFO_RET_FAIL;
53 	}
54 
55 	if (SUCCEED == (ret = zbx_tcp_connect(&s, CONFIG_SOURCE_IP, host, port, CONFIG_TIMEOUT,
56 			ZBX_TCP_SEC_UNENCRYPTED, NULL, NULL)))
57 	{
58 		zbx_snprintf(request, sizeof(request),
59 				"GET %s%s HTTP/1.1\r\n"
60 				"Host: %s\r\n"
61 				"Connection: close\r\n"
62 				"\r\n",
63 				'/' != *path ? "/" : "", path, host);
64 
65 		if (SUCCEED == (ret = zbx_tcp_send_raw(&s, request)))
66 		{
67 			if (SUCCEED == (ret = SUCCEED_OR_FAIL(zbx_tcp_recv_ext(&s, ZBX_TCP_READ_UNTIL_CLOSE, 0))))
68 			{
69 				if (NULL != buffer)
70 					zbx_strlcpy(buffer, s.buffer, max_buffer_len);
71 			}
72 		}
73 
74 		zbx_tcp_close(&s);
75 	}
76 
77 	if (FAIL == ret)
78 	{
79 		*error = zbx_dsprintf(NULL, "HTTP get error: %s", zbx_socket_strerror());
80 		return SYSINFO_RET_FAIL;
81 	}
82 
83 	return SYSINFO_RET_OK;
84 }
85 
WEB_PAGE_GET(AGENT_REQUEST * request,AGENT_RESULT * result)86 int	WEB_PAGE_GET(AGENT_REQUEST *request, AGENT_RESULT *result)
87 {
88 	char		*hostname, *path_str, *port_str, buffer[MAX_BUFFER_LEN], path[MAX_STRING_LEN], *error;
89 	unsigned short	port_number;
90 
91 	if (3 < request->nparam)
92 	{
93 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
94 		return SYSINFO_RET_FAIL;
95 	}
96 
97 	hostname = get_rparam(request, 0);
98 	path_str = get_rparam(request, 1);
99 	port_str = get_rparam(request, 2);
100 
101 	if (NULL == hostname || '\0' == *hostname)
102 	{
103 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
104 		return SYSINFO_RET_FAIL;
105 	}
106 
107 	if (NULL == path_str)
108 		*path = '\0';
109 	else
110 		strscpy(path, path_str);
111 
112 	if (NULL == port_str || '\0' == *port_str)
113 		port_number = ZBX_DEFAULT_HTTP_PORT;
114 	else if (FAIL == is_ushort(port_str, &port_number))
115 	{
116 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
117 		return SYSINFO_RET_FAIL;
118 	}
119 
120 	if (SYSINFO_RET_OK == get_http_page(hostname, path, port_number, buffer, sizeof(buffer), &error))
121 	{
122 		zbx_rtrim(buffer, "\r\n");
123 		SET_TEXT_RESULT(result, zbx_strdup(NULL, buffer));
124 	}
125 	else
126 	{
127 		SET_MSG_RESULT(result, error);
128 		return SYSINFO_RET_FAIL;
129 	}
130 
131 	return SYSINFO_RET_OK;
132 }
133 
WEB_PAGE_PERF(AGENT_REQUEST * request,AGENT_RESULT * result)134 int	WEB_PAGE_PERF(AGENT_REQUEST *request, AGENT_RESULT *result)
135 {
136 	char		*hostname, path[MAX_STRING_LEN], *port_str, *path_str, *error;
137 	double		start_time;
138 	unsigned short	port_number;
139 
140 	if (3 < request->nparam)
141 	{
142 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
143 		return SYSINFO_RET_FAIL;
144 	}
145 
146 	hostname = get_rparam(request, 0);
147 	path_str = get_rparam(request, 1);
148 	port_str = get_rparam(request, 2);
149 
150 	if (NULL == hostname || '\0' == *hostname)
151 	{
152 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
153 		return SYSINFO_RET_FAIL;
154 	}
155 
156 	if (NULL == path_str || '\0' == *path_str)
157 		*path = '\0';
158 	else
159 		strscpy(path, path_str);
160 
161 	if (NULL == port_str || '\0' == *port_str)
162 		port_number = ZBX_DEFAULT_HTTP_PORT;
163 	else if (FAIL == is_ushort(port_str, &port_number))
164 	{
165 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
166 		return SYSINFO_RET_FAIL;
167 	}
168 
169 	start_time = zbx_time();
170 
171 	if (SYSINFO_RET_OK == get_http_page(hostname, path, port_number, NULL, 0, &error))
172 	{
173 		SET_DBL_RESULT(result, zbx_time() - start_time);
174 
175 	}
176 	else
177 	{
178 		SET_MSG_RESULT(result, error);
179 		return SYSINFO_RET_FAIL;
180 	}
181 
182 	return SYSINFO_RET_OK;
183 }
184 
WEB_PAGE_REGEXP(AGENT_REQUEST * request,AGENT_RESULT * result)185 int	WEB_PAGE_REGEXP(AGENT_REQUEST *request, AGENT_RESULT *result)
186 {
187 	char		*hostname, *path_str, *port_str, *regexp, *length_str, path[MAX_STRING_LEN],
188 			*buffer = NULL, *ptr = NULL, *str, *newline, *error;
189 	int		length;
190 	const char	*output;
191 	unsigned short	port_number;
192 
193 	if (6 < request->nparam)
194 	{
195 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
196 		return SYSINFO_RET_FAIL;
197 	}
198 
199 	if (4 > request->nparam)
200 	{
201 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid number of parameters."));
202 		return SYSINFO_RET_FAIL;
203 	}
204 
205 	hostname = get_rparam(request, 0);
206 	path_str = get_rparam(request, 1);
207 	port_str = get_rparam(request, 2);
208 	regexp = get_rparam(request, 3);
209 	length_str = get_rparam(request, 4);
210 	output = get_rparam(request, 5);
211 
212 	if ('\0' == *hostname)
213 	{
214 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
215 		return SYSINFO_RET_FAIL;
216 	}
217 
218 	if ('\0' == *path_str)
219 		*path = '\0';
220 	else
221 		strscpy(path, path_str);
222 
223 	if ('\0' == *port_str)
224 		port_number = ZBX_DEFAULT_HTTP_PORT;
225 	else if (FAIL == is_ushort(port_str, &port_number))
226 	{
227 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
228 		return SYSINFO_RET_FAIL;
229 	}
230 
231 	if (NULL == length_str || '\0' == *length_str)
232 		length = MAX_BUFFER_LEN - 1;
233 	else if (FAIL == is_uint31_1(length_str, &length))
234 	{
235 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid fifth parameter."));
236 		return SYSINFO_RET_FAIL;
237 	}
238 
239 	/* by default return the matched part of web page */
240 	if (NULL == output || '\0' == *output)
241 		output = "\\0";
242 
243 	buffer = zbx_malloc(buffer, ZBX_MAX_WEBPAGE_SIZE);
244 
245 	if (SYSINFO_RET_OK == get_http_page(hostname, path, port_number, buffer, ZBX_MAX_WEBPAGE_SIZE, &error))
246 	{
247 		for (str = buffer; ;)
248 		{
249 			if (NULL != (newline = strchr(str, '\n')))
250 			{
251 				if (str != newline && '\r' == newline[-1])
252 					newline[-1] = '\0';
253 				else
254 					*newline = '\0';
255 			}
256 
257 			if (NULL != (ptr = zbx_regexp_sub(str, regexp, output)))
258 				break;
259 
260 			if (NULL != newline)
261 				str = newline + 1;
262 			else
263 				break;
264 		}
265 	}
266 	else
267 	{
268 		zbx_free(buffer);
269 		SET_MSG_RESULT(result, error);
270 		return SYSINFO_RET_FAIL;
271 	}
272 
273 	if (NULL != ptr)
274 		SET_STR_RESULT(result, ptr);
275 	else
276 		SET_STR_RESULT(result, zbx_strdup(NULL, ""));
277 
278 	zbx_free(buffer);
279 
280 	return SYSINFO_RET_OK;
281 }
282