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 "log.h"
23 #include "../zbxcrypto/tls_tcp.h"
24 #include "zbxcompress.h"
25
26 #ifdef _WINDOWS
27 # ifndef _WIN32_WINNT_WIN7
28 # define _WIN32_WINNT_WIN7 0x0601 /* allow compilation on older Windows systems */
29 # endif
30 # ifndef WSA_FLAG_NO_HANDLE_INHERIT
31 # define WSA_FLAG_NO_HANDLE_INHERIT 0x80 /* allow compilation on older Windows systems */
32 # endif
33 #endif
34
35 #define IPV4_MAX_CIDR_PREFIX 32 /* max number of bits in IPv4 CIDR prefix */
36 #define IPV6_MAX_CIDR_PREFIX 128 /* max number of bits in IPv6 CIDR prefix */
37
38 #ifndef ZBX_SOCKLEN_T
39 # define ZBX_SOCKLEN_T socklen_t
40 #endif
41
42 #ifndef SOCK_CLOEXEC
43 # define SOCK_CLOEXEC 0 /* SOCK_CLOEXEC is Linux-specific, available since 2.6.23 */
44 #endif
45
46 #ifdef HAVE_OPENSSL
47 extern ZBX_THREAD_LOCAL char info_buf[256];
48 #endif
49
50 extern int CONFIG_TIMEOUT;
51 extern int CONFIG_TCP_MAX_BACKLOG_SIZE;
52
53 /******************************************************************************
54 * *
55 * Function: zbx_socket_strerror *
56 * *
57 * Purpose: return string describing tcp error *
58 * *
59 * Return value: pointer to the null terminated string *
60 * *
61 * Author: Eugene Grigorjev *
62 * *
63 ******************************************************************************/
64
65 #define ZBX_SOCKET_STRERROR_LEN 512
66
67 static char zbx_socket_strerror_message[ZBX_SOCKET_STRERROR_LEN];
68
zbx_socket_strerror(void)69 const char *zbx_socket_strerror(void)
70 {
71 zbx_socket_strerror_message[ZBX_SOCKET_STRERROR_LEN - 1] = '\0'; /* force null termination */
72 return zbx_socket_strerror_message;
73 }
74
75 __zbx_attr_format_printf(1, 2)
zbx_set_socket_strerror(const char * fmt,...)76 static void zbx_set_socket_strerror(const char *fmt, ...)
77 {
78 va_list args;
79
80 va_start(args, fmt);
81
82 zbx_vsnprintf(zbx_socket_strerror_message, sizeof(zbx_socket_strerror_message), fmt, args);
83
84 va_end(args);
85 }
86
87 /******************************************************************************
88 * *
89 * Function: zbx_socket_peer_ip_save *
90 * *
91 * Purpose: get peer IP address info from a socket early while it is *
92 * connected. Connection can be terminated due to various errors at *
93 * any time and peer IP address will not be available anymore. *
94 * *
95 * Return value: SUCCEED or FAIL *
96 * *
97 ******************************************************************************/
zbx_socket_peer_ip_save(zbx_socket_t * s)98 static int zbx_socket_peer_ip_save(zbx_socket_t *s)
99 {
100 ZBX_SOCKADDR sa;
101 ZBX_SOCKLEN_T sz = sizeof(sa);
102 char *error_message = NULL;
103
104 if (ZBX_PROTO_ERROR == getpeername(s->socket, (struct sockaddr *)&sa, &sz))
105 {
106 error_message = strerror_from_system(zbx_socket_last_error());
107 zbx_set_socket_strerror("connection rejected, getpeername() failed: %s", error_message);
108 return FAIL;
109 }
110
111 /* store getpeername() result to have IP address in numerical form for security check */
112 memcpy(&s->peer_info, &sa, (size_t)sz);
113
114 /* store IP address as a text string for error reporting */
115
116 #ifdef HAVE_IPV6
117 if (0 != zbx_getnameinfo((struct sockaddr *)&sa, s->peer, sizeof(s->peer), NULL, 0, NI_NUMERICHOST))
118 {
119 error_message = strerror_from_system(zbx_socket_last_error());
120 zbx_set_socket_strerror("connection rejected, getnameinfo() failed: %s", error_message);
121 return FAIL;
122 }
123 #else
124 strscpy(s->peer, inet_ntoa(sa.sin_addr));
125 #endif
126 return SUCCEED;
127 }
128
129 #ifndef _WINDOWS
130 /******************************************************************************
131 * *
132 * Function: zbx_gethost_by_ip *
133 * *
134 * Purpose: retrieve 'hostent' by IP address *
135 * *
136 * Author: Alexei Vladishev *
137 * *
138 ******************************************************************************/
139 #ifdef HAVE_IPV6
zbx_gethost_by_ip(const char * ip,char * host,size_t hostlen)140 void zbx_gethost_by_ip(const char *ip, char *host, size_t hostlen)
141 {
142 struct addrinfo hints, *ai = NULL;
143
144 assert(ip);
145
146 memset(&hints, 0, sizeof(hints));
147 hints.ai_family = PF_UNSPEC;
148
149 if (0 != getaddrinfo(ip, NULL, &hints, &ai))
150 {
151 host[0] = '\0';
152 goto out;
153 }
154
155 if (0 != getnameinfo(ai->ai_addr, ai->ai_addrlen, host, hostlen, NULL, 0, NI_NAMEREQD))
156 {
157 host[0] = '\0';
158 goto out;
159 }
160 out:
161 if (NULL != ai)
162 freeaddrinfo(ai);
163 }
164 #else
zbx_gethost_by_ip(const char * ip,char * host,size_t hostlen)165 void zbx_gethost_by_ip(const char *ip, char *host, size_t hostlen)
166 {
167 struct in_addr addr;
168 struct hostent *hst;
169
170 assert(ip);
171
172 if (0 == inet_aton(ip, &addr))
173 {
174 host[0] = '\0';
175 return;
176 }
177
178 if (NULL == (hst = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)))
179 {
180 host[0] = '\0';
181 return;
182 }
183
184 zbx_strlcpy(host, hst->h_name, hostlen);
185 }
186 #endif /* HAVE_IPV6 */
187
188 /******************************************************************************
189 * *
190 * Function: zbx_getip_by_host *
191 * *
192 * Purpose: retrieve IP address by host name *
193 * *
194 ******************************************************************************/
zbx_getip_by_host(const char * host,char * ip,size_t iplen)195 void zbx_getip_by_host(const char *host, char *ip, size_t iplen)
196 {
197 struct addrinfo hints, *ai = NULL;
198
199 assert(ip);
200
201 memset(&hints, 0, sizeof(hints));
202 hints.ai_family = PF_UNSPEC;
203
204 if (0 != getaddrinfo(host, NULL, &hints, &ai))
205 {
206 ip[0] = '\0';
207 goto out;
208 }
209
210 switch(ai->ai_addr->sa_family) {
211 case AF_INET:
212 inet_ntop(AF_INET, &(((struct sockaddr_in *)ai->ai_addr)->sin_addr), ip, iplen);
213 break;
214 case AF_INET6:
215 inet_ntop(AF_INET6, &(((struct sockaddr_in *)ai->ai_addr)->sin_addr), ip, iplen);
216 break;
217 default:
218 ip[0] = '\0';
219 goto out;
220 }
221 out:
222 if (NULL != ai)
223 freeaddrinfo(ai);
224 }
225
226 #endif /* _WINDOWS */
227
228 #ifdef _WINDOWS
229 /******************************************************************************
230 * *
231 * Function: zbx_is_win_ver_or_greater *
232 * *
233 * Purpose: check Windows version *
234 * *
235 * Parameters: major - [IN] major windows version *
236 * minor - [IN] minor windows version *
237 * servpack - [IN] service pack version *
238 * *
239 * Return value: SUCCEED - Windows version matches input parameters *
240 * or greater *
241 * FAIL - Windows version is older *
242 * *
243 * Comments: This is reimplementation of IsWindowsVersionOrGreater() from *
244 * Version Helper API. We need it because the original function is *
245 * only available in newer Windows toolchains (VS2013+) *
246 * *
247 ******************************************************************************/
zbx_is_win_ver_or_greater(zbx_uint32_t major,zbx_uint32_t minor,zbx_uint32_t servpack)248 static int zbx_is_win_ver_or_greater(zbx_uint32_t major, zbx_uint32_t minor, zbx_uint32_t servpack)
249 {
250 OSVERSIONINFOEXW vi = { sizeof(vi), major, minor, 0, 0, { 0 }, servpack, 0 };
251
252 /* no need to test for an error, check VersionHelpers.h and usage examples */
253
254 return VerifyVersionInfoW(&vi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR,
255 VerSetConditionMask(VerSetConditionMask(VerSetConditionMask(0,
256 VER_MAJORVERSION, VER_GREATER_EQUAL),
257 VER_MINORVERSION, VER_GREATER_EQUAL),
258 VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL)) ? SUCCEED : FAIL;
259 }
260 #endif
261
262 /******************************************************************************
263 * *
264 * Function: zbx_socket_start *
265 * *
266 * Purpose: Initialize Windows Sockets APIs *
267 * *
268 * Parameters: error - [OUT] the error message *
269 * *
270 * Return value: SUCCEED or FAIL - an error occurred *
271 * *
272 * Author: Eugene Grigorjev *
273 * *
274 ******************************************************************************/
275 #ifdef _WINDOWS
zbx_socket_start(char ** error)276 int zbx_socket_start(char **error)
277 {
278 WSADATA sockInfo;
279 int ret;
280
281 if (0 != (ret = WSAStartup(MAKEWORD(2, 2), &sockInfo)))
282 {
283 *error = zbx_dsprintf(*error, "Cannot initialize Winsock DLL: %s", strerror_from_system(ret));
284 return FAIL;
285 }
286
287 return SUCCEED;
288 }
289 #endif
290
291 /******************************************************************************
292 * *
293 * Function: zbx_socket_clean *
294 * *
295 * Purpose: initialize socket *
296 * *
297 * Author: Alexei Vladishev *
298 * *
299 ******************************************************************************/
zbx_socket_clean(zbx_socket_t * s)300 static void zbx_socket_clean(zbx_socket_t *s)
301 {
302 memset(s, 0, sizeof(zbx_socket_t));
303
304 s->buf_type = ZBX_BUF_TYPE_STAT;
305 }
306
307 /******************************************************************************
308 * *
309 * Function: zbx_socket_free *
310 * *
311 * Purpose: free socket's dynamic buffer *
312 * *
313 * Author: Alexei Vladishev *
314 * *
315 ******************************************************************************/
zbx_socket_free(zbx_socket_t * s)316 static void zbx_socket_free(zbx_socket_t *s)
317 {
318 if (ZBX_BUF_TYPE_DYN == s->buf_type)
319 zbx_free(s->buffer);
320 }
321
322 /******************************************************************************
323 * *
324 * Function: zbx_socket_timeout_set *
325 * *
326 * Purpose: set timeout for socket operations *
327 * *
328 * Parameters: s - [IN] socket descriptor *
329 * timeout - [IN] timeout, in seconds *
330 * *
331 * Author: Alexander Vladishev *
332 * *
333 ******************************************************************************/
zbx_socket_timeout_set(zbx_socket_t * s,int timeout)334 static void zbx_socket_timeout_set(zbx_socket_t *s, int timeout)
335 {
336 s->timeout = timeout;
337 #ifdef _WINDOWS
338 timeout *= 1000;
339
340 if (ZBX_PROTO_ERROR == setsockopt(s->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)))
341 {
342 zabbix_log(LOG_LEVEL_WARNING, "setsockopt() failed for SO_RCVTIMEO: %s",
343 strerror_from_system(zbx_socket_last_error()));
344 }
345
346 if (ZBX_PROTO_ERROR == setsockopt(s->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout)))
347 {
348 zabbix_log(LOG_LEVEL_WARNING, "setsockopt() failed for SO_SNDTIMEO: %s",
349 strerror_from_system(zbx_socket_last_error()));
350 }
351 #else
352 zbx_alarm_on(timeout);
353 #endif
354 }
355
356 /******************************************************************************
357 * *
358 * Function: zbx_socket_timeout_cleanup *
359 * *
360 * Purpose: clean up timeout for socket operations *
361 * *
362 * Parameters: s - [OUT] socket descriptor *
363 * *
364 * Author: Alexander Vladishev *
365 * *
366 ******************************************************************************/
zbx_socket_timeout_cleanup(zbx_socket_t * s)367 static void zbx_socket_timeout_cleanup(zbx_socket_t *s)
368 {
369 #ifndef _WINDOWS
370 if (0 != s->timeout)
371 {
372 zbx_alarm_off();
373 s->timeout = 0;
374 }
375 #endif
376 }
377
378 /******************************************************************************
379 * *
380 * Function: zbx_socket_connect *
381 * *
382 * Purpose: connect to the specified address with an optional timeout value *
383 * *
384 * Parameters: s - [IN] socket descriptor *
385 * addr - [IN] the address *
386 * addrlen - [IN] the length of addr structure *
387 * timeout - [IN] the connection timeout (0 - system default) *
388 * error - [OUT] the error message *
389 * *
390 * Return value: SUCCEED - connected successfully *
391 * FAIL - an error occurred *
392 * *
393 * Comments: Windows connect implementation uses internal timeouts which *
394 * cannot be changed. Because of that in Windows use nonblocking *
395 * connect, then wait for connection the specified timeout period *
396 * and if successful change socket back to blocking mode. *
397 * *
398 ******************************************************************************/
zbx_socket_connect(zbx_socket_t * s,const struct sockaddr * addr,socklen_t addrlen,int timeout,char ** error)399 static int zbx_socket_connect(zbx_socket_t *s, const struct sockaddr *addr, socklen_t addrlen, int timeout,
400 char **error)
401 {
402 #ifdef _WINDOWS
403 u_long mode = 1;
404 FD_SET fdw, fde;
405 struct timeval tv, *ptv;
406 #endif
407 if (0 != timeout)
408 zbx_socket_timeout_set(s, timeout);
409
410 #ifdef _WINDOWS
411 if (0 != ioctlsocket(s->socket, FIONBIO, &mode))
412 {
413 *error = zbx_strdup(*error, strerror_from_system(zbx_socket_last_error()));
414 return FAIL;
415 }
416
417 FD_ZERO(&fdw);
418 FD_SET(s->socket, &fdw);
419
420 FD_ZERO(&fde);
421 FD_SET(s->socket, &fde);
422
423 if (0 != timeout)
424 {
425 tv.tv_sec = timeout;
426 tv.tv_usec = 0;
427 ptv = &tv;
428 }
429 else
430 ptv = NULL;
431
432 if (ZBX_PROTO_ERROR == connect(s->socket, addr, addrlen) && WSAEWOULDBLOCK != zbx_socket_last_error())
433 {
434 *error = zbx_strdup(*error, strerror_from_system(zbx_socket_last_error()));
435 return FAIL;
436 }
437
438 if (-1 == select(0, NULL, &fdw, &fde, ptv))
439 {
440 *error = zbx_strdup(*error, strerror_from_system(zbx_socket_last_error()));
441 return FAIL;
442 }
443
444 if (0 == FD_ISSET(s->socket, &fdw))
445 {
446 if (0 != FD_ISSET(s->socket, &fde))
447 {
448 int socket_error = 0;
449 int socket_error_len = sizeof(int);
450
451 if (ZBX_PROTO_ERROR != getsockopt(s->socket, SOL_SOCKET,
452 SO_ERROR, (char *)&socket_error, &socket_error_len))
453 {
454 if (socket_error == WSAECONNREFUSED)
455 *error = zbx_strdup(*error, "Connection refused.");
456 else if (socket_error == WSAETIMEDOUT)
457 *error = zbx_strdup(*error, "A connection timeout occurred.");
458 else
459 *error = zbx_strdup(*error, strerror_from_system(socket_error));
460 }
461 else
462 {
463 *error = zbx_dsprintf(*error, "Cannot obtain error code: %s",
464 strerror_from_system(zbx_socket_last_error()));
465 }
466 }
467
468 return FAIL;
469 }
470
471 mode = 0;
472 if (0 != ioctlsocket(s->socket, FIONBIO, &mode))
473 {
474 *error = zbx_strdup(*error, strerror_from_system(zbx_socket_last_error()));
475 return FAIL;
476 }
477 #else
478 if (ZBX_PROTO_ERROR == connect(s->socket, addr, addrlen))
479 {
480 *error = zbx_strdup(*error, strerror_from_system(zbx_socket_last_error()));
481 return FAIL;
482 }
483 #endif
484 s->connection_type = ZBX_TCP_SEC_UNENCRYPTED;
485
486 return SUCCEED;
487 }
488
489 /******************************************************************************
490 * *
491 * Function: zbx_socket_create *
492 * *
493 * Purpose: connect the socket of the specified type to external host *
494 * *
495 * Parameters: s - [OUT] socket descriptor *
496 * *
497 * Return value: SUCCEED - connected successfully *
498 * FAIL - an error occurred *
499 * *
500 * Author: Alexei Vladishev *
501 * *
502 ******************************************************************************/
503 #ifdef HAVE_IPV6
zbx_socket_create(zbx_socket_t * s,int type,const char * source_ip,const char * ip,unsigned short port,int timeout,unsigned int tls_connect,const char * tls_arg1,const char * tls_arg2)504 static int zbx_socket_create(zbx_socket_t *s, int type, const char *source_ip, const char *ip, unsigned short port,
505 int timeout, unsigned int tls_connect, const char *tls_arg1, const char *tls_arg2)
506 {
507 int ret = FAIL;
508 struct addrinfo *ai = NULL, hints;
509 struct addrinfo *ai_bind = NULL;
510 char service[8], *error = NULL;
511 void (*func_socket_close)(zbx_socket_t *s);
512
513 zbx_socket_clean(s);
514
515 if (SOCK_DGRAM == type && (ZBX_TCP_SEC_TLS_CERT == tls_connect || ZBX_TCP_SEC_TLS_PSK == tls_connect))
516 {
517 THIS_SHOULD_NEVER_HAPPEN;
518 return FAIL;
519 }
520 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
521 if (ZBX_TCP_SEC_TLS_PSK == tls_connect && '\0' == *tls_arg1)
522 {
523 zbx_set_socket_strerror("cannot connect with PSK: PSK not available");
524 return FAIL;
525 }
526 #else
527 if (ZBX_TCP_SEC_TLS_CERT == tls_connect || ZBX_TCP_SEC_TLS_PSK == tls_connect)
528 {
529 zbx_set_socket_strerror("support for TLS was not compiled in");
530 return FAIL;
531 }
532 #endif
533
534 zbx_snprintf(service, sizeof(service), "%hu", port);
535 memset(&hints, 0x00, sizeof(struct addrinfo));
536 hints.ai_family = PF_UNSPEC;
537 hints.ai_socktype = type;
538
539 if (0 != getaddrinfo(ip, service, &hints, &ai))
540 {
541 zbx_set_socket_strerror("cannot resolve [%s]", ip);
542 goto out;
543 }
544
545 if (ZBX_SOCKET_ERROR == (s->socket = socket(ai->ai_family, ai->ai_socktype | SOCK_CLOEXEC, ai->ai_protocol)))
546 {
547 zbx_set_socket_strerror("cannot create socket [[%s]:%hu]: %s",
548 ip, port, strerror_from_system(zbx_socket_last_error()));
549 goto out;
550 }
551
552 #if !defined(_WINDOWS) && !SOCK_CLOEXEC
553 if (-1 == fcntl(s->socket, F_SETFD, FD_CLOEXEC))
554 {
555 zbx_set_socket_strerror("failed to set the FD_CLOEXEC file descriptor flag on socket [[%s]:%hu]: %s",
556 ip, port, strerror_from_system(zbx_socket_last_error()));
557 }
558 #endif
559 func_socket_close = (SOCK_STREAM == type ? zbx_tcp_close : zbx_udp_close);
560
561 if (NULL != source_ip)
562 {
563 memset(&hints, 0x00, sizeof(struct addrinfo));
564
565 hints.ai_family = PF_UNSPEC;
566 hints.ai_socktype = type;
567 hints.ai_flags = AI_NUMERICHOST;
568
569 if (0 != getaddrinfo(source_ip, NULL, &hints, &ai_bind))
570 {
571 zbx_set_socket_strerror("invalid source IP address [%s]", source_ip);
572 func_socket_close(s);
573 goto out;
574 }
575
576 if (ZBX_PROTO_ERROR == zbx_bind(s->socket, ai_bind->ai_addr, ai_bind->ai_addrlen))
577 {
578 zbx_set_socket_strerror("bind() failed: %s", strerror_from_system(zbx_socket_last_error()));
579 func_socket_close(s);
580 goto out;
581 }
582 }
583
584 if (SUCCEED != zbx_socket_connect(s, ai->ai_addr, (socklen_t)ai->ai_addrlen, timeout, &error))
585 {
586 func_socket_close(s);
587 zbx_set_socket_strerror("cannot connect to [[%s]:%hu]: %s", ip, port, error);
588 zbx_free(error);
589 goto out;
590 }
591
592 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
593 if ((ZBX_TCP_SEC_TLS_CERT == tls_connect || ZBX_TCP_SEC_TLS_PSK == tls_connect) &&
594 SUCCEED != zbx_tls_connect(s, tls_connect, tls_arg1, tls_arg2, &error))
595 {
596 zbx_tcp_close(s);
597 zbx_set_socket_strerror("TCP successful, cannot establish TLS to [[%s]:%hu]: %s", ip, port, error);
598 zbx_free(error);
599 goto out;
600 }
601 #else
602 ZBX_UNUSED(tls_arg1);
603 ZBX_UNUSED(tls_arg2);
604 #endif
605 zbx_strlcpy(s->peer, ip, sizeof(s->peer));
606
607 ret = SUCCEED;
608 out:
609 if (NULL != ai)
610 freeaddrinfo(ai);
611
612 if (NULL != ai_bind)
613 freeaddrinfo(ai_bind);
614
615 return ret;
616 }
617 #else
zbx_socket_create(zbx_socket_t * s,int type,const char * source_ip,const char * ip,unsigned short port,int timeout,unsigned int tls_connect,const char * tls_arg1,const char * tls_arg2)618 static int zbx_socket_create(zbx_socket_t *s, int type, const char *source_ip, const char *ip, unsigned short port,
619 int timeout, unsigned int tls_connect, const char *tls_arg1, const char *tls_arg2)
620 {
621 ZBX_SOCKADDR servaddr_in;
622 struct addrinfo hints, *ai;
623 char *error = NULL;
624 void (*func_socket_close)(zbx_socket_t *s);
625
626 if (SOCK_DGRAM == type && (ZBX_TCP_SEC_TLS_CERT == tls_connect || ZBX_TCP_SEC_TLS_PSK == tls_connect))
627 {
628 THIS_SHOULD_NEVER_HAPPEN;
629 return FAIL;
630 }
631 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
632 if (ZBX_TCP_SEC_TLS_PSK == tls_connect && '\0' == *tls_arg1)
633 {
634 zbx_set_socket_strerror("cannot connect with PSK: PSK not available");
635 return FAIL;
636 }
637 #else
638 if (ZBX_TCP_SEC_TLS_CERT == tls_connect || ZBX_TCP_SEC_TLS_PSK == tls_connect)
639 {
640 zbx_set_socket_strerror("support for TLS was not compiled in");
641 return FAIL;
642 }
643 #endif
644 zbx_socket_clean(s);
645
646 memset(&hints, 0, sizeof(hints));
647 hints.ai_family = AF_INET;
648 hints.ai_socktype = type;
649
650 if (0 != getaddrinfo(ip, NULL, &hints, &ai))
651 {
652 #ifdef _WINDOWS
653 zbx_set_socket_strerror("getaddrinfo() failed for '%s': %s",
654 ip, strerror_from_system(WSAGetLastError()));
655 #else
656 #ifdef HAVE_HSTRERROR
657 zbx_set_socket_strerror("getaddrinfo() failed for '%s': [%d] %s",
658 ip, h_errno, hstrerror(h_errno));
659 #else
660 zbx_set_socket_strerror("getaddrinfo() failed for '%s': [%d]",
661 ip, h_errno);
662 #endif
663 #endif
664 return FAIL;
665 }
666
667 servaddr_in.sin_family = AF_INET;
668 servaddr_in.sin_addr = ((struct sockaddr_in *)ai->ai_addr)->sin_addr;
669 servaddr_in.sin_port = htons(port);
670
671 freeaddrinfo(ai);
672
673 if (ZBX_SOCKET_ERROR == (s->socket = socket(AF_INET, type | SOCK_CLOEXEC, 0)))
674 {
675 zbx_set_socket_strerror("cannot create socket [[%s]:%hu]: %s",
676 ip, port, strerror_from_system(zbx_socket_last_error()));
677 return FAIL;
678 }
679
680 #if !defined(_WINDOWS) && !SOCK_CLOEXEC
681 if (-1 == fcntl(s->socket, F_SETFD, FD_CLOEXEC))
682 {
683 zbx_set_socket_strerror("failed to set the FD_CLOEXEC file descriptor flag on socket [[%s]:%hu]: %s",
684 ip, port, strerror_from_system(zbx_socket_last_error()));
685 }
686 #endif
687 func_socket_close = (SOCK_STREAM == type ? zbx_tcp_close : zbx_udp_close);
688
689 if (NULL != source_ip)
690 {
691 ZBX_SOCKADDR source_addr;
692
693 memset(&source_addr, 0, sizeof(source_addr));
694
695 source_addr.sin_family = AF_INET;
696 source_addr.sin_addr.s_addr = inet_addr(source_ip);
697 source_addr.sin_port = 0;
698
699 if (ZBX_PROTO_ERROR == bind(s->socket, (struct sockaddr *)&source_addr, sizeof(source_addr)))
700 {
701 zbx_set_socket_strerror("bind() failed: %s", strerror_from_system(zbx_socket_last_error()));
702 func_socket_close(s);
703 return FAIL;
704 }
705 }
706
707 if (SUCCEED != zbx_socket_connect(s, (struct sockaddr *)&servaddr_in, sizeof(servaddr_in), timeout, &error))
708 {
709 func_socket_close(s);
710 zbx_set_socket_strerror("cannot connect to [[%s]:%hu]: %s", ip, port, error);
711 zbx_free(error);
712 return FAIL;
713 }
714
715 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
716 if ((ZBX_TCP_SEC_TLS_CERT == tls_connect || ZBX_TCP_SEC_TLS_PSK == tls_connect) &&
717 SUCCEED != zbx_tls_connect(s, tls_connect, tls_arg1, tls_arg2, &error))
718 {
719 zbx_tcp_close(s);
720 zbx_set_socket_strerror("TCP successful, cannot establish TLS to [[%s]:%hu]: %s", ip, port, error);
721 zbx_free(error);
722 return FAIL;
723 }
724 #else
725 ZBX_UNUSED(tls_arg1);
726 ZBX_UNUSED(tls_arg2);
727 #endif
728 zbx_strlcpy(s->peer, ip, sizeof(s->peer));
729
730 return SUCCEED;
731 }
732 #endif /* HAVE_IPV6 */
733
zbx_tcp_connect(zbx_socket_t * s,const char * source_ip,const char * ip,unsigned short port,int timeout,unsigned int tls_connect,const char * tls_arg1,const char * tls_arg2)734 int zbx_tcp_connect(zbx_socket_t *s, const char *source_ip, const char *ip, unsigned short port, int timeout,
735 unsigned int tls_connect, const char *tls_arg1, const char *tls_arg2)
736 {
737 if (ZBX_TCP_SEC_UNENCRYPTED != tls_connect && ZBX_TCP_SEC_TLS_CERT != tls_connect &&
738 ZBX_TCP_SEC_TLS_PSK != tls_connect)
739 {
740 THIS_SHOULD_NEVER_HAPPEN;
741 return FAIL;
742 }
743
744 return zbx_socket_create(s, SOCK_STREAM, source_ip, ip, port, timeout, tls_connect, tls_arg1, tls_arg2);
745 }
746
zbx_tcp_write(zbx_socket_t * s,const char * buf,size_t len)747 static ssize_t zbx_tcp_write(zbx_socket_t *s, const char *buf, size_t len)
748 {
749 ssize_t res;
750 int err;
751 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
752 char *error = NULL;
753 #endif
754 #ifdef _WINDOWS
755 double sec;
756 #endif
757 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
758 if (NULL != s->tls_ctx) /* TLS connection */
759 {
760 if (ZBX_PROTO_ERROR == (res = zbx_tls_write(s, buf, len, &error)))
761 {
762 zbx_set_socket_strerror("%s", error);
763 zbx_free(error);
764 }
765
766 return res;
767 }
768 #endif
769 #ifdef _WINDOWS
770 zbx_alarm_flag_clear();
771 sec = zbx_time();
772 #endif
773 do
774 {
775 res = ZBX_TCP_WRITE(s->socket, buf, len);
776 #ifdef _WINDOWS
777 if (s->timeout < zbx_time() - sec)
778 zbx_alarm_flag_set();
779 #endif
780 if (SUCCEED == zbx_alarm_timed_out())
781 {
782 zbx_set_socket_strerror("ZBX_TCP_WRITE() timed out");
783 return ZBX_PROTO_ERROR;
784 }
785 }
786 while (ZBX_PROTO_ERROR == res && ZBX_PROTO_AGAIN == (err = zbx_socket_last_error()));
787
788 if (ZBX_PROTO_ERROR == res)
789 zbx_set_socket_strerror("ZBX_TCP_WRITE() failed: %s", strerror_from_system(err));
790
791 return res;
792 }
793
794 /******************************************************************************
795 * *
796 * Function: zbx_tcp_send_ext *
797 * *
798 * Purpose: send data *
799 * *
800 * Return value: SUCCEED - success *
801 * FAIL - an error occurred *
802 * *
803 * Author: Eugene Grigorjev *
804 * *
805 * Comments: *
806 * RFC 5246 "The Transport Layer Security (TLS) Protocol. Version 1.2" *
807 * says: "The record layer fragments information blocks into TLSPlaintext *
808 * records carrying data in chunks of 2^14 bytes or less.". *
809 * *
810 * This function combines sending of Zabbix protocol header (5 bytes), *
811 * data length (8 bytes or 16 bytes for large packet) and at least part *
812 * of the message into one block of up to 16384 bytes for efficiency. *
813 * The same is applied for sending unencrypted messages. *
814 * *
815 ******************************************************************************/
816
817 #define ZBX_TCP_HEADER_DATA "ZBXD"
818 #define ZBX_TCP_HEADER_LEN ZBX_CONST_STRLEN(ZBX_TCP_HEADER_DATA)
819
zbx_tcp_send_ext(zbx_socket_t * s,const char * data,size_t len,size_t reserved,unsigned char flags,int timeout)820 int zbx_tcp_send_ext(zbx_socket_t *s, const char *data, size_t len, size_t reserved, unsigned char flags,
821 int timeout)
822 {
823 #define ZBX_TLS_MAX_REC_LEN 16384
824
825 ssize_t bytes_sent, written = 0;
826 size_t send_bytes, offset, send_len = len;
827 int ret = SUCCEED;
828 char *compressed_data = NULL;
829 const zbx_uint64_t max_uint32 = ~(zbx_uint32_t)0;
830
831 if (0 != timeout)
832 zbx_socket_timeout_set(s, timeout);
833
834 if (0 != (flags & ZBX_TCP_PROTOCOL))
835 {
836 size_t take_bytes;
837 char header_buf[ZBX_TLS_MAX_REC_LEN]; /* Buffer is allocated on stack with a hope that it */
838 /* will be short-lived in CPU cache. Static buffer is */
839 /* not used on purpose. */
840
841 if (ZBX_MAX_RECV_LARGE_DATA_SIZE < len)
842 {
843 zbx_set_socket_strerror("cannot send data: message size " ZBX_FS_UI64 " exceeds the maximum"
844 " size " ZBX_FS_UI64 " bytes.", len, ZBX_MAX_RECV_LARGE_DATA_SIZE);
845 ret = FAIL;
846 goto cleanup;
847 }
848
849 if (ZBX_MAX_RECV_LARGE_DATA_SIZE < reserved)
850 {
851 zbx_set_socket_strerror("cannot send data: uncompressed message size " ZBX_FS_UI64
852 " exceeds the maximum size " ZBX_FS_UI64 " bytes.", reserved,
853 ZBX_MAX_RECV_LARGE_DATA_SIZE);
854 ret = FAIL;
855 goto cleanup;
856 }
857
858 if (0 != (flags & ZBX_TCP_COMPRESS))
859 {
860 /* compress if not compressed yet */
861 if (0 == reserved)
862 {
863 if (SUCCEED != zbx_compress(data, len, &compressed_data, &send_len))
864 {
865 zbx_set_socket_strerror("cannot compress data: %s", zbx_compress_strerror());
866 ret = FAIL;
867 goto cleanup;
868 }
869
870 data = compressed_data;
871 reserved = len;
872 }
873 }
874
875 memcpy(header_buf, ZBX_TCP_HEADER_DATA, ZBX_CONST_STRLEN(ZBX_TCP_HEADER_DATA));
876 offset = ZBX_CONST_STRLEN(ZBX_TCP_HEADER_DATA);
877
878 if (max_uint32 <= len || max_uint32 <= reserved)
879 flags |= ZBX_TCP_LARGE;
880
881 header_buf[offset++] = flags;
882
883 if (0 != (flags & ZBX_TCP_LARGE))
884 {
885 zbx_uint64_t len64_le;
886
887 len64_le = zbx_htole_uint64((zbx_uint64_t)send_len);
888 memcpy(header_buf + offset, &len64_le, sizeof(len64_le));
889 offset += sizeof(len64_le);
890
891 len64_le = zbx_htole_uint64((zbx_uint64_t)reserved);
892 memcpy(header_buf + offset, &len64_le, sizeof(len64_le));
893 offset += sizeof(len64_le);
894 }
895 else
896 {
897 zbx_uint32_t len32_le;
898
899 len32_le = zbx_htole_uint32((zbx_uint32_t)send_len);
900 memcpy(header_buf + offset, &len32_le, sizeof(len32_le));
901 offset += sizeof(len32_le);
902
903 len32_le = zbx_htole_uint32((zbx_uint32_t)reserved);
904 memcpy(header_buf + offset, &len32_le, sizeof(len32_le));
905 offset += sizeof(len32_le);
906 }
907
908 take_bytes = MIN(send_len, ZBX_TLS_MAX_REC_LEN - offset);
909 memcpy(header_buf + offset, data, take_bytes);
910
911 send_bytes = offset + take_bytes;
912
913 while (written < (ssize_t)send_bytes)
914 {
915 if (ZBX_PROTO_ERROR == (bytes_sent = zbx_tcp_write(s, header_buf + written,
916 send_bytes - (size_t)written)))
917 {
918 ret = FAIL;
919 goto cleanup;
920 }
921 written += bytes_sent;
922 }
923
924 written -= offset;
925 }
926
927 while (written < (ssize_t)send_len)
928 {
929 if (ZBX_TCP_SEC_UNENCRYPTED == s->connection_type)
930 send_bytes = send_len - (size_t)written;
931 else
932 send_bytes = MIN(ZBX_TLS_MAX_REC_LEN, send_len - (size_t)written);
933
934 if (ZBX_PROTO_ERROR == (bytes_sent = zbx_tcp_write(s, data + written, send_bytes)))
935 {
936 ret = FAIL;
937 goto cleanup;
938 }
939 written += bytes_sent;
940 }
941 cleanup:
942 zbx_free(compressed_data);
943
944 if (0 != timeout)
945 zbx_socket_timeout_cleanup(s);
946
947 return ret;
948
949 #undef ZBX_TLS_MAX_REC_LEN
950 }
951
952 /******************************************************************************
953 * *
954 * Function: zbx_tcp_close *
955 * *
956 * Purpose: close open TCP socket *
957 * *
958 * Author: Alexei Vladishev *
959 * *
960 ******************************************************************************/
zbx_tcp_close(zbx_socket_t * s)961 void zbx_tcp_close(zbx_socket_t *s)
962 {
963 zbx_tcp_unaccept(s);
964
965 zbx_socket_timeout_cleanup(s);
966
967 zbx_socket_free(s);
968 zbx_socket_close(s->socket);
969 }
970
971 /******************************************************************************
972 * *
973 * Function: get_address_family *
974 * *
975 * Purpose: return address family *
976 * *
977 * Parameters: addr - [IN] address or hostname *
978 * family - [OUT] address family *
979 * error - [OUT] error string *
980 * max_error_len - [IN] error string length *
981 * *
982 * Return value: SUCCEED - success *
983 * FAIL - an error occurred *
984 * *
985 * Author: Alexander Vladishev *
986 * *
987 ******************************************************************************/
988 #ifdef HAVE_IPV6
get_address_family(const char * addr,int * family,char * error,int max_error_len)989 int get_address_family(const char *addr, int *family, char *error, int max_error_len)
990 {
991 struct addrinfo hints, *ai = NULL;
992 int err, res = FAIL;
993
994 memset(&hints, 0, sizeof(hints));
995 hints.ai_family = PF_UNSPEC;
996 hints.ai_flags = 0;
997 hints.ai_socktype = SOCK_STREAM;
998
999 if (0 != (err = getaddrinfo(addr, NULL, &hints, &ai)))
1000 {
1001 zbx_snprintf(error, max_error_len, "%s: [%d] %s", addr, err, gai_strerror(err));
1002 goto out;
1003 }
1004
1005 if (PF_INET != ai->ai_family && PF_INET6 != ai->ai_family)
1006 {
1007 zbx_snprintf(error, max_error_len, "%s: unsupported address family", addr);
1008 goto out;
1009 }
1010
1011 *family = (int)ai->ai_family;
1012
1013 res = SUCCEED;
1014 out:
1015 if (NULL != ai)
1016 freeaddrinfo(ai);
1017
1018 return res;
1019 }
1020 #endif /* HAVE_IPV6 */
1021
1022 /******************************************************************************
1023 * *
1024 * Function: zbx_tcp_listen *
1025 * *
1026 * Purpose: create socket for listening *
1027 * *
1028 * Return value: SUCCEED - success *
1029 * FAIL - an error occurred *
1030 * *
1031 * Author: Alexei Vladishev, Aleksandrs Saveljevs *
1032 * *
1033 ******************************************************************************/
1034 #ifdef HAVE_IPV6
zbx_tcp_listen(zbx_socket_t * s,const char * listen_ip,unsigned short listen_port)1035 int zbx_tcp_listen(zbx_socket_t *s, const char *listen_ip, unsigned short listen_port)
1036 {
1037 struct addrinfo hints, *ai = NULL, *current_ai;
1038 char port[8], *ip, *ips, *delim;
1039 int i, err, on, ret = FAIL;
1040 #ifdef _WINDOWS
1041 /* WSASocket() option to prevent inheritance is available on */
1042 /* Windows Server 2008 R2 SP1 or newer and on Windows 7 SP1 or newer */
1043 static int no_inherit_wsapi = -1;
1044
1045 if (-1 == no_inherit_wsapi)
1046 {
1047 /* Both Windows 7 and Windows 2008 R2 are 0x0601 */
1048 no_inherit_wsapi = zbx_is_win_ver_or_greater((_WIN32_WINNT_WIN7 >> 8) & 0xff,
1049 _WIN32_WINNT_WIN7 & 0xff, 1) == SUCCEED;
1050 }
1051 #endif
1052
1053 zbx_socket_clean(s);
1054
1055 memset(&hints, 0, sizeof(hints));
1056 hints.ai_family = PF_UNSPEC;
1057 hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
1058 hints.ai_socktype = SOCK_STREAM;
1059 zbx_snprintf(port, sizeof(port), "%hu", listen_port);
1060
1061 ip = ips = (NULL == listen_ip ? NULL : strdup(listen_ip));
1062
1063 while (1)
1064 {
1065 delim = (NULL == ip ? NULL : strchr(ip, ','));
1066 if (NULL != delim)
1067 *delim = '\0';
1068
1069 if (0 != (err = getaddrinfo(ip, port, &hints, &ai)))
1070 {
1071 zbx_set_socket_strerror("cannot resolve address [[%s]:%s]: [%d] %s",
1072 NULL != ip ? ip : "-", port, err, gai_strerror(err));
1073 goto out;
1074 }
1075
1076 for (current_ai = ai; NULL != current_ai; current_ai = current_ai->ai_next)
1077 {
1078 if (ZBX_SOCKET_COUNT == s->num_socks)
1079 {
1080 zbx_set_socket_strerror("not enough space for socket [[%s]:%s]",
1081 NULL != ip ? ip : "-", port);
1082 goto out;
1083 }
1084
1085 if (PF_INET != current_ai->ai_family && PF_INET6 != current_ai->ai_family)
1086 continue;
1087
1088 #ifdef _WINDOWS
1089 /* WSA_FLAG_NO_HANDLE_INHERIT prevents socket inheritance if we call CreateProcess() */
1090 /* later on. If it's not available we still try to avoid inheritance by calling */
1091 /* SetHandleInformation() below. WSA_FLAG_OVERLAPPED is not mandatory but strongly */
1092 /* recommended for every socket */
1093 s->sockets[s->num_socks] = WSASocket(current_ai->ai_family, current_ai->ai_socktype,
1094 current_ai->ai_protocol, NULL, 0,
1095 (0 != no_inherit_wsapi ? WSA_FLAG_NO_HANDLE_INHERIT : 0) |
1096 WSA_FLAG_OVERLAPPED);
1097 if (ZBX_SOCKET_ERROR == s->sockets[s->num_socks])
1098 {
1099 zbx_set_socket_strerror("WSASocket() for [[%s]:%s] failed: %s",
1100 NULL != ip ? ip : "-", port,
1101 strerror_from_system(zbx_socket_last_error()));
1102 if (WSAEAFNOSUPPORT == zbx_socket_last_error())
1103 #else
1104 if (ZBX_SOCKET_ERROR == (s->sockets[s->num_socks] =
1105 socket(current_ai->ai_family, current_ai->ai_socktype | SOCK_CLOEXEC,
1106 current_ai->ai_protocol)))
1107 {
1108 zbx_set_socket_strerror("socket() for [[%s]:%s] failed: %s",
1109 NULL != ip ? ip : "-", port,
1110 strerror_from_system(zbx_socket_last_error()));
1111 if (EAFNOSUPPORT == zbx_socket_last_error())
1112 #endif
1113 continue;
1114 else
1115 goto out;
1116 }
1117
1118 #if !defined(_WINDOWS) && !SOCK_CLOEXEC
1119 if (-1 == fcntl(s->sockets[s->num_socks], F_SETFD, FD_CLOEXEC))
1120 {
1121 zbx_set_socket_strerror("failed to set the FD_CLOEXEC file descriptor flag on "
1122 "socket [[%s]:%s]: %s", NULL != ip ? ip : "-", port,
1123 strerror_from_system(zbx_socket_last_error()));
1124 }
1125 #endif
1126 on = 1;
1127 #ifdef _WINDOWS
1128 /* If WSA_FLAG_NO_HANDLE_INHERIT not available, prevent listening socket from */
1129 /* inheritance with the old API. Disabling handle inheritance in WSASocket() instead of */
1130 /* SetHandleInformation() is preferred because it provides atomicity and gets the job done */
1131 /* on systems with non-IFS LSPs installed. So there is a chance that the socket will be still */
1132 /* inherited on Windows XP with 3rd party firewall/antivirus installed */
1133 if (0 == no_inherit_wsapi && 0 == SetHandleInformation((HANDLE)s->sockets[s->num_socks],
1134 HANDLE_FLAG_INHERIT, 0))
1135 {
1136 zabbix_log(LOG_LEVEL_WARNING, "SetHandleInformation() failed: %s",
1137 strerror_from_system(GetLastError()));
1138 }
1139
1140 /* prevent other processes from binding to the same port */
1141 /* SO_EXCLUSIVEADDRUSE is mutually exclusive with SO_REUSEADDR */
1142 /* on Windows SO_REUSEADDR has different semantics than on Unix */
1143 /* https://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx */
1144 if (ZBX_PROTO_ERROR == setsockopt(s->sockets[s->num_socks], SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
1145 (void *)&on, sizeof(on)))
1146 {
1147 zbx_set_socket_strerror("setsockopt() with %s for [[%s]:%s] failed: %s",
1148 "SO_EXCLUSIVEADDRUSE", NULL != ip ? ip : "-", port,
1149 strerror_from_system(zbx_socket_last_error()));
1150 }
1151 #else
1152 /* enable address reuse */
1153 /* this is to immediately use the address even if it is in TIME_WAIT state */
1154 /* http://www-128.ibm.com/developerworks/linux/library/l-sockpit/index.html */
1155 if (ZBX_PROTO_ERROR == setsockopt(s->sockets[s->num_socks], SOL_SOCKET, SO_REUSEADDR,
1156 (void *)&on, sizeof(on)))
1157 {
1158 zbx_set_socket_strerror("setsockopt() with %s for [[%s]:%s] failed: %s",
1159 "SO_REUSEADDR", NULL != ip ? ip : "-", port,
1160 strerror_from_system(zbx_socket_last_error()));
1161 }
1162 #endif
1163
1164 #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
1165 if (PF_INET6 == current_ai->ai_family &&
1166 ZBX_PROTO_ERROR == setsockopt(s->sockets[s->num_socks], IPPROTO_IPV6,
1167 IPV6_V6ONLY, (void *)&on, sizeof(on)))
1168 {
1169 zbx_set_socket_strerror("setsockopt() with %s for [[%s]:%s] failed: %s",
1170 "IPV6_V6ONLY", NULL != ip ? ip : "-", port,
1171 strerror_from_system(zbx_socket_last_error()));
1172 }
1173 #endif
1174 if (ZBX_PROTO_ERROR == zbx_bind(s->sockets[s->num_socks], current_ai->ai_addr,
1175 current_ai->ai_addrlen))
1176 {
1177 zbx_set_socket_strerror("bind() for [[%s]:%s] failed: %s",
1178 NULL != ip ? ip : "-", port,
1179 strerror_from_system(zbx_socket_last_error()));
1180 zbx_socket_close(s->sockets[s->num_socks]);
1181 #ifdef _WINDOWS
1182 if (WSAEADDRINUSE == zbx_socket_last_error())
1183 #else
1184 if (EADDRINUSE == zbx_socket_last_error())
1185 #endif
1186 continue;
1187 else
1188 goto out;
1189 }
1190
1191 if (ZBX_PROTO_ERROR == listen(s->sockets[s->num_socks], CONFIG_TCP_MAX_BACKLOG_SIZE))
1192 {
1193 zbx_set_socket_strerror("listen() for [[%s]:%s] failed: %s",
1194 NULL != ip ? ip : "-", port,
1195 strerror_from_system(zbx_socket_last_error()));
1196 zbx_socket_close(s->sockets[s->num_socks]);
1197 goto out;
1198 }
1199
1200 s->num_socks++;
1201 }
1202
1203 if (NULL != ai)
1204 {
1205 freeaddrinfo(ai);
1206 ai = NULL;
1207 }
1208
1209 if (NULL == ip || NULL == delim)
1210 break;
1211
1212 *delim = ',';
1213 ip = delim + 1;
1214 }
1215
1216 if (0 == s->num_socks)
1217 {
1218 zbx_set_socket_strerror("zbx_tcp_listen() fatal error: unable to serve on any address [[%s]:%hu]",
1219 NULL != listen_ip ? listen_ip : "-", listen_port);
1220 goto out;
1221 }
1222
1223 ret = SUCCEED;
1224 out:
1225 if (NULL != ips)
1226 zbx_free(ips);
1227
1228 if (NULL != ai)
1229 freeaddrinfo(ai);
1230
1231 if (SUCCEED != ret)
1232 {
1233 for (i = 0; i < s->num_socks; i++)
1234 zbx_socket_close(s->sockets[i]);
1235 }
1236
1237 return ret;
1238 }
1239 #else
1240 int zbx_tcp_listen(zbx_socket_t *s, const char *listen_ip, unsigned short listen_port)
1241 {
1242 ZBX_SOCKADDR serv_addr;
1243 char *ip, *ips, *delim;
1244 int i, on, ret = FAIL;
1245 #ifdef _WINDOWS
1246 /* WSASocket() option to prevent inheritance is available on */
1247 /* Windows Server 2008 R2 or newer and on Windows 7 SP1 or newer */
1248 static int no_inherit_wsapi = -1;
1249
1250 if (-1 == no_inherit_wsapi)
1251 {
1252 /* Both Windows 7 and Windows 2008 R2 are 0x0601 */
1253 no_inherit_wsapi = zbx_is_win_ver_or_greater((_WIN32_WINNT_WIN7 >> 8) & 0xff,
1254 _WIN32_WINNT_WIN7 & 0xff, 1) == SUCCEED;
1255 }
1256 #endif
1257
1258 zbx_socket_clean(s);
1259
1260 ip = ips = (NULL == listen_ip ? NULL : strdup(listen_ip));
1261
1262 while (1)
1263 {
1264 delim = (NULL == ip ? NULL : strchr(ip, ','));
1265 if (NULL != delim)
1266 *delim = '\0';
1267
1268 if (NULL != ip && FAIL == is_ip4(ip))
1269 {
1270 zbx_set_socket_strerror("incorrect IPv4 address [%s]", ip);
1271 goto out;
1272 }
1273
1274 if (ZBX_SOCKET_COUNT == s->num_socks)
1275 {
1276 zbx_set_socket_strerror("not enough space for socket [[%s]:%hu]",
1277 NULL != ip ? ip : "-", listen_port);
1278 goto out;
1279 }
1280
1281 #ifdef _WINDOWS
1282 /* WSA_FLAG_NO_HANDLE_INHERIT prevents socket inheritance if we call CreateProcess() */
1283 /* later on. If it's not available we still try to avoid inheritance by calling */
1284 /* SetHandleInformation() below. WSA_FLAG_OVERLAPPED is not mandatory but strongly */
1285 /* recommended for every socket */
1286 s->sockets[s->num_socks] = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
1287 (0 != no_inherit_wsapi ? WSA_FLAG_NO_HANDLE_INHERIT : 0) | WSA_FLAG_OVERLAPPED);
1288 if (ZBX_SOCKET_ERROR == s->sockets[s->num_socks])
1289 {
1290 zbx_set_socket_strerror("WSASocket() for [[%s]:%hu] failed: %s",
1291 NULL != ip ? ip : "-", listen_port,
1292 strerror_from_system(zbx_socket_last_error()));
1293 #else
1294 if (ZBX_SOCKET_ERROR == (s->sockets[s->num_socks] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)))
1295 {
1296 zbx_set_socket_strerror("socket() for [[%s]:%hu] failed: %s",
1297 NULL != ip ? ip : "-", listen_port,
1298 strerror_from_system(zbx_socket_last_error()));
1299 #endif
1300 goto out;
1301 }
1302
1303 #if !defined(_WINDOWS) && !SOCK_CLOEXEC
1304 if (-1 == fcntl(s->sockets[s->num_socks], F_SETFD, FD_CLOEXEC))
1305 {
1306 zbx_set_socket_strerror("failed to set the FD_CLOEXEC file descriptor flag on "
1307 "socket [[%s]:%hu]: %s", NULL != ip ? ip : "-", listen_port,
1308 strerror_from_system(zbx_socket_last_error()));
1309 }
1310 #endif
1311 on = 1;
1312 #ifdef _WINDOWS
1313 /* If WSA_FLAG_NO_HANDLE_INHERIT not available, prevent listening socket from */
1314 /* inheritance with the old API. Disabling handle inheritance in WSASocket() instead of */
1315 /* SetHandleInformation() is preferred because it provides atomicity and gets the job done */
1316 /* on systems with non-IFS LSPs installed. So there is a chance that the socket will be still */
1317 /* inherited on Windows XP with 3rd party firewall/antivirus installed */
1318 if (0 == no_inherit_wsapi && 0 == SetHandleInformation((HANDLE)s->sockets[s->num_socks],
1319 HANDLE_FLAG_INHERIT, 0))
1320 {
1321 zabbix_log(LOG_LEVEL_WARNING, "SetHandleInformation() failed: %s",
1322 strerror_from_system(GetLastError()));
1323 }
1324
1325 /* prevent other processes from binding to the same port */
1326 /* SO_EXCLUSIVEADDRUSE is mutually exclusive with SO_REUSEADDR */
1327 /* on Windows SO_REUSEADDR has different semantics than on Unix */
1328 /* https://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx */
1329 if (ZBX_PROTO_ERROR == setsockopt(s->sockets[s->num_socks], SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
1330 (void *)&on, sizeof(on)))
1331 {
1332 zbx_set_socket_strerror("setsockopt() with %s for [[%s]:%hu] failed: %s", "SO_EXCLUSIVEADDRUSE",
1333 NULL != ip ? ip : "-", listen_port,
1334 strerror_from_system(zbx_socket_last_error()));
1335
1336 }
1337 #else
1338 /* enable address reuse */
1339 /* this is to immediately use the address even if it is in TIME_WAIT state */
1340 /* http://www-128.ibm.com/developerworks/linux/library/l-sockpit/index.html */
1341 if (ZBX_PROTO_ERROR == setsockopt(s->sockets[s->num_socks], SOL_SOCKET, SO_REUSEADDR,
1342 (void *)&on, sizeof(on)))
1343 {
1344 zbx_set_socket_strerror("setsockopt() with %s for [[%s]:%hu] failed: %s", "SO_REUSEADDR",
1345 NULL != ip ? ip : "-", listen_port,
1346 strerror_from_system(zbx_socket_last_error()));
1347 }
1348 #endif
1349 memset(&serv_addr, 0, sizeof(serv_addr));
1350
1351 serv_addr.sin_family = AF_INET;
1352 serv_addr.sin_addr.s_addr = (NULL != ip ? inet_addr(ip) : htonl(INADDR_ANY));
1353 serv_addr.sin_port = htons((unsigned short)listen_port);
1354
1355 if (ZBX_PROTO_ERROR == bind(s->sockets[s->num_socks], (struct sockaddr *)&serv_addr, sizeof(serv_addr)))
1356 {
1357 zbx_set_socket_strerror("bind() for [[%s]:%hu] failed: %s",
1358 NULL != ip ? ip : "-", listen_port,
1359 strerror_from_system(zbx_socket_last_error()));
1360 zbx_socket_close(s->sockets[s->num_socks]);
1361 goto out;
1362 }
1363
1364 if (ZBX_PROTO_ERROR == listen(s->sockets[s->num_socks], CONFIG_TCP_MAX_BACKLOG_SIZE))
1365 {
1366 zbx_set_socket_strerror("listen() for [[%s]:%hu] failed: %s",
1367 NULL != ip ? ip : "-", listen_port,
1368 strerror_from_system(zbx_socket_last_error()));
1369 zbx_socket_close(s->sockets[s->num_socks]);
1370 goto out;
1371 }
1372
1373 s->num_socks++;
1374
1375 if (NULL == ip || NULL == delim)
1376 break;
1377 *delim = ',';
1378 ip = delim + 1;
1379 }
1380
1381 if (0 == s->num_socks)
1382 {
1383 zbx_set_socket_strerror("zbx_tcp_listen() fatal error: unable to serve on any address [[%s]:%hu]",
1384 NULL != listen_ip ? listen_ip : "-", listen_port);
1385 goto out;
1386 }
1387
1388 ret = SUCCEED;
1389 out:
1390 if (NULL != ips)
1391 zbx_free(ips);
1392
1393 if (SUCCEED != ret)
1394 {
1395 for (i = 0; i < s->num_socks; i++)
1396 zbx_socket_close(s->sockets[i]);
1397 }
1398
1399 return ret;
1400 }
1401 #endif /* HAVE_IPV6 */
1402
1403 /******************************************************************************
1404 * *
1405 * Function: zbx_tcp_accept *
1406 * *
1407 * Purpose: permits an incoming connection attempt on a socket *
1408 * *
1409 * Return value: SUCCEED - success *
1410 * FAIL - an error occurred *
1411 * *
1412 * Author: Eugene Grigorjev, Aleksandrs Saveljevs *
1413 * *
1414 ******************************************************************************/
1415 int zbx_tcp_accept(zbx_socket_t *s, unsigned int tls_accept)
1416 {
1417 ZBX_SOCKADDR serv_addr;
1418 fd_set sock_set;
1419 ZBX_SOCKET accepted_socket;
1420 ZBX_SOCKLEN_T nlen;
1421 int i, n = 0, ret = FAIL;
1422 ssize_t res;
1423 unsigned char buf; /* 1 byte buffer */
1424
1425 zbx_tcp_unaccept(s);
1426
1427 FD_ZERO(&sock_set);
1428
1429 for (i = 0; i < s->num_socks; i++)
1430 {
1431 FD_SET(s->sockets[i], &sock_set);
1432 #ifndef _WINDOWS
1433 if (s->sockets[i] > n)
1434 n = s->sockets[i];
1435 #endif
1436 }
1437
1438 if (ZBX_PROTO_ERROR == select(n + 1, &sock_set, NULL, NULL, NULL))
1439 {
1440 zbx_set_socket_strerror("select() failed: %s", strerror_from_system(zbx_socket_last_error()));
1441 return ret;
1442 }
1443
1444 for (i = 0; i < s->num_socks; i++)
1445 {
1446 if (FD_ISSET(s->sockets[i], &sock_set))
1447 break;
1448 }
1449
1450 /* Since this socket was returned by select(), we know we have */
1451 /* a connection waiting and that this accept() will not block. */
1452 nlen = sizeof(serv_addr);
1453 if (ZBX_SOCKET_ERROR == (accepted_socket = (ZBX_SOCKET)accept(s->sockets[i], (struct sockaddr *)&serv_addr,
1454 &nlen)))
1455 {
1456 zbx_set_socket_strerror("accept() failed: %s", strerror_from_system(zbx_socket_last_error()));
1457 return ret;
1458 }
1459
1460 s->socket_orig = s->socket; /* remember main socket */
1461 s->socket = accepted_socket; /* replace socket to accepted */
1462 s->accepted = 1;
1463
1464 if (SUCCEED != zbx_socket_peer_ip_save(s))
1465 {
1466 /* cannot get peer IP address */
1467 zbx_tcp_unaccept(s);
1468 goto out;
1469 }
1470
1471 zbx_socket_timeout_set(s, CONFIG_TIMEOUT);
1472
1473 if (ZBX_SOCKET_ERROR == (res = recv(s->socket, &buf, 1, MSG_PEEK)))
1474 {
1475 zbx_set_socket_strerror("from %s: reading first byte from connection failed: %s", s->peer,
1476 strerror_from_system(zbx_socket_last_error()));
1477 zbx_tcp_unaccept(s);
1478 goto out;
1479 }
1480
1481 /* if the 1st byte is 0x16 then assume it's a TLS connection */
1482 if (1 == res && '\x16' == buf)
1483 {
1484 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1485 if (0 != (tls_accept & (ZBX_TCP_SEC_TLS_CERT | ZBX_TCP_SEC_TLS_PSK)))
1486 {
1487 char *error = NULL;
1488
1489 if (SUCCEED != zbx_tls_accept(s, tls_accept, &error))
1490 {
1491 zbx_set_socket_strerror("from %s: %s", s->peer, error);
1492 zbx_tcp_unaccept(s);
1493 zbx_free(error);
1494 goto out;
1495 }
1496 }
1497 else
1498 {
1499 zbx_set_socket_strerror("from %s: TLS connections are not allowed", s->peer);
1500 zbx_tcp_unaccept(s);
1501 goto out;
1502 }
1503 #else
1504 zbx_set_socket_strerror("from %s: support for TLS was not compiled in", s->peer);
1505 zbx_tcp_unaccept(s);
1506 goto out;
1507 #endif
1508 }
1509 else
1510 {
1511 if (0 == (tls_accept & ZBX_TCP_SEC_UNENCRYPTED))
1512 {
1513 zbx_set_socket_strerror("from %s: unencrypted connections are not allowed", s->peer);
1514 zbx_tcp_unaccept(s);
1515 goto out;
1516 }
1517
1518 s->connection_type = ZBX_TCP_SEC_UNENCRYPTED;
1519 }
1520
1521 ret = SUCCEED;
1522 out:
1523 zbx_socket_timeout_cleanup(s);
1524
1525 return ret;
1526 }
1527
1528 /******************************************************************************
1529 * *
1530 * Function: zbx_tcp_unaccept *
1531 * *
1532 * Purpose: close accepted connection *
1533 * *
1534 * Author: Eugene Grigorjev *
1535 * *
1536 ******************************************************************************/
1537 void zbx_tcp_unaccept(zbx_socket_t *s)
1538 {
1539 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1540 zbx_tls_close(s);
1541 #endif
1542 if (!s->accepted) return;
1543
1544 shutdown(s->socket, 2);
1545
1546 zbx_socket_close(s->socket);
1547
1548 s->socket = s->socket_orig; /* restore main socket */
1549 s->socket_orig = ZBX_SOCKET_ERROR;
1550 s->accepted = 0;
1551 }
1552
1553 /******************************************************************************
1554 * *
1555 * Function: zbx_socket_find_line *
1556 * *
1557 * Purpose: finds the next line in socket data buffer *
1558 * *
1559 * Parameters: s - [IN] the socket *
1560 * *
1561 * Return value: A pointer to the next line or NULL if the socket data buffer *
1562 * contains no more lines. *
1563 * *
1564 ******************************************************************************/
1565 static const char *zbx_socket_find_line(zbx_socket_t *s)
1566 {
1567 char *ptr, *line = NULL;
1568
1569 if (NULL == s->next_line)
1570 return NULL;
1571
1572 /* check if the buffer contains the next line */
1573 if ((size_t)(s->next_line - s->buffer) <= s->read_bytes && NULL != (ptr = strchr(s->next_line, '\n')))
1574 {
1575 line = s->next_line;
1576 s->next_line = ptr + 1;
1577
1578 if (ptr > line && '\r' == *(ptr - 1))
1579 ptr--;
1580
1581 *ptr = '\0';
1582 }
1583
1584 return line;
1585 }
1586
1587 /******************************************************************************
1588 * *
1589 * Function: zbx_tcp_recv_line *
1590 * *
1591 * Purpose: reads next line from a socket *
1592 * *
1593 * Parameters: s - [IN] the socket *
1594 * *
1595 * Return value: a pointer to the line in socket buffer or NULL if there are *
1596 * no more lines (socket was closed or an error occurred) *
1597 * *
1598 * Comments: Lines larger than 64KB are truncated. *
1599 * *
1600 ******************************************************************************/
1601 const char *zbx_tcp_recv_line(zbx_socket_t *s)
1602 {
1603 #define ZBX_TCP_LINE_LEN (64 * ZBX_KIBIBYTE)
1604
1605 char buffer[ZBX_STAT_BUF_LEN], *ptr = NULL;
1606 const char *line;
1607 ssize_t nbytes;
1608 size_t alloc = 0, offset = 0, line_length, left;
1609
1610 /* check if the buffer already contains the next line */
1611 if (NULL != (line = zbx_socket_find_line(s)))
1612 return line;
1613
1614 /* Find the size of leftover data from the last read line operation and copy */
1615 /* the leftover data to the static buffer and reset the dynamic buffer. */
1616 /* Because we are reading data in ZBX_STAT_BUF_LEN chunks the leftover */
1617 /* data will always fit the static buffer. */
1618 if (NULL != s->next_line)
1619 {
1620 left = s->read_bytes - (s->next_line - s->buffer);
1621 memmove(s->buf_stat, s->next_line, left);
1622 }
1623 else
1624 left = 0;
1625
1626 s->read_bytes = left;
1627 s->next_line = s->buf_stat;
1628
1629 zbx_socket_free(s);
1630 s->buf_type = ZBX_BUF_TYPE_STAT;
1631 s->buffer = s->buf_stat;
1632
1633 /* read more data into static buffer */
1634 if (ZBX_PROTO_ERROR == (nbytes = ZBX_TCP_READ(s->socket, s->buf_stat + left, ZBX_STAT_BUF_LEN - left - 1)))
1635 goto out;
1636
1637 s->buf_stat[left + nbytes] = '\0';
1638
1639 if (0 == nbytes)
1640 {
1641 /* Socket was closed before newline was found. If we have data in buffer */
1642 /* return it with success. Otherwise return failure. */
1643 line = 0 != s->read_bytes ? s->next_line : NULL;
1644 s->next_line += s->read_bytes;
1645
1646 goto out;
1647 }
1648
1649 s->read_bytes += nbytes;
1650
1651 /* check if the static buffer now contains the next line */
1652 if (NULL != (line = zbx_socket_find_line(s)))
1653 goto out;
1654
1655 /* copy the static buffer data into dynamic buffer */
1656 s->buf_type = ZBX_BUF_TYPE_DYN;
1657 s->buffer = NULL;
1658 zbx_strncpy_alloc(&s->buffer, &alloc, &offset, s->buf_stat, s->read_bytes);
1659 line_length = s->read_bytes;
1660
1661 /* Read data into dynamic buffer until newline has been found. */
1662 /* Lines larger than ZBX_TCP_LINE_LEN bytes will be truncated. */
1663 do
1664 {
1665 if (ZBX_PROTO_ERROR == (nbytes = ZBX_TCP_READ(s->socket, buffer, ZBX_STAT_BUF_LEN - 1)))
1666 goto out;
1667
1668 if (0 == nbytes)
1669 {
1670 /* socket was closed before newline was found, just return the data we have */
1671 line = 0 != s->read_bytes ? s->buffer : NULL;
1672 s->next_line = s->buffer + s->read_bytes;
1673
1674 goto out;
1675 }
1676
1677 buffer[nbytes] = '\0';
1678 ptr = strchr(buffer, '\n');
1679
1680 if (s->read_bytes + nbytes < ZBX_TCP_LINE_LEN && s->read_bytes == line_length)
1681 {
1682 zbx_strncpy_alloc(&s->buffer, &alloc, &offset, buffer, nbytes);
1683 s->read_bytes += nbytes;
1684 }
1685 else
1686 {
1687 if (0 != (left = (NULL == ptr ? ZBX_TCP_LINE_LEN - s->read_bytes :
1688 MIN(ZBX_TCP_LINE_LEN - s->read_bytes, (size_t)(ptr - buffer)))))
1689 {
1690 /* fill the string to the defined limit */
1691 zbx_strncpy_alloc(&s->buffer, &alloc, &offset, buffer, left);
1692 s->read_bytes += left;
1693 }
1694
1695 /* if the line exceeds the defined limit then truncate it by skipping data until the newline */
1696 if (NULL != ptr)
1697 {
1698 zbx_strncpy_alloc(&s->buffer, &alloc, &offset, ptr, nbytes - (ptr - buffer));
1699 s->read_bytes += nbytes - (ptr - buffer);
1700 }
1701 }
1702
1703 line_length += nbytes;
1704
1705 }
1706 while (NULL == ptr);
1707
1708 s->next_line = s->buffer;
1709 line = zbx_socket_find_line(s);
1710 out:
1711 return line;
1712 }
1713
1714 static ssize_t zbx_tcp_read(zbx_socket_t *s, char *buf, size_t len)
1715 {
1716 ssize_t res;
1717 int err;
1718 #ifdef _WINDOWS
1719 double sec;
1720 #endif
1721 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1722 if (NULL != s->tls_ctx) /* TLS connection */
1723 {
1724 char *error = NULL;
1725
1726 if (ZBX_PROTO_ERROR == (res = zbx_tls_read(s, buf, len, &error)))
1727 {
1728 zbx_set_socket_strerror("%s", error);
1729 zbx_free(error);
1730 }
1731
1732 return res;
1733 }
1734 #endif
1735 #ifdef _WINDOWS
1736 zbx_alarm_flag_clear();
1737 sec = zbx_time();
1738 #endif
1739 do
1740 {
1741 res = ZBX_TCP_READ(s->socket, buf, len);
1742 #ifdef _WINDOWS
1743 if (s->timeout < zbx_time() - sec)
1744 zbx_alarm_flag_set();
1745 #endif
1746 if (SUCCEED == zbx_alarm_timed_out())
1747 {
1748 zbx_set_socket_strerror("ZBX_TCP_READ() timed out");
1749 return ZBX_PROTO_ERROR;
1750 }
1751 }
1752 while (ZBX_PROTO_ERROR == res && ZBX_PROTO_AGAIN == (err = zbx_socket_last_error()));
1753
1754 if (ZBX_PROTO_ERROR == res)
1755 zbx_set_socket_strerror("ZBX_TCP_READ() failed: %s", strerror_from_system(err));
1756
1757 return res;
1758 }
1759
1760 /******************************************************************************
1761 * *
1762 * Function: zbx_tcp_recv_ext *
1763 * *
1764 * Purpose: receive data *
1765 * *
1766 * Return value: number of bytes received - success, *
1767 * FAIL - an error occurred *
1768 * *
1769 * Author: Eugene Grigorjev *
1770 * *
1771 ******************************************************************************/
1772 ssize_t zbx_tcp_recv_ext(zbx_socket_t *s, int timeout, unsigned char flags)
1773 {
1774 #define ZBX_TCP_EXPECT_HEADER 1
1775 #define ZBX_TCP_EXPECT_VERSION 2
1776 #define ZBX_TCP_EXPECT_VERSION_VALIDATE 3
1777 #define ZBX_TCP_EXPECT_LENGTH 4
1778 #define ZBX_TCP_EXPECT_SIZE 5
1779
1780 ssize_t nbytes;
1781 size_t buf_dyn_bytes = 0, buf_stat_bytes = 0, offset = 0;
1782 zbx_uint64_t expected_len = 16 * ZBX_MEBIBYTE, reserved = 0, max_len;
1783 unsigned char expect = ZBX_TCP_EXPECT_HEADER;
1784 int protocol_version;
1785 #if defined(_WINDOWS)
1786 max_len = ZBX_MAX_RECV_DATA_SIZE;
1787 #else
1788 max_len = 0 != (flags & ZBX_TCP_LARGE) ? ZBX_MAX_RECV_LARGE_DATA_SIZE : ZBX_MAX_RECV_DATA_SIZE;
1789 #endif
1790
1791 if (0 != timeout)
1792 zbx_socket_timeout_set(s, timeout);
1793
1794 zbx_socket_free(s);
1795
1796 s->buf_type = ZBX_BUF_TYPE_STAT;
1797 s->buffer = s->buf_stat;
1798
1799 while (0 != (nbytes = zbx_tcp_read(s, s->buf_stat + buf_stat_bytes, sizeof(s->buf_stat) - buf_stat_bytes)))
1800 {
1801 if (ZBX_PROTO_ERROR == nbytes)
1802 goto out;
1803
1804 if (ZBX_BUF_TYPE_STAT == s->buf_type)
1805 buf_stat_bytes += nbytes;
1806 else
1807 {
1808 if (buf_dyn_bytes + nbytes <= expected_len)
1809 memcpy(s->buffer + buf_dyn_bytes, s->buf_stat, nbytes);
1810 buf_dyn_bytes += nbytes;
1811 }
1812
1813 if (buf_stat_bytes + buf_dyn_bytes >= expected_len)
1814 break;
1815
1816 if (ZBX_TCP_EXPECT_HEADER == expect)
1817 {
1818 if (ZBX_TCP_HEADER_LEN > buf_stat_bytes)
1819 {
1820 if (0 == strncmp(s->buf_stat, ZBX_TCP_HEADER_DATA, buf_stat_bytes))
1821 continue;
1822
1823 break;
1824 }
1825 else
1826 {
1827 if (0 != strncmp(s->buf_stat, ZBX_TCP_HEADER_DATA, ZBX_TCP_HEADER_LEN))
1828 {
1829 /* invalid header, abort receiving */
1830 break;
1831 }
1832
1833 expect = ZBX_TCP_EXPECT_VERSION;
1834 offset += ZBX_TCP_HEADER_LEN;
1835 }
1836 }
1837
1838 if (ZBX_TCP_EXPECT_VERSION == expect)
1839 {
1840 if (offset + 1 > buf_stat_bytes)
1841 continue;
1842
1843 expect = ZBX_TCP_EXPECT_VERSION_VALIDATE;
1844 protocol_version = s->buf_stat[ZBX_TCP_HEADER_LEN];
1845
1846 if (0 == (protocol_version & ZBX_TCP_PROTOCOL) ||
1847 protocol_version > (ZBX_TCP_PROTOCOL | ZBX_TCP_COMPRESS | flags))
1848 {
1849 /* invalid protocol version, abort receiving */
1850 break;
1851 }
1852 s->protocol = protocol_version;
1853 expect = ZBX_TCP_EXPECT_LENGTH;
1854 offset++;
1855 }
1856
1857 if (ZBX_TCP_EXPECT_LENGTH == expect)
1858 {
1859 if (0 != (protocol_version & ZBX_TCP_LARGE))
1860 {
1861 zbx_uint64_t len64_le;
1862
1863 if (offset + 2 * sizeof(len64_le) > buf_stat_bytes)
1864 continue;
1865
1866 memcpy(&len64_le, s->buf_stat + offset, sizeof(len64_le));
1867 offset += sizeof(len64_le);
1868 expected_len = zbx_letoh_uint64(len64_le);
1869
1870 memcpy(&len64_le, s->buf_stat + offset, sizeof(len64_le));
1871 offset += sizeof(len64_le);
1872 reserved = zbx_letoh_uint64(len64_le);
1873 }
1874 else
1875 {
1876 zbx_uint32_t len32_le;
1877
1878 if (offset + 2 * sizeof(len32_le) > buf_stat_bytes)
1879 continue;
1880
1881 memcpy(&len32_le, s->buf_stat + offset, sizeof(len32_le));
1882 offset += sizeof(len32_le);
1883 expected_len = zbx_letoh_uint32(len32_le);
1884
1885 memcpy(&len32_le, s->buf_stat + offset, sizeof(len32_le));
1886 offset += sizeof(len32_le);
1887 reserved = zbx_letoh_uint32(len32_le);
1888 }
1889
1890 if (max_len < expected_len)
1891 {
1892 zabbix_log(LOG_LEVEL_WARNING, "Message size " ZBX_FS_UI64 " from %s exceeds the "
1893 "maximum size " ZBX_FS_UI64 " bytes. Message ignored.", expected_len,
1894 s->peer, max_len);
1895 nbytes = ZBX_PROTO_ERROR;
1896 goto out;
1897 }
1898
1899 /* compressed protocol stores uncompressed packet size in the reserved data */
1900 if (max_len < reserved)
1901 {
1902 zabbix_log(LOG_LEVEL_WARNING, "Uncompressed message size " ZBX_FS_UI64 " from %s"
1903 " exceeds the maximum size " ZBX_FS_UI64 " bytes. Message ignored.",
1904 reserved, s->peer, max_len);
1905 nbytes = ZBX_PROTO_ERROR;
1906 goto out;
1907 }
1908
1909 if (sizeof(s->buf_stat) > expected_len)
1910 {
1911 buf_stat_bytes -= offset;
1912 memmove(s->buf_stat, s->buf_stat + offset, buf_stat_bytes);
1913 }
1914 else
1915 {
1916 s->buf_type = ZBX_BUF_TYPE_DYN;
1917 s->buffer = (char *)zbx_malloc(NULL, expected_len + 1);
1918 buf_dyn_bytes = buf_stat_bytes - offset;
1919 buf_stat_bytes = 0;
1920 memcpy(s->buffer, s->buf_stat + offset, buf_dyn_bytes);
1921 }
1922
1923 expect = ZBX_TCP_EXPECT_SIZE;
1924
1925 if (buf_stat_bytes + buf_dyn_bytes >= expected_len)
1926 break;
1927 }
1928 }
1929
1930 if (ZBX_TCP_EXPECT_SIZE == expect)
1931 {
1932 if (buf_stat_bytes + buf_dyn_bytes == expected_len)
1933 {
1934 if (0 != (protocol_version & ZBX_TCP_COMPRESS))
1935 {
1936 char *out;
1937 size_t out_size = reserved;
1938
1939 out = (char *)zbx_malloc(NULL, reserved + 1);
1940 if (FAIL == zbx_uncompress(s->buffer, buf_stat_bytes + buf_dyn_bytes, out, &out_size))
1941 {
1942 zbx_free(out);
1943 zbx_set_socket_strerror("cannot uncompress data: %s", zbx_compress_strerror());
1944 nbytes = ZBX_PROTO_ERROR;
1945 goto out;
1946 }
1947
1948 if (out_size != reserved)
1949 {
1950 zbx_free(out);
1951 zbx_set_socket_strerror("size of uncompressed data is less than expected");
1952 nbytes = ZBX_PROTO_ERROR;
1953 goto out;
1954 }
1955
1956 if (ZBX_BUF_TYPE_DYN == s->buf_type)
1957 zbx_free(s->buffer);
1958
1959 s->buf_type = ZBX_BUF_TYPE_DYN;
1960 s->buffer = out;
1961 s->read_bytes = reserved;
1962
1963 zabbix_log(LOG_LEVEL_TRACE, "%s(): received " ZBX_FS_SIZE_T " bytes with"
1964 " compression ratio %.1f", __func__,
1965 (zbx_fs_size_t)(buf_stat_bytes + buf_dyn_bytes),
1966 (double)reserved / (buf_stat_bytes + buf_dyn_bytes));
1967 }
1968 else
1969 s->read_bytes = buf_stat_bytes + buf_dyn_bytes;
1970
1971 s->buffer[s->read_bytes] = '\0';
1972 }
1973 else
1974 {
1975 if (buf_stat_bytes + buf_dyn_bytes < expected_len)
1976 {
1977 zabbix_log(LOG_LEVEL_WARNING, "Message from %s is shorter than expected " ZBX_FS_UI64
1978 " bytes. Message ignored.", s->peer, (zbx_uint64_t)expected_len);
1979 }
1980 else
1981 {
1982 zabbix_log(LOG_LEVEL_WARNING, "Message from %s is longer than expected " ZBX_FS_UI64
1983 " bytes. Message ignored.", s->peer, (zbx_uint64_t)expected_len);
1984 }
1985
1986 nbytes = ZBX_PROTO_ERROR;
1987 }
1988 }
1989 else if (ZBX_TCP_EXPECT_LENGTH == expect)
1990 {
1991 zabbix_log(LOG_LEVEL_WARNING, "Message from %s is missing data length. Message ignored.", s->peer);
1992 nbytes = ZBX_PROTO_ERROR;
1993 }
1994 else if (ZBX_TCP_EXPECT_VERSION == expect)
1995 {
1996 zabbix_log(LOG_LEVEL_WARNING, "Message from %s is missing protocol version. Message ignored.",
1997 s->peer);
1998 nbytes = ZBX_PROTO_ERROR;
1999 }
2000 else if (ZBX_TCP_EXPECT_VERSION_VALIDATE == expect)
2001 {
2002 zabbix_log(LOG_LEVEL_WARNING, "Message from %s is using unsupported protocol version \"%d\"."
2003 " Message ignored.", s->peer, protocol_version);
2004 nbytes = ZBX_PROTO_ERROR;
2005 }
2006 else if (0 != buf_stat_bytes)
2007 {
2008 zabbix_log(LOG_LEVEL_WARNING, "Message from %s is missing header. Message ignored.", s->peer);
2009 nbytes = ZBX_PROTO_ERROR;
2010 }
2011 else
2012 {
2013 s->read_bytes = 0;
2014 s->buffer[s->read_bytes] = '\0';
2015 }
2016 out:
2017 if (0 != timeout)
2018 zbx_socket_timeout_cleanup(s);
2019
2020 return (ZBX_PROTO_ERROR == nbytes ? FAIL : (ssize_t)(s->read_bytes + offset));
2021
2022 #undef ZBX_TCP_EXPECT_HEADER
2023 #undef ZBX_TCP_EXPECT_LENGTH
2024 #undef ZBX_TCP_EXPECT_SIZE
2025 }
2026
2027 /******************************************************************************
2028 * *
2029 * Function: zbx_tcp_recv_raw_ext *
2030 * *
2031 * Purpose: receive data till connection is closed *
2032 * *
2033 * Return value: number of bytes received - success, *
2034 * FAIL - an error occurred *
2035 * *
2036 ******************************************************************************/
2037 ssize_t zbx_tcp_recv_raw_ext(zbx_socket_t *s, int timeout)
2038 {
2039 ssize_t nbytes;
2040 size_t allocated = 8 * ZBX_STAT_BUF_LEN, buf_dyn_bytes = 0, buf_stat_bytes = 0;
2041 zbx_uint64_t expected_len = 16 * ZBX_MEBIBYTE;
2042
2043 if (0 != timeout)
2044 zbx_socket_timeout_set(s, timeout);
2045
2046 zbx_socket_free(s);
2047
2048 s->buf_type = ZBX_BUF_TYPE_STAT;
2049 s->buffer = s->buf_stat;
2050
2051 while (0 != (nbytes = zbx_tcp_read(s, s->buf_stat + buf_stat_bytes, sizeof(s->buf_stat) - buf_stat_bytes)))
2052 {
2053 if (ZBX_PROTO_ERROR == nbytes)
2054 goto out;
2055
2056 if (ZBX_BUF_TYPE_STAT == s->buf_type)
2057 buf_stat_bytes += nbytes;
2058 else
2059 {
2060 if (buf_dyn_bytes + nbytes >= allocated)
2061 {
2062 while (buf_dyn_bytes + nbytes >= allocated)
2063 allocated *= 2;
2064 s->buffer = (char *)zbx_realloc(s->buffer, allocated);
2065 }
2066
2067 memcpy(s->buffer + buf_dyn_bytes, s->buf_stat, nbytes);
2068 buf_dyn_bytes += nbytes;
2069 }
2070
2071 if (buf_stat_bytes + buf_dyn_bytes >= expected_len)
2072 break;
2073
2074 if (sizeof(s->buf_stat) == buf_stat_bytes)
2075 {
2076 s->buf_type = ZBX_BUF_TYPE_DYN;
2077 s->buffer = (char *)zbx_malloc(NULL, allocated);
2078 buf_dyn_bytes = sizeof(s->buf_stat);
2079 buf_stat_bytes = 0;
2080 memcpy(s->buffer, s->buf_stat, sizeof(s->buf_stat));
2081 }
2082 }
2083
2084 if (buf_stat_bytes + buf_dyn_bytes >= expected_len)
2085 {
2086 zabbix_log(LOG_LEVEL_WARNING, "Message from %s is longer than " ZBX_FS_UI64 " bytes allowed for"
2087 " plain text. Message ignored.", s->peer, expected_len);
2088 nbytes = ZBX_PROTO_ERROR;
2089 goto out;
2090 }
2091
2092 s->read_bytes = buf_stat_bytes + buf_dyn_bytes;
2093 s->buffer[s->read_bytes] = '\0';
2094 out:
2095 if (0 != timeout)
2096 zbx_socket_timeout_cleanup(s);
2097
2098 return (ZBX_PROTO_ERROR == nbytes ? FAIL : (ssize_t)(s->read_bytes));
2099 }
2100
2101 static int subnet_match(int af, unsigned int prefix_size, const void *address1, const void *address2)
2102 {
2103 unsigned char netmask[16] = {0};
2104 int i, j, bytes;
2105
2106 if (af == AF_INET)
2107 {
2108 if (prefix_size > IPV4_MAX_CIDR_PREFIX)
2109 return FAIL;
2110 bytes = 4;
2111 }
2112 else
2113 {
2114 if (prefix_size > IPV6_MAX_CIDR_PREFIX)
2115 return FAIL;
2116 bytes = 16;
2117 }
2118
2119 /* CIDR notation to subnet mask */
2120 for (i = (int)prefix_size, j = 0; i > 0 && j < bytes; i -= 8, j++)
2121 netmask[j] = i >= 8 ? 0xFF : ~((1 << (8 - i)) - 1);
2122
2123 /* The result of the bitwise AND operation of IP address and the subnet mask is the network prefix. */
2124 /* All hosts on a subnetwork have the same network prefix. */
2125 for (i = 0; i < bytes; i++)
2126 {
2127 if ((((const unsigned char *)address1)[i] & netmask[i]) !=
2128 (((const unsigned char *)address2)[i] & netmask[i]))
2129 {
2130 return FAIL;
2131 }
2132 }
2133
2134 return SUCCEED;
2135 }
2136
2137 #ifndef HAVE_IPV6
2138 static int zbx_ip_cmp(unsigned int prefix_size, const struct addrinfo *current_ai, ZBX_SOCKADDR name)
2139 {
2140 struct sockaddr_in *name4 = (struct sockaddr_in *)&name,
2141 *ai_addr4 = (struct sockaddr_in *)current_ai->ai_addr;
2142
2143 return subnet_match(current_ai->ai_family, prefix_size, &name4->sin_addr.s_addr, &ai_addr4->sin_addr.s_addr);
2144 }
2145 #else
2146 static int zbx_ip_cmp(unsigned int prefix_size, const struct addrinfo *current_ai, ZBX_SOCKADDR name)
2147 {
2148 /* Network Byte Order is ensured */
2149 /* IPv4-compatible, the first 96 bits are zeros */
2150 const unsigned char ipv4_compat_mask[12] = {0};
2151 /* IPv4-mapped, the first 80 bits are zeros, 16 next - ones */
2152 const unsigned char ipv4_mapped_mask[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255};
2153
2154 struct sockaddr_in *name4 = (struct sockaddr_in *)&name,
2155 *ai_addr4 = (struct sockaddr_in *)current_ai->ai_addr;
2156 struct sockaddr_in6 *name6 = (struct sockaddr_in6 *)&name,
2157 *ai_addr6 = (struct sockaddr_in6 *)current_ai->ai_addr;
2158
2159 #ifdef HAVE_SOCKADDR_STORAGE_SS_FAMILY
2160 if (current_ai->ai_family == name.ss_family)
2161 #else
2162 if (current_ai->ai_family == name.__ss_family)
2163 #endif
2164 {
2165 switch (current_ai->ai_family)
2166 {
2167 case AF_INET:
2168 if (SUCCEED == subnet_match(current_ai->ai_family, prefix_size, &name4->sin_addr.s_addr,
2169 &ai_addr4->sin_addr.s_addr))
2170 {
2171 return SUCCEED;
2172 }
2173 break;
2174 case AF_INET6:
2175 if (SUCCEED == subnet_match(current_ai->ai_family, prefix_size, name6->sin6_addr.s6_addr,
2176 ai_addr6->sin6_addr.s6_addr))
2177 {
2178 return SUCCEED;
2179 }
2180 break;
2181 }
2182 }
2183 else
2184 {
2185 unsigned char ipv6_compat_address[16], ipv6_mapped_address[16];
2186
2187 switch (current_ai->ai_family)
2188 {
2189 case AF_INET:
2190 /* incoming AF_INET6, must see whether it is compatible or mapped */
2191 if ((0 == memcmp(name6->sin6_addr.s6_addr, ipv4_compat_mask, 12) ||
2192 0 == memcmp(name6->sin6_addr.s6_addr, ipv4_mapped_mask, 12)) &&
2193 SUCCEED == subnet_match(AF_INET, prefix_size,
2194 &name6->sin6_addr.s6_addr[12], &ai_addr4->sin_addr.s_addr))
2195 {
2196 return SUCCEED;
2197 }
2198 break;
2199 case AF_INET6:
2200 /* incoming AF_INET, must see whether the given is compatible or mapped */
2201 memcpy(ipv6_compat_address, ipv4_compat_mask, sizeof(ipv4_compat_mask));
2202 memcpy(&ipv6_compat_address[sizeof(ipv4_compat_mask)], &name4->sin_addr.s_addr, 4);
2203
2204 memcpy(ipv6_mapped_address, ipv4_mapped_mask, sizeof(ipv4_mapped_mask));
2205 memcpy(&ipv6_mapped_address[sizeof(ipv4_mapped_mask)], &name4->sin_addr.s_addr, 4);
2206
2207 if (SUCCEED == subnet_match(AF_INET6, prefix_size,
2208 &ai_addr6->sin6_addr.s6_addr, ipv6_compat_address) ||
2209 SUCCEED == subnet_match(AF_INET6, prefix_size,
2210 &ai_addr6->sin6_addr.s6_addr, ipv6_mapped_address))
2211 {
2212 return SUCCEED;
2213 }
2214 break;
2215 }
2216 }
2217 return FAIL;
2218 }
2219 #endif
2220
2221 static int validate_cidr(const char *ip, const char *cidr, void *value)
2222 {
2223 if (SUCCEED == is_ip4(ip))
2224 return is_uint_range(cidr, value, 0, IPV4_MAX_CIDR_PREFIX);
2225 #ifdef HAVE_IPV6
2226 if (SUCCEED == is_ip6(ip))
2227 return is_uint_range(cidr, value, 0, IPV6_MAX_CIDR_PREFIX);
2228 #endif
2229 return FAIL;
2230 }
2231
2232 int zbx_validate_peer_list(const char *peer_list, char **error)
2233 {
2234 char *start, *end, *cidr_sep;
2235 char tmp[MAX_STRING_LEN];
2236
2237 strscpy(tmp, peer_list);
2238
2239 for (start = tmp; '\0' != *start;)
2240 {
2241 if (NULL != (end = strchr(start, ',')))
2242 *end = '\0';
2243
2244 if (NULL != (cidr_sep = strchr(start, '/')))
2245 {
2246 *cidr_sep = '\0';
2247
2248 if (FAIL == validate_cidr(start, cidr_sep + 1, NULL))
2249 {
2250 *cidr_sep = '/';
2251 *error = zbx_dsprintf(NULL, "\"%s\"", start);
2252 return FAIL;
2253 }
2254 }
2255 else if (FAIL == is_supported_ip(start) && FAIL == zbx_validate_hostname(start))
2256 {
2257 *error = zbx_dsprintf(NULL, "\"%s\"", start);
2258 return FAIL;
2259 }
2260
2261 if (NULL != end)
2262 start = end + 1;
2263 else
2264 break;
2265 }
2266
2267 return SUCCEED;
2268 }
2269
2270 /******************************************************************************
2271 * *
2272 * Function: zbx_tcp_check_allowed_peers *
2273 * *
2274 * Purpose: check if connection initiator is in list of peers *
2275 * *
2276 * Parameters: s - [IN] socket descriptor *
2277 * peer_list - [IN] comma-delimited list of allowed peers. *
2278 * NULL not allowed. Empty string results in *
2279 * return value FAIL. *
2280 * *
2281 * Return value: SUCCEED - connection allowed *
2282 * FAIL - connection is not allowed *
2283 * *
2284 * Author: Alexei Vladishev, Dmitry Borovikov *
2285 * *
2286 * Comments: standard, compatible and IPv4-mapped addresses are treated *
2287 * the same: 127.0.0.1 == ::127.0.0.1 == ::ffff:127.0.0.1 *
2288 * *
2289 ******************************************************************************/
2290 int zbx_tcp_check_allowed_peers(const zbx_socket_t *s, const char *peer_list)
2291 {
2292 char *start = NULL, *end = NULL, *cidr_sep, tmp[MAX_STRING_LEN];
2293 int prefix_size;
2294
2295 /* examine list of allowed peers which may include DNS names, IPv4/6 addresses and addresses in CIDR notation */
2296
2297 strscpy(tmp, peer_list);
2298
2299 for (start = tmp; '\0' != *start;)
2300 {
2301 struct addrinfo hints, *ai = NULL, *current_ai;
2302
2303 prefix_size = -1;
2304
2305 if (NULL != (end = strchr(start, ',')))
2306 *end = '\0';
2307
2308 if (NULL != (cidr_sep = strchr(start, '/')))
2309 {
2310 *cidr_sep = '\0';
2311
2312 /* validate_cidr() may overwrite 'prefix_size' */
2313 if (SUCCEED != validate_cidr(start, cidr_sep + 1, &prefix_size))
2314 *cidr_sep = '/'; /* CIDR is only supported for IP */
2315 }
2316
2317 memset(&hints, 0, sizeof(hints));
2318 hints.ai_family = AF_UNSPEC;
2319 hints.ai_socktype = SOCK_STREAM;
2320 hints.ai_protocol = IPPROTO_TCP;
2321
2322 if (0 == getaddrinfo(start, NULL, &hints, &ai))
2323 {
2324 for (current_ai = ai; NULL != current_ai; current_ai = current_ai->ai_next)
2325 {
2326 int prefix_size_current = prefix_size;
2327
2328 if (-1 == prefix_size_current)
2329 {
2330 prefix_size_current = (current_ai->ai_family == AF_INET ?
2331 IPV4_MAX_CIDR_PREFIX : IPV6_MAX_CIDR_PREFIX);
2332 }
2333
2334 if (SUCCEED == zbx_ip_cmp(prefix_size_current, current_ai, s->peer_info))
2335 {
2336 freeaddrinfo(ai);
2337 return SUCCEED;
2338 }
2339 }
2340 freeaddrinfo(ai);
2341 }
2342
2343 if (NULL != end)
2344 start = end + 1;
2345 else
2346 break;
2347 }
2348
2349 zbx_set_socket_strerror("connection from \"%s\" rejected, allowed hosts: \"%s\"", s->peer, peer_list);
2350
2351 return FAIL;
2352 }
2353
2354 /******************************************************************************
2355 * *
2356 * Function: zbx_tcp_connection_type_name *
2357 * *
2358 * Purpose: translate connection type code to name *
2359 * *
2360 ******************************************************************************/
2361 const char *zbx_tcp_connection_type_name(unsigned int type)
2362 {
2363 switch (type)
2364 {
2365 case ZBX_TCP_SEC_UNENCRYPTED:
2366 return "unencrypted";
2367 case ZBX_TCP_SEC_TLS_CERT:
2368 return "TLS with certificate";
2369 case ZBX_TCP_SEC_TLS_PSK:
2370 return "TLS with PSK";
2371 default:
2372 return "unknown";
2373 }
2374 }
2375
2376 int zbx_udp_connect(zbx_socket_t *s, const char *source_ip, const char *ip, unsigned short port, int timeout)
2377 {
2378 return zbx_socket_create(s, SOCK_DGRAM, source_ip, ip, port, timeout, ZBX_TCP_SEC_UNENCRYPTED, NULL, NULL);
2379 }
2380
2381 int zbx_udp_send(zbx_socket_t *s, const char *data, size_t data_len, int timeout)
2382 {
2383 int ret = SUCCEED;
2384
2385 if (0 != timeout)
2386 zbx_socket_timeout_set(s, timeout);
2387
2388 if (ZBX_PROTO_ERROR == zbx_sendto(s->socket, data, data_len, 0, NULL, 0))
2389 {
2390 zbx_set_socket_strerror("sendto() failed: %s", strerror_from_system(zbx_socket_last_error()));
2391 ret = FAIL;
2392 }
2393
2394 if (0 != timeout)
2395 zbx_socket_timeout_cleanup(s);
2396
2397 return ret;
2398 }
2399
2400 int zbx_udp_recv(zbx_socket_t *s, int timeout)
2401 {
2402 char buffer[65508]; /* maximum payload for UDP over IPv4 is 65507 bytes */
2403 ssize_t read_bytes;
2404
2405 zbx_socket_free(s);
2406
2407 if (0 != timeout)
2408 zbx_socket_timeout_set(s, timeout);
2409
2410 if (ZBX_PROTO_ERROR == (read_bytes = recvfrom(s->socket, buffer, sizeof(buffer) - 1, 0, NULL, NULL)))
2411 zbx_set_socket_strerror("recvfrom() failed: %s", strerror_from_system(zbx_socket_last_error()));
2412
2413 if (0 != timeout)
2414 zbx_socket_timeout_cleanup(s);
2415
2416 if (ZBX_PROTO_ERROR == read_bytes)
2417 return FAIL;
2418
2419 if (sizeof(s->buf_stat) > (size_t)read_bytes)
2420 {
2421 s->buf_type = ZBX_BUF_TYPE_STAT;
2422 s->buffer = s->buf_stat;
2423 }
2424 else
2425 {
2426 s->buf_type = ZBX_BUF_TYPE_DYN;
2427 s->buffer = (char *)zbx_malloc(s->buffer, read_bytes + 1);
2428 }
2429
2430 buffer[read_bytes] = '\0';
2431 memcpy(s->buffer, buffer, read_bytes + 1);
2432
2433 s->read_bytes = (size_t)read_bytes;
2434
2435 return SUCCEED;
2436 }
2437
2438 void zbx_udp_close(zbx_socket_t *s)
2439 {
2440 zbx_socket_timeout_cleanup(s);
2441
2442 zbx_socket_free(s);
2443 zbx_socket_close(s->socket);
2444 }
2445