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 "comms.h"
23 #include "log.h"
24 #include "cfg.h"
25 #include "telnet.h"
26 #include "../common/net.h"
27 #include "ntp.h"
28 #include "simple.h"
29
30 #ifdef HAVE_LDAP
31 # include <ldap.h>
32 #endif
33
34 #ifdef HAVE_LBER_H
35 # include <lber.h>
36 #endif
37
38 ZBX_METRIC parameters_simple[] =
39 /* KEY FLAG FUNCTION TEST PARAMETERS */
40 {
41 {"net.tcp.service", CF_HAVEPARAMS, CHECK_SERVICE, "ssh,127.0.0.1,22"},
42 {"net.tcp.service.perf",CF_HAVEPARAMS, CHECK_SERVICE_PERF, "ssh,127.0.0.1,22"},
43 {"net.udp.service", CF_HAVEPARAMS, CHECK_SERVICE, "ntp,127.0.0.1,123"},
44 {"net.udp.service.perf",CF_HAVEPARAMS, CHECK_SERVICE_PERF, "ntp,127.0.0.1,123"},
45 {NULL}
46 };
47
48 #ifdef HAVE_LDAP
check_ldap(const char * host,unsigned short port,int timeout,int * value_int)49 static int check_ldap(const char *host, unsigned short port, int timeout, int *value_int)
50 {
51 LDAP *ldap = NULL;
52 LDAPMessage *res = NULL;
53 LDAPMessage *msg = NULL;
54 BerElement *ber = NULL;
55
56 char *attrs[2] = {"namingContexts", NULL };
57 char *attr = NULL;
58 char **valRes = NULL;
59 int ldapErr = 0;
60
61 zbx_alarm_on(timeout);
62
63 *value_int = 0;
64
65 if (NULL == (ldap = ldap_init(host, port)))
66 {
67 zabbix_log(LOG_LEVEL_DEBUG, "LDAP - initialization failed [%s:%hu]", host, port);
68 goto lbl_ret;
69 }
70
71 if (LDAP_SUCCESS != (ldapErr = ldap_search_s(ldap, "", LDAP_SCOPE_BASE, "(objectClass=*)", attrs, 0, &res)))
72 {
73 zabbix_log(LOG_LEVEL_DEBUG, "LDAP - searching failed [%s] [%s]", host, ldap_err2string(ldapErr));
74 goto lbl_ret;
75 }
76
77 if (NULL == (msg = ldap_first_entry(ldap, res)))
78 {
79 zabbix_log(LOG_LEVEL_DEBUG, "LDAP - empty sort result. [%s] [%s]", host, ldap_err2string(ldapErr));
80 goto lbl_ret;
81 }
82
83 if (NULL == (attr = ldap_first_attribute(ldap, msg, &ber)))
84 {
85 zabbix_log(LOG_LEVEL_DEBUG, "LDAP - empty first entry result. [%s] [%s]", host, ldap_err2string(ldapErr));
86 goto lbl_ret;
87 }
88
89 valRes = ldap_get_values(ldap, msg, attr);
90
91 *value_int = 1;
92 lbl_ret:
93 zbx_alarm_off();
94
95 if (NULL != valRes)
96 ldap_value_free(valRes);
97 if (NULL != attr)
98 ldap_memfree(attr);
99 if (NULL != ber)
100 ber_free(ber, 0);
101 if (NULL != res)
102 ldap_msgfree(res);
103 if (NULL != ldap)
104 ldap_unbind(ldap);
105
106 return SYSINFO_RET_OK;
107 }
108 #endif /* HAVE_LDAP */
109
check_ssh(const char * host,unsigned short port,int timeout,int * value_int)110 static int check_ssh(const char *host, unsigned short port, int timeout, int *value_int)
111 {
112 int ret, major, minor;
113 zbx_socket_t s;
114 char send_buf[MAX_STRING_LEN];
115 const char *buf;
116
117 *value_int = 0;
118
119 if (SUCCEED == (ret = zbx_tcp_connect(&s, CONFIG_SOURCE_IP, host, port, timeout, ZBX_TCP_SEC_UNENCRYPTED, NULL,
120 NULL)))
121 {
122 while (NULL != (buf = zbx_tcp_recv_line(&s)))
123 {
124 /* parse buf for SSH identification string as per RFC 4253, section 4.2 */
125 if (2 == sscanf(buf, "SSH-%d.%d-%*s", &major, &minor))
126 {
127 zbx_snprintf(send_buf, sizeof(send_buf), "SSH-%d.%d-zabbix_agent\r\n", major, minor);
128 *value_int = 1;
129 break;
130 }
131 }
132
133 if (0 == *value_int)
134 strscpy(send_buf, "0\n");
135
136 ret = zbx_tcp_send_raw(&s, send_buf);
137 zbx_tcp_close(&s);
138 }
139
140 if (FAIL == ret)
141 zabbix_log(LOG_LEVEL_DEBUG, "SSH check error: %s", zbx_socket_strerror());
142
143 return SYSINFO_RET_OK;
144 }
145
146 #ifdef HAVE_LIBCURL
check_https(const char * host,unsigned short port,int timeout,int * value_int)147 static int check_https(const char *host, unsigned short port, int timeout, int *value_int)
148 {
149 const char *__function_name = "check_https";
150 CURL *easyhandle;
151 CURLoption opt;
152 CURLcode err;
153 char https_host[MAX_STRING_LEN];
154
155 *value_int = 0;
156
157 if (NULL == (easyhandle = curl_easy_init()))
158 {
159 zabbix_log(LOG_LEVEL_DEBUG, "%s: could not init cURL library", __function_name);
160 goto clean;
161 }
162
163 if (SUCCEED == is_ip6(host))
164 zbx_snprintf(https_host, sizeof(https_host), "%s[%s]", (0 == strncmp(host, "https://", 8) ? "" : "https://"), host);
165 else
166 zbx_snprintf(https_host, sizeof(https_host), "%s%s", (0 == strncmp(host, "https://", 8) ? "" : "https://"), host);
167
168 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_USERAGENT, "Zabbix " ZABBIX_VERSION)) ||
169 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_URL, https_host)) ||
170 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_PORT, (long)port)) ||
171 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_NOBODY, 1L)) ||
172 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_SSL_VERIFYPEER, 0L)) ||
173 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_SSL_VERIFYHOST, 0L)) ||
174 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_TIMEOUT, (long)timeout)))
175 {
176 zabbix_log(LOG_LEVEL_DEBUG, "%s: could not set cURL option [%d]: %s",
177 __function_name, (int)opt, curl_easy_strerror(err));
178 goto clean;
179 }
180
181 if (NULL != CONFIG_SOURCE_IP)
182 {
183 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_INTERFACE, CONFIG_SOURCE_IP)))
184 {
185 zabbix_log(LOG_LEVEL_DEBUG, "%s: could not set source interface option [%d]: %s",
186 __function_name, (int)opt, curl_easy_strerror(err));
187 goto clean;
188 }
189 }
190
191 if (CURLE_OK == (err = curl_easy_perform(easyhandle)))
192 *value_int = 1;
193 else
194 zabbix_log(LOG_LEVEL_DEBUG, "%s: curl_easy_perform failed for [%s:%hu]: %s",
195 __function_name, host, port, curl_easy_strerror(err));
196 clean:
197 curl_easy_cleanup(easyhandle);
198
199 return SYSINFO_RET_OK;
200 }
201 #endif /* HAVE_LIBCURL */
202
check_telnet(const char * host,unsigned short port,int timeout,int * value_int)203 static int check_telnet(const char *host, unsigned short port, int timeout, int *value_int)
204 {
205 const char *__function_name = "check_telnet";
206 zbx_socket_t s;
207 #ifdef _WINDOWS
208 u_long argp = 1;
209 #else
210 int flags;
211 #endif
212 *value_int = 0;
213
214 if (SUCCEED == zbx_tcp_connect(&s, CONFIG_SOURCE_IP, host, port, timeout, ZBX_TCP_SEC_UNENCRYPTED, NULL, NULL))
215 {
216 #ifdef _WINDOWS
217 ioctlsocket(s.socket, FIONBIO, &argp); /* non-zero value sets the socket to non-blocking */
218 #else
219 flags = fcntl(s.socket, F_GETFL);
220 if (0 == (flags & O_NONBLOCK))
221 fcntl(s.socket, F_SETFL, flags | O_NONBLOCK);
222 #endif
223
224 if (SUCCEED == telnet_test_login(s.socket))
225 *value_int = 1;
226 else
227 zabbix_log(LOG_LEVEL_DEBUG, "Telnet check error: no login prompt");
228
229 zbx_tcp_close(&s);
230 }
231 else
232 zabbix_log(LOG_LEVEL_DEBUG, "%s error: %s", __function_name, zbx_socket_strerror());
233
234 return SYSINFO_RET_OK;
235 }
236
237 /* validation functions for service checks */
validate_smtp(const char * line)238 static int validate_smtp(const char *line)
239 {
240 if (0 == strncmp(line, "220", 3))
241 {
242 if ('-' == line[3])
243 return ZBX_TCP_EXPECT_IGNORE;
244
245 if ('\0' == line[3] || ' ' == line[3])
246 return ZBX_TCP_EXPECT_OK;
247 }
248
249 return ZBX_TCP_EXPECT_FAIL;
250 }
251
validate_ftp(const char * line)252 static int validate_ftp(const char *line)
253 {
254 if (0 == strncmp(line, "220 ", 4))
255 return ZBX_TCP_EXPECT_OK;
256
257 return ZBX_TCP_EXPECT_IGNORE;
258 }
259
validate_pop(const char * line)260 static int validate_pop(const char *line)
261 {
262 return 0 == strncmp(line, "+OK", 3) ? ZBX_TCP_EXPECT_OK : ZBX_TCP_EXPECT_FAIL;
263 }
264
validate_nntp(const char * line)265 static int validate_nntp(const char *line)
266 {
267 if (0 == strncmp(line, "200", 3) || 0 == strncmp(line, "201", 3))
268 return ZBX_TCP_EXPECT_OK;
269
270 return ZBX_TCP_EXPECT_FAIL;
271 }
272
validate_imap(const char * line)273 static int validate_imap(const char *line)
274 {
275 return 0 == strncmp(line, "* OK", 4) ? ZBX_TCP_EXPECT_OK : ZBX_TCP_EXPECT_FAIL;
276 }
277
check_service(AGENT_REQUEST * request,const char * default_addr,AGENT_RESULT * result,int perf)278 int check_service(AGENT_REQUEST *request, const char *default_addr, AGENT_RESULT *result, int perf)
279 {
280 unsigned short port = 0;
281 char *service, *ip_str, ip[MAX_ZBX_DNSNAME_LEN + 1], *port_str;
282 int value_int, ret = SYSINFO_RET_FAIL;
283 double check_time;
284
285 check_time = zbx_time();
286
287 if (3 < request->nparam)
288 {
289 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
290 return SYSINFO_RET_FAIL;
291 }
292
293 service = get_rparam(request, 0);
294 ip_str = get_rparam(request, 1);
295 port_str = get_rparam(request, 2);
296
297 if (NULL == service || '\0' == *service)
298 {
299 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
300 return SYSINFO_RET_FAIL;
301 }
302
303 if (NULL == ip_str || '\0' == *ip_str)
304 strscpy(ip, default_addr);
305 else
306 strscpy(ip, ip_str);
307
308 if (NULL != port_str && '\0' != *port_str && SUCCEED != is_ushort(port_str, &port))
309 {
310 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
311 return SYSINFO_RET_FAIL;
312 }
313
314 if (0 == strncmp("net.tcp.service", get_rkey(request), 15))
315 {
316 if (0 == strcmp(service, "ssh"))
317 {
318 if (NULL == port_str || '\0' == *port_str)
319 port = ZBX_DEFAULT_SSH_PORT;
320 ret = check_ssh(ip, port, CONFIG_TIMEOUT, &value_int);
321 }
322 else if (0 == strcmp(service, "ldap"))
323 {
324 #ifdef HAVE_LDAP
325 if (NULL == port_str || '\0' == *port_str)
326 port = ZBX_DEFAULT_LDAP_PORT;
327 ret = check_ldap(ip, port, CONFIG_TIMEOUT, &value_int);
328 #else
329 SET_MSG_RESULT(result, zbx_strdup(NULL, "Support for LDAP check was not compiled in."));
330 #endif
331 }
332 else if (0 == strcmp(service, "smtp"))
333 {
334 if (NULL == port_str || '\0' == *port_str)
335 port = ZBX_DEFAULT_SMTP_PORT;
336 ret = tcp_expect(ip, port, CONFIG_TIMEOUT, NULL, validate_smtp, "QUIT\r\n", &value_int);
337 }
338 else if (0 == strcmp(service, "ftp"))
339 {
340 if (NULL == port_str || '\0' == *port_str)
341 port = ZBX_DEFAULT_FTP_PORT;
342 ret = tcp_expect(ip, port, CONFIG_TIMEOUT, NULL, validate_ftp, "QUIT\r\n", &value_int);
343 }
344 else if (0 == strcmp(service, "http"))
345 {
346 if (NULL == port_str || '\0' == *port_str)
347 port = ZBX_DEFAULT_HTTP_PORT;
348 ret = tcp_expect(ip, port, CONFIG_TIMEOUT, NULL, NULL, NULL, &value_int);
349 }
350 else if (0 == strcmp(service, "pop"))
351 {
352 if (NULL == port_str || '\0' == *port_str)
353 port = ZBX_DEFAULT_POP_PORT;
354 ret = tcp_expect(ip, port, CONFIG_TIMEOUT, NULL, validate_pop, "QUIT\r\n", &value_int);
355 }
356 else if (0 == strcmp(service, "nntp"))
357 {
358 if (NULL == port_str || '\0' == *port_str)
359 port = ZBX_DEFAULT_NNTP_PORT;
360 ret = tcp_expect(ip, port, CONFIG_TIMEOUT, NULL, validate_nntp, "QUIT\r\n", &value_int);
361 }
362 else if (0 == strcmp(service, "imap"))
363 {
364 if (NULL == port_str || '\0' == *port_str)
365 port = ZBX_DEFAULT_IMAP_PORT;
366 ret = tcp_expect(ip, port, CONFIG_TIMEOUT, NULL, validate_imap, "a1 LOGOUT\r\n", &value_int);
367 }
368 else if (0 == strcmp(service, "tcp"))
369 {
370 if (NULL == port_str || '\0' == *port_str)
371 {
372 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
373 return SYSINFO_RET_FAIL;
374 }
375 ret = tcp_expect(ip, port, CONFIG_TIMEOUT, NULL, NULL, NULL, &value_int);
376 }
377 else if (0 == strcmp(service, "https"))
378 {
379 #ifdef HAVE_LIBCURL
380 if (NULL == port_str || '\0' == *port_str)
381 port = ZBX_DEFAULT_HTTPS_PORT;
382 ret = check_https(ip, port, CONFIG_TIMEOUT, &value_int);
383 #else
384 SET_MSG_RESULT(result, zbx_strdup(NULL, "Support for HTTPS check was not compiled in."));
385 #endif
386 }
387 else if (0 == strcmp(service, "telnet"))
388 {
389 if (NULL == port_str || '\0' == *port_str)
390 port = ZBX_DEFAULT_TELNET_PORT;
391 ret = check_telnet(ip, port, CONFIG_TIMEOUT, &value_int);
392 }
393 else
394 {
395 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
396 return ret;
397 }
398 }
399 else /* net.udp.service */
400 {
401 if (0 == strcmp(service, "ntp"))
402 {
403 if (NULL == port_str || '\0' == *port_str)
404 port = ZBX_DEFAULT_NTP_PORT;
405 ret = check_ntp(ip, port, CONFIG_TIMEOUT, &value_int);
406 }
407 else
408 {
409 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
410 return ret;
411 }
412 }
413
414 if (SYSINFO_RET_OK == ret)
415 {
416 if (0 != perf)
417 {
418 if (0 != value_int)
419 {
420 check_time = zbx_time() - check_time;
421
422 if (ZBX_FLOAT_PRECISION > check_time)
423 check_time = ZBX_FLOAT_PRECISION;
424
425 SET_DBL_RESULT(result, check_time);
426 }
427 else
428 SET_DBL_RESULT(result, 0.0);
429 }
430 else
431 SET_UI64_RESULT(result, value_int);
432 }
433
434 return ret;
435 }
436
437 /* Examples:
438 *
439 * net.tcp.service[ssh]
440 * net.tcp.service[smtp,127.0.0.1]
441 * net.tcp.service[ssh,127.0.0.1,22]
442 *
443 * net.udp.service[ntp]
444 * net.udp.service[ntp,127.0.0.1]
445 * net.udp.service[ntp,127.0.0.1,123]
446 *
447 * net.tcp.service.perf[ssh]
448 * net.tcp.service.perf[smtp,127.0.0.1]
449 * net.tcp.service.perf[ssh,127.0.0.1,22]
450 *
451 * net.udp.service.perf[ntp]
452 * net.udp.service.perf[ntp,127.0.0.1]
453 * net.udp.service.perf[ntp,127.0.0.1,123]
454 *
455 * The old name for these checks is check_service[*].
456 */
457
CHECK_SERVICE(AGENT_REQUEST * request,AGENT_RESULT * result)458 int CHECK_SERVICE(AGENT_REQUEST *request, AGENT_RESULT *result)
459 {
460 return check_service(request, "127.0.0.1", result, 0);
461 }
462
CHECK_SERVICE_PERF(AGENT_REQUEST * request,AGENT_RESULT * result)463 int CHECK_SERVICE_PERF(AGENT_REQUEST *request, AGENT_RESULT *result)
464 {
465 return check_service(request, "127.0.0.1", result, 1);
466 }
467