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