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 "db.h"
22 #include "dbcache.h"
23 #include "log.h"
24 #include "zbxserver.h"
25 #include "zbxregexp.h"
26
27 #include "active.h"
28 #include "../../libs/zbxcrypto/tls_tcp_active.h"
29
30 extern unsigned char program_type;
31
32 /******************************************************************************
33 * *
34 * Function: get_hostid_by_host *
35 * *
36 * Purpose: check for host name and return hostid *
37 * *
38 * Parameters: host - [IN] require size 'HOST_HOST_LEN_MAX' *
39 * *
40 * Return value: SUCCEED - host is found *
41 * FAIL - an error occurred or host not found *
42 * *
43 * Author: Alexander Vladishev *
44 * *
45 * Comments: NB! adds host to the database if it does not exist *
46 * *
47 ******************************************************************************/
get_hostid_by_host(const zbx_socket_t * sock,const char * host,const char * ip,unsigned short port,const char * host_metadata,zbx_uint64_t * hostid,char * error)48 static int get_hostid_by_host(const zbx_socket_t *sock, const char *host, const char *ip, unsigned short port,
49 const char *host_metadata, zbx_uint64_t *hostid, char *error)
50 {
51 const char *__function_name = "get_hostid_by_host";
52
53 char *host_esc, dns[INTERFACE_DNS_LEN_MAX], *ch_error;
54 DB_RESULT result;
55 DB_ROW row;
56 int ret = FAIL;
57
58 zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'%s'", __function_name, host);
59
60 if (FAIL == zbx_check_hostname(host, &ch_error))
61 {
62 zbx_snprintf(error, MAX_STRING_LEN, "invalid host name [%s]: %s", host, ch_error);
63 zbx_free(ch_error);
64 goto out;
65 }
66
67 host_esc = DBdyn_escape_string(host);
68
69 result =
70 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
71 DBselect(
72 "select hostid,status,tls_accept,tls_issuer,tls_subject,tls_psk_identity"
73 " from hosts"
74 " where host='%s'"
75 " and status in (%d,%d)"
76 " and flags<>%d"
77 " and proxy_hostid is null",
78 host_esc, HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, ZBX_FLAG_DISCOVERY_PROTOTYPE);
79 #else
80 DBselect(
81 "select hostid,status,tls_accept"
82 " from hosts"
83 " where host='%s'"
84 " and status in (%d,%d)"
85 " and flags<>%d"
86 " and proxy_hostid is null",
87 host_esc, HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, ZBX_FLAG_DISCOVERY_PROTOTYPE);
88 #endif
89 if (NULL != (row = DBfetch(result)))
90 {
91 if (HOST_STATUS_MONITORED == atoi(row[1]))
92 {
93 unsigned int tls_accept;
94
95 tls_accept = (unsigned int)atoi(row[2]);
96
97 if (0 == (tls_accept & sock->connection_type))
98 {
99 zbx_snprintf(error, MAX_STRING_LEN, "connection of type \"%s\" is not allowed for host"
100 " \"%s\"", zbx_tcp_connection_type_name(sock->connection_type), host);
101 goto done;
102 }
103
104 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
105 if (ZBX_TCP_SEC_TLS_CERT == sock->connection_type)
106 {
107 zbx_tls_conn_attr_t attr;
108
109 if (SUCCEED != zbx_tls_get_attr_cert(sock, &attr))
110 {
111 THIS_SHOULD_NEVER_HAPPEN;
112
113 zbx_snprintf(error, MAX_STRING_LEN, "cannot get connection attributes for host"
114 " \"%s\"", host);
115 goto done;
116 }
117
118 /* simplified match, not compliant with RFC 4517, 4518 */
119 if ('\0' != *row[3] && 0 != strcmp(row[3], attr.issuer))
120 {
121 zbx_snprintf(error, MAX_STRING_LEN, "certificate issuer does not match for"
122 " host \"%s\"", host);
123 goto done;
124 }
125
126 /* simplified match, not compliant with RFC 4517, 4518 */
127 if ('\0' != *row[4] && 0 != strcmp(row[4], attr.subject))
128 {
129 zbx_snprintf(error, MAX_STRING_LEN, "certificate subject does not match for"
130 " host \"%s\"", host);
131 goto done;
132 }
133 }
134 #endif
135 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || (defined(HAVE_OPENSSL) && defined(HAVE_OPENSSL_WITH_PSK))
136 else if (ZBX_TCP_SEC_TLS_PSK == sock->connection_type)
137 {
138 zbx_tls_conn_attr_t attr;
139
140 if (SUCCEED != zbx_tls_get_attr_psk(sock, &attr))
141 {
142 THIS_SHOULD_NEVER_HAPPEN;
143
144 zbx_snprintf(error, MAX_STRING_LEN, "cannot get connection attributes for host"
145 " \"%s\"", host);
146 goto done;
147 }
148
149 if (strlen(row[5]) != attr.psk_identity_len ||
150 0 != memcmp(row[5], attr.psk_identity, attr.psk_identity_len))
151 {
152 zbx_snprintf(error, MAX_STRING_LEN, "false PSK identity for host \"%s\"", host);
153 goto done;
154 }
155 }
156 #endif
157 ZBX_STR2UINT64(*hostid, row[0]);
158
159 ret = SUCCEED;
160 }
161 else
162 zbx_snprintf(error, MAX_STRING_LEN, "host [%s] not monitored", host);
163 }
164 else
165 {
166 zbx_snprintf(error, MAX_STRING_LEN, "host [%s] not found", host);
167
168 /* remove ::ffff: prefix from IPv4-mapped IPv6 addresses */
169 if (0 == strncmp("::ffff:", ip, 7) && SUCCEED == is_ip4(ip + 7))
170 ip += 7;
171
172 zbx_alarm_on(CONFIG_TIMEOUT);
173 zbx_gethost_by_ip(ip, dns, sizeof(dns));
174 zbx_alarm_off();
175
176 DBbegin();
177
178 if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER))
179 DBregister_host(0, host, ip, dns, port, host_metadata, (int)time(NULL));
180 else if (0 != (program_type & ZBX_PROGRAM_TYPE_PROXY))
181 DBproxy_register_host(host, ip, dns, port, host_metadata);
182
183 DBcommit();
184 }
185 done:
186 DBfree_result(result);
187
188 zbx_free(host_esc);
189 out:
190 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
191
192 return ret;
193 }
194
get_list_of_active_checks(zbx_uint64_t hostid,zbx_vector_uint64_t * itemids)195 static void get_list_of_active_checks(zbx_uint64_t hostid, zbx_vector_uint64_t *itemids)
196 {
197 DB_RESULT result;
198 DB_ROW row;
199 zbx_uint64_t itemid;
200
201 result = DBselect(
202 "select itemid"
203 " from items"
204 " where type=%d"
205 " and flags<>%d"
206 " and hostid=" ZBX_FS_UI64,
207 ITEM_TYPE_ZABBIX_ACTIVE, ZBX_FLAG_DISCOVERY_PROTOTYPE, hostid);
208
209 while (NULL != (row = DBfetch(result)))
210 {
211 ZBX_STR2UINT64(itemid, row[0]);
212 zbx_vector_uint64_append(itemids, itemid);
213 }
214 DBfree_result(result);
215 }
216
217 /******************************************************************************
218 * *
219 * Function: send_list_of_active_checks *
220 * *
221 * Purpose: send list of active checks to the host (older version agent) *
222 * *
223 * Parameters: sock - open socket of server-agent connection *
224 * request - request buffer *
225 * *
226 * Return value: SUCCEED - list of active checks sent successfully *
227 * FAIL - an error occurred *
228 * *
229 * Comments: format of the request: ZBX_GET_ACTIVE_CHECKS\n<host name>\n *
230 * format of the list: key:delay:last_log_size *
231 * *
232 ******************************************************************************/
send_list_of_active_checks(zbx_socket_t * sock,char * request)233 int send_list_of_active_checks(zbx_socket_t *sock, char *request)
234 {
235 const char *__function_name = "send_list_of_active_checks";
236
237 char *host = NULL, *p, *buffer = NULL, error[MAX_STRING_LEN];
238 size_t buffer_alloc = 8 * ZBX_KIBIBYTE, buffer_offset = 0;
239 int ret = FAIL, i;
240 zbx_uint64_t hostid;
241 zbx_vector_uint64_t itemids;
242
243 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
244
245 if (NULL != (host = strchr(request, '\n')))
246 {
247 host++;
248 if (NULL != (p = strchr(host, '\n')))
249 *p = '\0';
250 }
251 else
252 {
253 zbx_snprintf(error, sizeof(error), "host is null");
254 goto out;
255 }
256
257 /* no host metadata in older versions of agent */
258 if (FAIL == get_hostid_by_host(sock, host, sock->peer, ZBX_DEFAULT_AGENT_PORT, "", &hostid, error))
259 goto out;
260
261 zbx_vector_uint64_create(&itemids);
262
263 get_list_of_active_checks(hostid, &itemids);
264
265 buffer = zbx_malloc(buffer, buffer_alloc);
266
267 if (0 != itemids.values_num)
268 {
269 DC_ITEM *dc_items;
270 int *errcodes, now;
271 zbx_config_t cfg;
272
273 dc_items = zbx_malloc(NULL, sizeof(DC_ITEM) * itemids.values_num);
274 errcodes = zbx_malloc(NULL, sizeof(int) * itemids.values_num);
275
276 DCconfig_get_items_by_itemids(dc_items, itemids.values, errcodes, itemids.values_num);
277 zbx_config_get(&cfg, ZBX_CONFIG_FLAGS_REFRESH_UNSUPPORTED);
278
279 now = time(NULL);
280
281 for (i = 0; i < itemids.values_num; i++)
282 {
283 if (SUCCEED != errcodes[i])
284 {
285 zabbix_log(LOG_LEVEL_DEBUG, "%s() Item [" ZBX_FS_UI64 "] was not found in the"
286 " server cache. Not sending now.", __function_name, itemids.values[i]);
287 continue;
288 }
289
290 if (ITEM_STATUS_ACTIVE != dc_items[i].status)
291 continue;
292
293 if (HOST_STATUS_MONITORED != dc_items[i].host.status)
294 continue;
295
296 if (ITEM_STATE_NOTSUPPORTED == dc_items[i].state)
297 {
298 if (0 == cfg.refresh_unsupported)
299 continue;
300
301 if (dc_items[i].lastclock + cfg.refresh_unsupported > now)
302 continue;
303 }
304
305 zbx_snprintf_alloc(&buffer, &buffer_alloc, &buffer_offset, "%s:%d:" ZBX_FS_UI64 "\n",
306 dc_items[i].key_orig, dc_items[i].delay, dc_items[i].lastlogsize);
307 }
308
309 zbx_config_clean(&cfg);
310
311 DCconfig_clean_items(dc_items, errcodes, itemids.values_num);
312
313 zbx_free(errcodes);
314 zbx_free(dc_items);
315 }
316
317 zbx_vector_uint64_destroy(&itemids);
318
319 zbx_strcpy_alloc(&buffer, &buffer_alloc, &buffer_offset, "ZBX_EOF\n");
320
321 zabbix_log(LOG_LEVEL_DEBUG, "%s() sending [%s]", __function_name, buffer);
322
323 zbx_alarm_on(CONFIG_TIMEOUT);
324 if (SUCCEED != zbx_tcp_send_raw(sock, buffer))
325 zbx_strlcpy(error, zbx_socket_strerror(), MAX_STRING_LEN);
326 else
327 ret = SUCCEED;
328 zbx_alarm_off();
329
330 zbx_free(buffer);
331 out:
332 if (FAIL == ret)
333 zabbix_log(LOG_LEVEL_WARNING, "cannot send list of active checks to \"%s\": %s", sock->peer, error);
334
335 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
336
337 return ret;
338 }
339
340 /******************************************************************************
341 * *
342 * Function: zbx_vector_str_append_uniq *
343 * *
344 * Purpose: append non duplicate string to the string vector *
345 * *
346 * Parameters: vector - [IN/OUT] the string vector *
347 * str - [IN] the string to append *
348 * *
349 ******************************************************************************/
zbx_vector_str_append_uniq(zbx_vector_str_t * vector,const char * str)350 static void zbx_vector_str_append_uniq(zbx_vector_str_t *vector, const char *str)
351 {
352 if (FAIL == zbx_vector_str_search(vector, str, ZBX_DEFAULT_STR_COMPARE_FUNC))
353 zbx_vector_str_append(vector, zbx_strdup(NULL, str));
354 }
355
356 /******************************************************************************
357 * *
358 * Function: zbx_itemkey_extract_global_regexps *
359 * *
360 * Purpose: extract global regular expression names from item key *
361 * *
362 * Parameters: key - [IN] the item key to parse *
363 * regexps - [OUT] the extracted regular expression names *
364 * *
365 ******************************************************************************/
zbx_itemkey_extract_global_regexps(const char * key,zbx_vector_str_t * regexps)366 static void zbx_itemkey_extract_global_regexps(const char *key, zbx_vector_str_t *regexps)
367 {
368 #define ZBX_KEY_LOG 1
369 #define ZBX_KEY_EVENTLOG 2
370
371 AGENT_REQUEST request;
372 int item_key;
373 const char *param;
374
375 if (0 == strncmp(key, "log[", 4) || 0 == strncmp(key, "logrt[", 6))
376 item_key = ZBX_KEY_LOG;
377 else if (0 == strncmp(key, "eventlog[", 9))
378 item_key = ZBX_KEY_EVENTLOG;
379 else
380 return;
381
382 init_request(&request);
383
384 if(SUCCEED != parse_item_key(key, &request))
385 goto out;
386
387 /* "params" parameter */
388 if (NULL != (param = get_rparam(&request, 1)) && '@' == *param)
389 zbx_vector_str_append_uniq(regexps, param + 1);
390
391 if (ZBX_KEY_EVENTLOG == item_key)
392 {
393 /* "severity" parameter */
394 if (NULL != (param = get_rparam(&request, 2)) && '@' == *param)
395 zbx_vector_str_append_uniq(regexps, param + 1);
396
397 /* "source" parameter */
398 if (NULL != (param = get_rparam(&request, 3)) && '@' == *param)
399 zbx_vector_str_append_uniq(regexps, param + 1);
400
401 /* "logeventid" parameter */
402 if (NULL != (param = get_rparam(&request, 4)) && '@' == *param)
403 zbx_vector_str_append_uniq(regexps, param + 1);
404 }
405 out:
406 free_request(&request);
407 }
408
409 /******************************************************************************
410 * *
411 * Function: send_list_of_active_checks_json *
412 * *
413 * Purpose: send list of active checks to the host *
414 * *
415 * Parameters: sock - open socket of server-agent connection *
416 * json - request buffer *
417 * *
418 * Return value: SUCCEED - list of active checks sent successfully *
419 * FAIL - an error occurred *
420 * *
421 * Author: Alexander Vladishev *
422 * *
423 * Comments: *
424 * *
425 ******************************************************************************/
send_list_of_active_checks_json(zbx_socket_t * sock,struct zbx_json_parse * jp)426 int send_list_of_active_checks_json(zbx_socket_t *sock, struct zbx_json_parse *jp)
427 {
428 const char *__function_name = "send_list_of_active_checks_json";
429
430 char host[HOST_HOST_LEN_MAX], tmp[MAX_STRING_LEN], ip[INTERFACE_IP_LEN_MAX],
431 error[MAX_STRING_LEN], *host_metadata = NULL;
432 struct zbx_json json;
433 int ret = FAIL, i;
434 zbx_uint64_t hostid;
435 size_t host_metadata_alloc = 1; /* for at least NUL-termination char */
436 unsigned short port;
437 zbx_vector_uint64_t itemids;
438
439 zbx_vector_ptr_t regexps;
440 zbx_vector_str_t names;
441
442 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
443
444 zbx_vector_ptr_create(®exps);
445 zbx_vector_str_create(&names);
446
447 if (FAIL == zbx_json_value_by_name(jp, ZBX_PROTO_TAG_HOST, host, sizeof(host)))
448 {
449 zbx_snprintf(error, MAX_STRING_LEN, "%s", zbx_json_strerror());
450 goto error;
451 }
452
453 host_metadata = zbx_malloc(host_metadata, host_metadata_alloc);
454
455 if (FAIL == zbx_json_value_by_name_dyn(jp, ZBX_PROTO_TAG_HOST_METADATA,
456 &host_metadata, &host_metadata_alloc))
457 {
458 *host_metadata = '\0';
459 }
460
461 if (FAIL == zbx_json_value_by_name(jp, ZBX_PROTO_TAG_IP, ip, sizeof(ip)))
462 strscpy(ip, sock->peer);
463
464 if (FAIL == is_ip(ip)) /* check even if 'ip' came from get_ip_by_socket() - it can return not a valid IP */
465 {
466 zbx_snprintf(error, MAX_STRING_LEN, "\"%s\" is not a valid IP address", ip);
467 goto error;
468 }
469
470 if (FAIL == zbx_json_value_by_name(jp, ZBX_PROTO_TAG_PORT, tmp, sizeof(tmp)))
471 {
472 port = ZBX_DEFAULT_AGENT_PORT;
473 }
474 else if (FAIL == is_ushort(tmp, &port))
475 {
476 zbx_snprintf(error, MAX_STRING_LEN, "\"%s\" is not a valid port", tmp);
477 goto error;
478 }
479
480 if (FAIL == get_hostid_by_host(sock, host, ip, port, host_metadata, &hostid, error))
481 goto error;
482
483 zbx_vector_uint64_create(&itemids);
484
485 get_list_of_active_checks(hostid, &itemids);
486
487 zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
488 zbx_json_addstring(&json, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_SUCCESS, ZBX_JSON_TYPE_STRING);
489 zbx_json_addarray(&json, ZBX_PROTO_TAG_DATA);
490
491 if (0 != itemids.values_num)
492 {
493 DC_ITEM *dc_items;
494 int *errcodes, now;
495 zbx_config_t cfg;
496
497 dc_items = zbx_malloc(NULL, sizeof(DC_ITEM) * itemids.values_num);
498 errcodes = zbx_malloc(NULL, sizeof(int) * itemids.values_num);
499
500 DCconfig_get_items_by_itemids(dc_items, itemids.values, errcodes, itemids.values_num);
501 zbx_config_get(&cfg, ZBX_CONFIG_FLAGS_REFRESH_UNSUPPORTED);
502
503 now = time(NULL);
504
505 for (i = 0; i < itemids.values_num; i++)
506 {
507 if (SUCCEED != errcodes[i])
508 {
509 zabbix_log(LOG_LEVEL_DEBUG, "%s() Item [" ZBX_FS_UI64 "] was not found in the"
510 " server cache. Not sending now.", __function_name, itemids.values[i]);
511 continue;
512 }
513
514 if (ITEM_STATUS_ACTIVE != dc_items[i].status)
515 continue;
516
517 if (HOST_STATUS_MONITORED != dc_items[i].host.status)
518 continue;
519
520 if (ITEM_STATE_NOTSUPPORTED == dc_items[i].state)
521 {
522 if (0 == cfg.refresh_unsupported)
523 continue;
524
525 if (dc_items[i].lastclock + cfg.refresh_unsupported > now)
526 continue;
527 }
528
529 dc_items[i].key = zbx_strdup(dc_items[i].key, dc_items[i].key_orig);
530 substitute_key_macros(&dc_items[i].key, NULL, &dc_items[i], NULL, MACRO_TYPE_ITEM_KEY, NULL, 0);
531
532 zbx_json_addobject(&json, NULL);
533 zbx_json_addstring(&json, ZBX_PROTO_TAG_KEY, dc_items[i].key, ZBX_JSON_TYPE_STRING);
534 if (0 != strcmp(dc_items[i].key, dc_items[i].key_orig))
535 {
536 zbx_json_addstring(&json, ZBX_PROTO_TAG_KEY_ORIG,
537 dc_items[i].key_orig, ZBX_JSON_TYPE_STRING);
538 }
539 zbx_json_adduint64(&json, ZBX_PROTO_TAG_DELAY, dc_items[i].delay);
540 /* The agent expects ALWAYS to have lastlogsize and mtime tags. */
541 /* Removing those would cause older agents to fail. */
542 zbx_json_adduint64(&json, ZBX_PROTO_TAG_LASTLOGSIZE, dc_items[i].lastlogsize);
543 zbx_json_adduint64(&json, ZBX_PROTO_TAG_MTIME, dc_items[i].mtime);
544 zbx_json_close(&json);
545
546 zbx_itemkey_extract_global_regexps(dc_items[i].key, &names);
547
548 zbx_free(dc_items[i].key);
549 }
550
551 zbx_config_clean(&cfg);
552
553 DCconfig_clean_items(dc_items, errcodes, itemids.values_num);
554
555 zbx_free(errcodes);
556 zbx_free(dc_items);
557 }
558
559 zbx_vector_uint64_destroy(&itemids);
560
561 zbx_json_close(&json);
562
563 DCget_expressions_by_names(®exps, (const char * const *)names.values, names.values_num);
564
565 if (0 < regexps.values_num)
566 {
567 char buffer[32];
568
569 zbx_json_addarray(&json, ZBX_PROTO_TAG_REGEXP);
570
571 for (i = 0; i < regexps.values_num; i++)
572 {
573 zbx_expression_t *regexp = regexps.values[i];
574
575 zbx_json_addobject(&json, NULL);
576 zbx_json_addstring(&json, "name", regexp->name, ZBX_JSON_TYPE_STRING);
577 zbx_json_addstring(&json, "expression", regexp->expression, ZBX_JSON_TYPE_STRING);
578
579 zbx_snprintf(buffer, sizeof(buffer), "%d", regexp->expression_type);
580 zbx_json_addstring(&json, "expression_type", buffer, ZBX_JSON_TYPE_INT);
581
582 zbx_snprintf(buffer, sizeof(buffer), "%c", regexp->exp_delimiter);
583 zbx_json_addstring(&json, "exp_delimiter", buffer, ZBX_JSON_TYPE_STRING);
584
585 zbx_snprintf(buffer, sizeof(buffer), "%d", regexp->case_sensitive);
586 zbx_json_addstring(&json, "case_sensitive", buffer, ZBX_JSON_TYPE_INT);
587
588 zbx_json_close(&json);
589 }
590
591 zbx_json_close(&json);
592 }
593
594 zabbix_log(LOG_LEVEL_DEBUG, "%s() sending [%s]", __function_name, json.buffer);
595
596 zbx_alarm_on(CONFIG_TIMEOUT);
597 if (SUCCEED != zbx_tcp_send(sock, json.buffer))
598 strscpy(error, zbx_socket_strerror());
599 else
600 ret = SUCCEED;
601 zbx_alarm_off();
602
603 zbx_json_free(&json);
604
605 goto out;
606 error:
607 zabbix_log(LOG_LEVEL_WARNING, "cannot send list of active checks to \"%s\": %s", sock->peer, error);
608
609 zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
610 zbx_json_addstring(&json, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_FAILED, ZBX_JSON_TYPE_STRING);
611 zbx_json_addstring(&json, ZBX_PROTO_TAG_INFO, error, ZBX_JSON_TYPE_STRING);
612
613 zabbix_log(LOG_LEVEL_DEBUG, "%s() sending [%s]", __function_name, json.buffer);
614
615 ret = zbx_tcp_send(sock, json.buffer);
616
617 zbx_json_free(&json);
618 out:
619 for (i = 0; i < names.values_num; i++)
620 zbx_free(names.values[i]);
621
622 zbx_vector_str_destroy(&names);
623
624 zbx_regexp_clean_expressions(®exps);
625 zbx_vector_ptr_destroy(®exps);
626
627 zbx_free(host_metadata);
628
629 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
630
631 return ret;
632 }
633