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