1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21 #include "sysinfo.h"
22
23 #include "comms.h"
24 #include "log.h"
25 #include "cfg.h"
26
27 #include "net.h"
28 #include "zbxalgo.h"
29
30 #ifdef _WINDOWS
31 # include <windns.h>
32 # pragma comment(lib, "Dnsapi.lib") /* add the library for DnsQuery function */
33 #endif
34
tcp_expect(const char * host,unsigned short port,int timeout,const char * request,int (* validate_func)(const char *),const char * sendtoclose,int * value_int)35 int tcp_expect(const char *host, unsigned short port, int timeout, const char *request,
36 int (*validate_func)(const char *), const char *sendtoclose, int *value_int)
37 {
38 zbx_socket_t s;
39 const char *buf;
40 int net, val = ZBX_TCP_EXPECT_OK;
41
42 *value_int = 0;
43
44 if (SUCCEED != (net = zbx_tcp_connect(&s, CONFIG_SOURCE_IP, host, port, timeout, ZBX_TCP_SEC_UNENCRYPTED, NULL,
45 NULL)))
46 {
47 goto out;
48 }
49
50 if (NULL != request)
51 net = zbx_tcp_send_raw(&s, request);
52
53 if (NULL != validate_func && SUCCEED == net)
54 {
55 val = ZBX_TCP_EXPECT_FAIL;
56
57 while (NULL != (buf = zbx_tcp_recv_line(&s)))
58 {
59 val = validate_func(buf);
60
61 if (ZBX_TCP_EXPECT_OK == val)
62 break;
63
64 if (ZBX_TCP_EXPECT_FAIL == val)
65 {
66 zabbix_log(LOG_LEVEL_DEBUG, "TCP expect content error, received [%s]", buf);
67 break;
68 }
69 }
70 }
71
72 if (NULL != sendtoclose && SUCCEED == net && ZBX_TCP_EXPECT_OK == val)
73 (void)zbx_tcp_send_raw(&s, sendtoclose);
74
75 if (SUCCEED == net && ZBX_TCP_EXPECT_OK == val)
76 *value_int = 1;
77
78 zbx_tcp_close(&s);
79 out:
80 if (SUCCEED != net)
81 zabbix_log(LOG_LEVEL_DEBUG, "TCP expect network error: %s", zbx_socket_strerror());
82
83 return SYSINFO_RET_OK;
84 }
85
NET_TCP_PORT(AGENT_REQUEST * request,AGENT_RESULT * result)86 int NET_TCP_PORT(AGENT_REQUEST *request, AGENT_RESULT *result)
87 {
88 unsigned short port;
89 int value_int, ret;
90 char *ip_str, ip[MAX_ZBX_DNSNAME_LEN + 1], *port_str;
91
92 if (2 < request->nparam)
93 {
94 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
95 return SYSINFO_RET_FAIL;
96 }
97
98 ip_str = get_rparam(request, 0);
99 port_str = get_rparam(request, 1);
100
101 if (NULL == ip_str || '\0' == *ip_str)
102 strscpy(ip, "127.0.0.1");
103 else
104 strscpy(ip, ip_str);
105
106 if (NULL == port_str || SUCCEED != is_ushort(port_str, &port))
107 {
108 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
109 return SYSINFO_RET_FAIL;
110 }
111
112 if (SYSINFO_RET_OK == (ret = tcp_expect(ip, port, CONFIG_TIMEOUT, NULL, NULL, NULL, &value_int)))
113 SET_UI64_RESULT(result, value_int);
114
115 return ret;
116 }
117
118 #if defined(HAVE_RES_QUERY) || defined(_WINDOWS)
119
decode_type(int q_type)120 static const char *decode_type(int q_type)
121 {
122 ZBX_THREAD_LOCAL static char buf[16];
123
124 switch (q_type)
125 {
126 case T_A:
127 return "A"; /* address */
128 case T_AAAA:
129 return "AAAA"; /* v6 address */
130 case T_NS:
131 return "NS"; /* name server */
132 case T_MD:
133 return "MD"; /* mail destination */ /* obsolete */
134 case T_MF:
135 return "MF"; /* mail forwarder */ /* obsolete */
136 case T_CNAME:
137 return "CNAME"; /* canonical name */
138 case T_SOA:
139 return "SOA"; /* start of authority */
140 case T_MB:
141 return "MB"; /* mailbox */ /* experimental */
142 case T_MG:
143 return "MG"; /* mail group member */ /* experimental */
144 case T_MR:
145 return "MR"; /* mail rename */ /* experimental */
146 case T_NULL:
147 return "NULL"; /* null */ /* obsolete */
148 case T_WKS:
149 return "WKS"; /* well-known service */ /* obsolete */
150 case T_PTR:
151 return "PTR"; /* domain name pointer */
152 case T_HINFO:
153 return "HINFO"; /* host information */
154 case T_MINFO:
155 return "MINFO"; /* mailbox information */ /* experimental */
156 case T_MX:
157 return "MX"; /* mail exchanger */
158 case T_TXT:
159 return "TXT"; /* text */
160 case T_SRV:
161 return "SRV"; /* service locator */
162 default:
163 zbx_snprintf(buf, sizeof(buf), "T_%d", q_type);
164 return buf;
165 }
166 }
167
168 #if !defined(_WINDOWS)
get_name(unsigned char * msg,unsigned char * msg_end,unsigned char ** msg_ptr)169 static char *get_name(unsigned char *msg, unsigned char *msg_end, unsigned char **msg_ptr)
170 {
171 int res;
172 static char buffer[MAX_STRING_LEN];
173
174 if (-1 == (res = dn_expand(msg, msg_end, *msg_ptr, buffer, sizeof(buffer))))
175 return NULL;
176
177 *msg_ptr += res;
178
179 return buffer;
180 }
181 #endif /* !defined(_WINDOWS) */
182
183 /* Replace zbx_inet_ntop with inet_ntop in case of drop Windows XP/W2k3 support */
184 #if defined(_WINDOWS)
zbx_inet_ntop(int af,const void * src,char * dst,size_t size)185 const char *zbx_inet_ntop(int af, const void *src, char *dst, size_t size)
186 {
187 struct sockaddr_storage ss;
188 unsigned long s = size;
189
190 memset(&ss, '\0', sizeof(ss));
191 ss.ss_family = af;
192
193 switch(af)
194 {
195 case AF_INET:
196 ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
197 break;
198 case AF_INET6:
199 ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src;
200 break;
201 default:
202 return NULL;
203 }
204
205 return (0 == WSAAddressToStringA((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s))? dst : NULL;
206 }
207 #endif
208 #endif /* defined(HAVE_RES_QUERY) || defined(_WINDOWS) */
209
dns_query(AGENT_REQUEST * request,AGENT_RESULT * result,int short_answer)210 static int dns_query(AGENT_REQUEST *request, AGENT_RESULT *result, int short_answer)
211 {
212 #if defined(HAVE_RES_QUERY) || defined(_WINDOWS)
213
214 size_t offset = 0;
215 int res, type, retrans, retry, use_tcp, i, ret = SYSINFO_RET_FAIL, ip_type = AF_INET;
216 char *ip, zone[MAX_STRING_LEN], buffer[MAX_STRING_LEN], *zone_str, *param,
217 tmp[MAX_STRING_LEN];
218 struct in_addr inaddr;
219 struct in6_addr in6addr;
220 #ifndef _WINDOWS
221 #if defined(HAVE_RES_NINIT) && !defined(_AIX)
222 /* It seems that on some AIX systems with no updates installed res_ninit() can */
223 /* corrupt stack (see ZBX-14559). Use res_init() on AIX. */
224 struct __res_state res_state_local;
225 #else /* thread-unsafe resolver API */
226 int saved_retrans, saved_retry, saved_nscount = 0;
227 unsigned long saved_options;
228 struct sockaddr_in saved_ns;
229 # if defined(HAVE_RES_U_EXT) /* thread-unsafe resolver API /Linux/ */
230 int save_nssocks, saved_nscount6;
231 # endif
232 #endif
233
234 #if defined(HAVE_RES_EXT_EXT) /* AIX */
235 union res_sockaddr_union saved_ns6;
236 #elif defined(HAVE_RES_U_EXT_EXT) /* BSD */
237 struct sockaddr_in6 saved_ns6;
238 #else
239 struct sockaddr_in6 *saved_ns6;
240 #endif
241 struct sockaddr_in6 sockaddrin6;
242 struct addrinfo hint, *hres = NULL;
243 #endif
244 typedef struct
245 {
246 const char *name;
247 int type;
248 }
249 resolv_querytype_t;
250
251 static const resolv_querytype_t qt[] =
252 {
253 {"ANY", T_ANY},
254 {"A", T_A},
255 {"AAAA", T_AAAA},
256 {"NS", T_NS},
257 {"MD", T_MD},
258 {"MF", T_MF},
259 {"CNAME", T_CNAME},
260 {"SOA", T_SOA},
261 {"MB", T_MB},
262 {"MG", T_MG},
263 {"MR", T_MR},
264 {"NULL", T_NULL},
265 #ifndef _WINDOWS
266 {"WKS", T_WKS},
267 #endif
268 {"PTR", T_PTR},
269 {"HINFO", T_HINFO},
270 {"MINFO", T_MINFO},
271 {"MX", T_MX},
272 {"TXT", T_TXT},
273 {"SRV", T_SRV},
274 {NULL}
275 };
276
277 #ifdef _WINDOWS
278 PDNS_RECORD pQueryResults, pDnsRecord;
279 wchar_t *wzone;
280 char tmp2[MAX_STRING_LEN];
281 DWORD options;
282 #else
283 char *name;
284 unsigned char *msg_end, *msg_ptr, *p;
285 int num_answers, num_query, q_type, q_class, q_len, value, c, n;
286 struct servent *s;
287 HEADER *hp;
288 struct protoent *pr;
289 #if PACKETSZ > 1024
290 unsigned char buf[PACKETSZ];
291 #else
292 unsigned char buf[1024];
293 #endif
294
295 typedef union
296 {
297 HEADER h;
298 #if defined(NS_PACKETSZ)
299 unsigned char buffer[NS_PACKETSZ];
300 #elif defined(PACKETSZ)
301 unsigned char buffer[PACKETSZ];
302 #else
303 unsigned char buffer[512];
304 #endif
305 }
306 answer_t;
307
308 answer_t answer;
309 #endif /* _WINDOWS */
310 zbx_vector_str_t answers;
311
312 *buffer = '\0';
313
314 if (6 < request->nparam)
315 {
316 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
317 return SYSINFO_RET_FAIL;
318 }
319
320 ip = get_rparam(request, 0);
321 zone_str = get_rparam(request, 1);
322
323 #ifndef _WINDOWS
324 memset(&hint, '\0', sizeof(hint));
325 hint.ai_family = PF_UNSPEC;
326 hint.ai_flags = AI_NUMERICHOST;
327
328 if (NULL != ip && '\0' != *ip && 0 == getaddrinfo(ip, NULL, &hint, &hres) && AF_INET6 == hres->ai_family)
329 ip_type = hres->ai_family;
330
331 if (NULL != hres)
332 freeaddrinfo(hres);
333 #endif
334 if (NULL == zone_str || '\0' == *zone_str)
335 strscpy(zone, "zabbix.com");
336 else
337 strscpy(zone, zone_str);
338
339 param = get_rparam(request, 2);
340
341 if (NULL == param || '\0' == *param)
342 type = T_SOA;
343 else
344 {
345 for (i = 0; NULL != qt[i].name; i++)
346 {
347 if (0 == strcasecmp(qt[i].name, param))
348 {
349 type = qt[i].type;
350 break;
351 }
352 }
353
354 if (NULL == qt[i].name)
355 {
356 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
357 return SYSINFO_RET_FAIL;
358 }
359 }
360
361 param = get_rparam(request, 3);
362
363 if (NULL == param || '\0' == *param)
364 retrans = 1;
365 else if (SUCCEED != is_uint31(param, &retrans) || 0 == retrans)
366 {
367 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid fourth parameter."));
368 return SYSINFO_RET_FAIL;
369 }
370
371 param = get_rparam(request, 4);
372
373 if (NULL == param || '\0' == *param)
374 retry = 2;
375 else if (SUCCEED != is_uint31(param, &retry) || 0 == retry)
376 {
377 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid fifth parameter."));
378 return SYSINFO_RET_FAIL;
379 }
380
381 param = get_rparam(request, 5);
382
383 if (NULL == param || '\0' == *param || 0 == strcmp(param, "udp"))
384 use_tcp = 0;
385 else if (0 == strcmp(param, "tcp"))
386 use_tcp = 1;
387 else
388 {
389 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid sixth parameter."));
390 return SYSINFO_RET_FAIL;
391 }
392
393 #ifdef _WINDOWS
394 options = DNS_QUERY_STANDARD | DNS_QUERY_BYPASS_CACHE;
395 if (0 != use_tcp)
396 options |= DNS_QUERY_USE_TCP_ONLY;
397
398 wzone = zbx_utf8_to_unicode(zone);
399 res = DnsQuery(wzone, type, options, NULL, &pQueryResults, NULL);
400 zbx_free(wzone);
401
402 if (1 == short_answer)
403 {
404 SET_UI64_RESULT(result, DNS_RCODE_NOERROR != res ? 0 : 1);
405 ret = SYSINFO_RET_OK;
406 goto clean_dns;
407 }
408
409 if (DNS_RCODE_NOERROR != res)
410 {
411 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot perform DNS query: [%d]", res));
412 return SYSINFO_RET_FAIL;
413 }
414
415 pDnsRecord = pQueryResults;
416 zbx_vector_str_create(&answers);
417
418 while (NULL != pDnsRecord)
419 {
420 if (DnsSectionAnswer != pDnsRecord->Flags.S.Section)
421 {
422 pDnsRecord = pDnsRecord->pNext;
423 continue;
424 }
425
426 if (NULL == pDnsRecord->pName)
427 goto clean;
428
429 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%-20s",
430 zbx_unicode_to_utf8_static(pDnsRecord->pName, tmp, sizeof(tmp)));
431 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %-8s",
432 decode_type(pDnsRecord->wType));
433
434 switch (pDnsRecord->wType)
435 {
436 case T_A:
437 inaddr.s_addr = pDnsRecord->Data.A.IpAddress;
438 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
439 inet_ntoa(inaddr));
440 break;
441 case T_AAAA:
442 memcpy(&in6addr.s6_addr, &(pDnsRecord->Data.AAAA.Ip6Address), sizeof(in6addr.s6_addr));
443 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
444 zbx_inet_ntop(AF_INET6, &in6addr, tmp, sizeof(tmp)));
445 break;
446 case T_NS:
447 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
448 zbx_unicode_to_utf8_static(pDnsRecord->Data.NS.pNameHost, tmp, sizeof(tmp)));
449 break;
450 case T_MD:
451 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
452 zbx_unicode_to_utf8_static(pDnsRecord->Data.MD.pNameHost, tmp, sizeof(tmp)));
453 break;
454 case T_MF:
455 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
456 zbx_unicode_to_utf8_static(pDnsRecord->Data.MF.pNameHost, tmp, sizeof(tmp)));
457 break;
458 case T_CNAME:
459 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
460 zbx_unicode_to_utf8_static(pDnsRecord->Data.CNAME.pNameHost, tmp, sizeof(tmp)));
461 break;
462 case T_SOA:
463 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s %s %lu %lu %lu %lu %lu",
464 zbx_unicode_to_utf8_static(pDnsRecord->Data.SOA.pNamePrimaryServer, tmp, sizeof(tmp)),
465 zbx_unicode_to_utf8_static(pDnsRecord->Data.SOA.pNameAdministrator, tmp2, sizeof(tmp2)),
466 pDnsRecord->Data.SOA.dwSerialNo,
467 pDnsRecord->Data.SOA.dwRefresh,
468 pDnsRecord->Data.SOA.dwRetry,
469 pDnsRecord->Data.SOA.dwExpire,
470 pDnsRecord->Data.SOA.dwDefaultTtl);
471 break;
472 case T_MB:
473 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
474 zbx_unicode_to_utf8_static(pDnsRecord->Data.MB.pNameHost, tmp, sizeof(tmp)));
475 break;
476 case T_MG:
477 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
478 zbx_unicode_to_utf8_static(pDnsRecord->Data.MG.pNameHost, tmp, sizeof(tmp)));
479 break;
480 case T_MR:
481 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
482 zbx_unicode_to_utf8_static(pDnsRecord->Data.MR.pNameHost, tmp, sizeof(tmp)));
483 break;
484 case T_NULL:
485 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " len:%lu",
486 pDnsRecord->Data.Null.dwByteCount);
487 break;
488 case T_PTR:
489 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
490 zbx_unicode_to_utf8_static(pDnsRecord->Data.PTR.pNameHost, tmp, sizeof(tmp)));
491 break;
492 case T_HINFO:
493 for (i = 0; i < (int)(pDnsRecord->Data.HINFO.dwStringCount); i++)
494 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"%s\"",
495 zbx_unicode_to_utf8_static(pDnsRecord->Data.HINFO.pStringArray[i], tmp, sizeof(tmp)));
496 break;
497 case T_MINFO:
498 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s %s",
499 zbx_unicode_to_utf8_static(pDnsRecord->Data.MINFO.pNameMailbox, tmp, sizeof(tmp)),
500 zbx_unicode_to_utf8_static(pDnsRecord->Data.MINFO.pNameErrorsMailbox, tmp2, sizeof(tmp2)));
501 break;
502 case T_MX:
503 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %hu %s",
504 pDnsRecord->Data.MX.wPreference,
505 zbx_unicode_to_utf8_static(pDnsRecord->Data.MX.pNameExchange, tmp, sizeof(tmp)));
506 break;
507 case T_TXT:
508 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"");
509
510 for (i = 0; i < (int)(pDnsRecord->Data.TXT.dwStringCount); i++)
511 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%s ",
512 zbx_unicode_to_utf8_static(pDnsRecord->Data.TXT.pStringArray[i], tmp, sizeof(tmp)));
513
514 if (0 < i)
515 offset -= 1; /* remove the trailing space */
516
517 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\"");
518
519 break;
520 case T_SRV:
521 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %hu %hu %hu %s",
522 pDnsRecord->Data.SRV.wPriority,
523 pDnsRecord->Data.SRV.wWeight,
524 pDnsRecord->Data.SRV.wPort,
525 zbx_unicode_to_utf8_static(pDnsRecord->Data.SRV.pNameTarget, tmp, sizeof(tmp)));
526 break;
527 default:
528 break;
529 }
530
531 zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\n");
532
533 pDnsRecord = pDnsRecord->pNext;
534 zbx_vector_str_append(&answers, zbx_strdup(NULL, buffer));
535 offset = 0;
536 *buffer = '\0';
537 }
538 #else /* not _WINDOWS */
539 #if defined(HAVE_RES_NINIT) && !defined(_AIX)
540 memset(&res_state_local, 0, sizeof(res_state_local));
541 if (-1 == res_ninit(&res_state_local)) /* initialize always, settings might have changed */
542 #else
543 if (-1 == res_init()) /* initialize always, settings might have changed */
544 #endif
545 {
546 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot initialize DNS subsystem: %s", zbx_strerror(errno)));
547 return SYSINFO_RET_FAIL;
548 }
549
550 #if defined(HAVE_RES_NINIT) && !defined(_AIX)
551 if (-1 == (res = res_nmkquery(&res_state_local, QUERY, zone, C_IN, type, NULL, 0, NULL, buf, sizeof(buf))))
552 #else
553 if (-1 == (res = res_mkquery(QUERY, zone, C_IN, type, NULL, 0, NULL, buf, sizeof(buf))))
554 #endif
555 {
556 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot create DNS query: %s", zbx_strerror(errno)));
557 return SYSINFO_RET_FAIL;
558 }
559
560 if (NULL != ip && '\0' != *ip && AF_INET == ip_type)
561 {
562 if (0 == inet_aton(ip, &inaddr))
563 {
564 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid IP address."));
565 return SYSINFO_RET_FAIL;
566 }
567
568 #if defined(HAVE_RES_NINIT) && !defined(_AIX)
569 res_state_local.nsaddr_list[0].sin_addr = inaddr;
570 res_state_local.nsaddr_list[0].sin_family = AF_INET;
571 res_state_local.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT);
572 res_state_local.nscount = 1;
573 #else /* thread-unsafe resolver API */
574 memcpy(&saved_ns, &(_res.nsaddr_list[0]), sizeof(struct sockaddr_in));
575 saved_nscount = _res.nscount;
576
577 _res.nsaddr_list[0].sin_addr = inaddr;
578 _res.nsaddr_list[0].sin_family = AF_INET;
579 _res.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT);
580 _res.nscount = 1;
581 #endif
582 }
583 else if (NULL != ip && '\0' != *ip && AF_INET6 == ip_type)
584 {
585 if (0 == inet_pton(ip_type, ip, &in6addr))
586 {
587 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid IPv6 address."));
588 return SYSINFO_RET_FAIL;
589 }
590
591 memset(&sockaddrin6, '\0', sizeof(sockaddrin6));
592 #if defined(HAVE_RES_SIN6_LEN)
593 sockaddrin6.sin6_len = sizeof(sockaddrin6);
594 #endif
595 sockaddrin6.sin6_family = AF_INET6;
596 sockaddrin6.sin6_addr = in6addr;
597 sockaddrin6.sin6_port = htons(ZBX_DEFAULT_DNS_PORT);
598 #if defined(HAVE_RES_NINIT) && !defined(_AIX) && (defined(HAVE_RES_U_EXT) || defined(HAVE_RES_U_EXT_EXT))
599 memset(&res_state_local.nsaddr_list[0], '\0', sizeof(res_state_local.nsaddr_list[0]));
600 # ifdef HAVE_RES_U_EXT /* Linux */
601 saved_ns6 = res_state_local._u._ext.nsaddrs[0];
602 res_state_local._u._ext.nsaddrs[0] = &sockaddrin6;
603 res_state_local._u._ext.nssocks[0] = -1;
604 res_state_local._u._ext.nscount6 = 1; /* CentOS */
605 # elif HAVE_RES_U_EXT_EXT /* BSD */
606 if (NULL != res_state_local._u._ext.ext)
607 memcpy(res_state_local._u._ext.ext, &sockaddrin6, sizeof(sockaddrin6));
608
609 res_state_local.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT);
610 # endif
611 res_state_local.nscount = 1;
612 #else
613 memcpy(&saved_ns, &(_res.nsaddr_list[0]), sizeof(struct sockaddr_in));
614 saved_nscount = _res.nscount;
615 # if defined(HAVE_RES_U_EXT) || defined(HAVE_RES_U_EXT_EXT) || defined(HAVE_RES_EXT_EXT)
616 memset(&_res.nsaddr_list[0], '\0', sizeof(_res.nsaddr_list[0]));
617 _res.nscount = 1;
618 # endif
619 # if defined(HAVE_RES_U_EXT) /* thread-unsafe resolver API /Linux/ */
620 saved_nscount6 = _res._u._ext.nscount6;
621 saved_ns6 = _res._u._ext.nsaddrs[0];
622 save_nssocks = _res._u._ext.nssocks[0];
623 _res._u._ext.nsaddrs[0] = &sockaddrin6;
624 _res._u._ext.nssocks[0] = -1;
625 _res._u._ext.nscount6 = 1;
626 # elif defined(HAVE_RES_U_EXT_EXT) /* thread-unsafe resolver API /BSD/ */
627 memcpy(&saved_ns6, _res._u._ext.ext, sizeof(saved_ns6));
628 _res.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT);
629
630 if (NULL != _res._u._ext.ext)
631 memcpy(_res._u._ext.ext, &sockaddrin6, sizeof(sockaddrin6));
632 # elif defined(HAVE_RES_EXT_EXT) /* thread-unsafe resolver API /AIX/ */
633 memcpy(&saved_ns6, &(_res._ext.ext.nsaddrs[0]), sizeof(saved_ns6));
634 memcpy(&_res._ext.ext.nsaddrs[0], &sockaddrin6, sizeof(sockaddrin6));
635 # endif /* #if defined(HAVE_RES_U_EXT) */
636 #endif /* #if defined(HAVE_RES_NINIT) && !defined(_AIX) && (defined(HAVE_RES_U_EXT) || defined(HAVE_RES_U_EXT_EXT)) */
637 }
638
639 #if defined(HAVE_RES_NINIT) && !defined(_AIX) && (defined(HAVE_RES_U_EXT) || defined(HAVE_RES_U_EXT_EXT))
640 if (0 != use_tcp)
641 res_state_local.options |= RES_USEVC;
642
643 res_state_local.retrans = retrans;
644 res_state_local.retry = retry;
645
646 res = res_nsend(&res_state_local, buf, res, answer.buffer, sizeof(answer.buffer));
647
648 # ifdef HAVE_RES_U_EXT /* Linux */
649 if (NULL != ip && '\0' != *ip && AF_INET6 == ip_type)
650 res_state_local._u._ext.nsaddrs[0] = saved_ns6;
651 # endif
652 # ifdef HAVE_RES_NDESTROY
653 res_ndestroy(&res_state_local);
654 # else
655 res_nclose(&res_state_local);
656 # endif
657 #else /* thread-unsafe resolver API */
658 saved_options = _res.options;
659 saved_retrans = _res.retrans;
660 saved_retry = _res.retry;
661
662 if (0 != use_tcp)
663 _res.options |= RES_USEVC;
664
665 _res.retrans = retrans;
666 _res.retry = retry;
667
668 res = res_send(buf, res, answer.buffer, sizeof(answer.buffer));
669
670 _res.options = saved_options;
671 _res.retrans = saved_retrans;
672 _res.retry = saved_retry;
673
674 if (NULL != ip && '\0' != *ip)
675 {
676 if (AF_INET6 == ip_type)
677 {
678 # if defined(HAVE_RES_U_EXT) /* Linux */
679 _res._u._ext.nsaddrs[0] = saved_ns6;
680 _res._u._ext.nssocks[0] = save_nssocks;
681 _res._u._ext.nscount6 = saved_nscount6;
682 # elif defined(HAVE_RES_U_EXT_EXT) /* BSD */
683 if (NULL != _res._u._ext.ext)
684 memcpy(_res._u._ext.ext, &saved_ns6, sizeof(saved_ns6));
685 # elif defined(HAVE_RES_EXT_EXT) /* AIX */
686 memcpy(&_res._ext.ext.nsaddrs[0], &saved_ns6, sizeof(saved_ns6));
687 # endif
688 }
689
690 memcpy(&(_res.nsaddr_list[0]), &saved_ns, sizeof(struct sockaddr_in));
691 _res.nscount = saved_nscount;
692 }
693 #endif
694 hp = (HEADER *)answer.buffer;
695
696 if (1 == short_answer)
697 {
698 SET_UI64_RESULT(result, NOERROR != hp->rcode || 0 == ntohs(hp->ancount) || -1 == res ? 0 : 1);
699 return SYSINFO_RET_OK;
700 }
701
702 if (NOERROR != hp->rcode || 0 == ntohs(hp->ancount) || -1 == res)
703 {
704 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot perform DNS query."));
705 return SYSINFO_RET_FAIL;
706 }
707
708 msg_end = answer.buffer + res;
709
710 num_answers = ntohs(answer.h.ancount);
711 num_query = ntohs(answer.h.qdcount);
712
713 msg_ptr = answer.buffer + HFIXEDSZ;
714 zbx_vector_str_create(&answers);
715
716 /* skipping query records */
717 for (; 0 < num_query && msg_ptr < msg_end; num_query--)
718 msg_ptr += dn_skipname(msg_ptr, msg_end) + QFIXEDSZ;
719
720 for (; 0 < num_answers && msg_ptr < msg_end; num_answers--)
721 {
722 if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr)))
723 {
724 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
725 ret = SYSINFO_RET_FAIL;
726 goto clean;
727 }
728
729 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%-20s", name);
730
731 GETSHORT(q_type, msg_ptr);
732 GETSHORT(q_class, msg_ptr);
733 msg_ptr += INT32SZ; /* skipping TTL */
734 GETSHORT(q_len, msg_ptr);
735 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %-8s", decode_type(q_type));
736
737 switch (q_type)
738 {
739 case T_A:
740 switch (q_class)
741 {
742 case C_IN:
743 case C_HS:
744 memcpy(&inaddr, msg_ptr, INADDRSZ);
745 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
746 inet_ntoa(inaddr));
747 break;
748 default:
749 ;
750 }
751
752 msg_ptr += q_len;
753
754 break;
755 case T_AAAA:
756 switch (q_class)
757 {
758 case C_IN:
759 case C_HS:
760 memcpy(&in6addr, msg_ptr, IN6ADDRSZ);
761 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
762 inet_ntop(AF_INET6, &in6addr, tmp, sizeof(tmp)));
763 break;
764 default:
765 ;
766 }
767
768 msg_ptr += q_len;
769
770 break;
771 case T_NS:
772 case T_CNAME:
773 case T_MB:
774 case T_MD:
775 case T_MF:
776 case T_MG:
777 case T_MR:
778 case T_PTR:
779 if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr)))
780 {
781 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
782 return SYSINFO_RET_FAIL;
783 }
784 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);
785 break;
786 case T_MX:
787 GETSHORT(value, msg_ptr); /* preference */
788 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);
789
790 if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* exchange */
791 {
792 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
793 return SYSINFO_RET_FAIL;
794 }
795 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);
796
797 break;
798 case T_SOA:
799 if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* source host */
800 {
801 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
802 return SYSINFO_RET_FAIL;
803 }
804 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);
805
806 if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* administrator */
807 {
808 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
809 return SYSINFO_RET_FAIL;
810 }
811 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);
812
813 GETLONG(value, msg_ptr); /* serial number */
814 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);
815
816 GETLONG(value, msg_ptr); /* refresh time */
817 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);
818
819 GETLONG(value, msg_ptr); /* retry time */
820 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);
821
822 GETLONG(value, msg_ptr); /* expire time */
823 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);
824
825 GETLONG(value, msg_ptr); /* minimum TTL */
826 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);
827
828 break;
829 case T_NULL:
830 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " len:%d", q_len);
831 msg_ptr += q_len;
832 break;
833 case T_WKS:
834 if (INT32SZ + 1 > q_len)
835 {
836 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
837 return SYSINFO_RET_FAIL;
838 }
839
840 p = msg_ptr + q_len;
841
842 memcpy(&inaddr, msg_ptr, INADDRSZ);
843 msg_ptr += INT32SZ;
844
845 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", inet_ntoa(inaddr));
846
847 if (NULL != (pr = getprotobynumber(*msg_ptr)))
848 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", pr->p_name);
849 else
850 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", (int)*msg_ptr);
851
852 msg_ptr++;
853 n = 0;
854
855 while (msg_ptr < p)
856 {
857 c = *msg_ptr++;
858
859 do
860 {
861 if (0 != (c & 0200))
862 {
863 s = getservbyport((int)htons(n), pr ? pr->p_name : NULL);
864
865 if (NULL != s)
866 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", s->s_name);
867 else
868 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " #%d", n);
869 }
870
871 c <<= 1;
872 }
873 while (0 != (++n & 07));
874 }
875
876 break;
877 case T_HINFO:
878 p = msg_ptr + q_len;
879 c = *msg_ptr++;
880
881 if (0 != c)
882 {
883 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"%.*s\"", c, msg_ptr);
884 msg_ptr += c;
885 }
886
887 if (msg_ptr < p)
888 {
889 c = *msg_ptr++;
890
891 if (0 != c)
892 {
893 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"%.*s\"", c, msg_ptr);
894 msg_ptr += c;
895 }
896 }
897
898 break;
899 case T_MINFO:
900 if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* mailbox responsible for mailing lists */
901 {
902 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
903 return SYSINFO_RET_FAIL;
904 }
905 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);
906
907 if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* mailbox for error messages */
908 {
909 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
910 return SYSINFO_RET_FAIL;
911 }
912 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);
913
914 break;
915 case T_TXT:
916 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"");
917 p = msg_ptr + q_len;
918
919 while (msg_ptr < p)
920 {
921 for (c = *msg_ptr++; 0 < c && msg_ptr < p; c--)
922 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%c", *msg_ptr++);
923 }
924
925 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\"");
926
927 break;
928 case T_SRV:
929 GETSHORT(value, msg_ptr); /* priority */
930 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);
931
932 GETSHORT(value, msg_ptr); /* weight */
933 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);
934
935 GETSHORT(value, msg_ptr); /* port */
936 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);
937
938 if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* target */
939 {
940 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
941 return SYSINFO_RET_FAIL;
942 }
943 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);
944
945 break;
946 default:
947 msg_ptr += q_len;
948 break;
949 }
950
951 zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\n");
952
953 zbx_vector_str_append(&answers, zbx_strdup(NULL, buffer));
954 offset = 0;
955 *buffer = '\0';
956 }
957 #endif /* _WINDOWS */
958
959 zbx_vector_str_sort(&answers, ZBX_DEFAULT_STR_COMPARE_FUNC);
960
961 for (i = 0; i < answers.values_num; i++)
962 offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%s", answers.values[i]);
963
964 if (0 != offset)
965 buffer[--offset] = '\0';
966
967 SET_TEXT_RESULT(result, zbx_strdup(NULL, buffer));
968 ret = SYSINFO_RET_OK;
969
970 clean:
971 zbx_vector_str_clear_ext(&answers, zbx_str_free);
972 zbx_vector_str_destroy(&answers);
973 #ifdef _WINDOWS
974 clean_dns:
975 if (DNS_RCODE_NOERROR == res)
976 DnsRecordListFree(pQueryResults, DnsFreeRecordList);
977 #endif
978
979 return ret;
980
981 #else /* both HAVE_RES_QUERY and _WINDOWS not defined */
982
983 return SYSINFO_RET_FAIL;
984
985 #endif /* defined(HAVE_RES_QUERY) || defined(_WINDOWS) */
986 }
987
NET_DNS(AGENT_REQUEST * request,AGENT_RESULT * result)988 int NET_DNS(AGENT_REQUEST *request, AGENT_RESULT *result)
989 {
990 return dns_query(request, result, 1);
991 }
992
NET_DNS_RECORD(AGENT_REQUEST * request,AGENT_RESULT * result)993 int NET_DNS_RECORD(AGENT_REQUEST *request, AGENT_RESULT *result)
994 {
995 return dns_query(request, result, 0);
996 }
997