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