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 #include "zbxjson.h"
23 #include "log.h"
24
25 typedef struct
26 {
27 zbx_uint64_t ibytes;
28 zbx_uint64_t ipackets;
29 zbx_uint64_t ierr;
30 zbx_uint64_t idrop;
31 zbx_uint64_t ififo;
32 zbx_uint64_t iframe;
33 zbx_uint64_t icompressed;
34 zbx_uint64_t imulticast;
35 zbx_uint64_t obytes;
36 zbx_uint64_t opackets;
37 zbx_uint64_t oerr;
38 zbx_uint64_t odrop;
39 zbx_uint64_t ocolls;
40 zbx_uint64_t ofifo;
41 zbx_uint64_t ocarrier;
42 zbx_uint64_t ocompressed;
43 }
44 net_stat_t;
45
46 #if HAVE_INET_DIAG
47 # include <sys/socket.h>
48 # include <linux/netlink.h>
49 # include <linux/inet_diag.h>
50
51 enum
52 {
53 STATE_UNKNOWN = 0,
54 STATE_ESTABLISHED,
55 STATE_SYN_SENT,
56 STATE_SYN_RECV,
57 STATE_FIN_WAIT1,
58 STATE_FIN_WAIT2,
59 STATE_TIME_WAIT,
60 STATE_CLOSE,
61 STATE_CLOSE_WAIT,
62 STATE_LAST_ACK,
63 STATE_LISTEN,
64 STATE_CLOSING,
65 STATE_MAXSTATES
66 };
67
68 enum
69 {
70 NLERR_OK = 0,
71 NLERR_UNKNOWN,
72 NLERR_SOCKCREAT,
73 NLERR_BADSEND,
74 NLERR_BADRECV,
75 NLERR_RECVTIMEOUT,
76 NLERR_RESPTRUNCAT,
77 NLERR_OPNOTSUPPORTED,
78 NLERR_UNKNOWNMSGTYPE
79 };
80
81 static int nlerr;
82
find_tcp_port_by_state_nl(unsigned short port,int state,int * found)83 static int find_tcp_port_by_state_nl(unsigned short port, int state, int *found)
84 {
85 struct
86 {
87 struct nlmsghdr nlhdr;
88 struct inet_diag_req r;
89 }
90 request;
91
92 int ret = FAIL, fd, status, i;
93 int families[] = {AF_INET, AF_INET6, AF_UNSPEC};
94 unsigned int sequence = 0x58425A;
95 struct timeval timeout = { 1, 500 * 1000 };
96
97 struct sockaddr_nl s_sa = { AF_NETLINK, 0, 0, 0 };
98 struct iovec s_io[1] = { { &request, sizeof(request) } };
99 struct msghdr s_msg = { (void *)&s_sa, sizeof(struct sockaddr_nl), s_io, 1, NULL, 0, 0};
100
101 char buffer[BUFSIZ] = { 0 };
102
103 struct sockaddr_nl r_sa = { AF_NETLINK, 0, 0, 0 };
104 struct iovec r_io[1] = { { buffer, BUFSIZ } };
105 struct msghdr r_msg = { (void *)&r_sa, sizeof(struct sockaddr_nl), r_io, 1, NULL, 0, 0};
106
107 struct nlmsghdr *r_hdr;
108
109 *found = 0;
110
111 request.nlhdr.nlmsg_len = sizeof(request);
112 request.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
113 request.nlhdr.nlmsg_pid = 0;
114 request.nlhdr.nlmsg_seq = sequence;
115 request.nlhdr.nlmsg_type = TCPDIAG_GETSOCK;
116
117 memset(&request.r, 0, sizeof(request.r));
118 request.r.idiag_states = (1 << state);
119
120 if (-1 == (fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_INET_DIAG)) ||
121 0 != setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval)))
122 {
123 nlerr = NLERR_SOCKCREAT;
124 goto out;
125 }
126
127 nlerr = NLERR_OK;
128
129 for (i = 0; AF_UNSPEC != families[i]; i++)
130 {
131 request.r.idiag_family = families[i];
132
133 if (-1 == sendmsg(fd, &s_msg, 0))
134 {
135 nlerr = NLERR_BADSEND;
136 goto out;
137 }
138
139 while (NLERR_OK == nlerr)
140 {
141 status = recvmsg(fd, &r_msg, 0);
142
143 if (0 > status)
144 {
145 if (EAGAIN == errno || EWOULDBLOCK == errno)
146 nlerr = NLERR_RECVTIMEOUT;
147 else if (EINTR != errno)
148 nlerr = NLERR_BADRECV;
149
150 continue;
151 }
152
153 if (0 == status)
154 break;
155
156 for (r_hdr = (struct nlmsghdr *)buffer; NLMSG_OK(r_hdr, (unsigned)status);
157 r_hdr = NLMSG_NEXT(r_hdr, status))
158 {
159 struct inet_diag_msg *r = (struct inet_diag_msg *)NLMSG_DATA(r_hdr);
160
161 if (sequence != r_hdr->nlmsg_seq)
162 continue;
163
164 switch (r_hdr->nlmsg_type)
165 {
166 case NLMSG_DONE:
167 goto out;
168 case NLMSG_ERROR:
169 {
170 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(r_hdr);
171
172 if (NLMSG_LENGTH(sizeof(struct nlmsgerr)) > r_hdr->nlmsg_len)
173 {
174 nlerr = NLERR_RESPTRUNCAT;
175 }
176 else
177 {
178 nlerr = (EOPNOTSUPP == -err->error ? NLERR_OPNOTSUPPORTED :
179 NLERR_UNKNOWN);
180 }
181
182 goto out;
183 }
184 case 0x12:
185 if (state == r->idiag_state && port == ntohs(r->id.idiag_sport))
186 {
187 *found = 1;
188 goto out;
189 }
190 break;
191 default:
192 nlerr = NLERR_UNKNOWNMSGTYPE;
193 break;
194 }
195 }
196 }
197 }
198 out:
199 if (-1 != fd)
200 close(fd);
201
202 if (NLERR_OK == nlerr)
203 ret = SUCCEED;
204
205 return ret;
206 }
207 #endif
208
get_net_stat(const char * if_name,net_stat_t * result,char ** error)209 static int get_net_stat(const char *if_name, net_stat_t *result, char **error)
210 {
211 int ret = SYSINFO_RET_FAIL;
212 char line[MAX_STRING_LEN], name[MAX_STRING_LEN], *p;
213 FILE *f;
214
215 if (NULL == if_name || '\0' == *if_name)
216 {
217 *error = zbx_strdup(NULL, "Network interface name cannot be empty.");
218 return SYSINFO_RET_FAIL;
219 }
220
221 if (NULL == (f = fopen("/proc/net/dev", "r")))
222 {
223 *error = zbx_dsprintf(NULL, "Cannot open /proc/net/dev: %s", zbx_strerror(errno));
224 return SYSINFO_RET_FAIL;
225 }
226
227 while (NULL != fgets(line, sizeof(line), f))
228 {
229 if (NULL == (p = strstr(line, ":")))
230 continue;
231
232 *p = '\t';
233
234 if (17 == sscanf(line, "%s\t" ZBX_FS_UI64 "\t" ZBX_FS_UI64 "\t"
235 ZBX_FS_UI64 "\t" ZBX_FS_UI64 "\t"
236 ZBX_FS_UI64 "\t" ZBX_FS_UI64 "\t"
237 ZBX_FS_UI64 "\t" ZBX_FS_UI64 "\t"
238 ZBX_FS_UI64 "\t" ZBX_FS_UI64 "\t"
239 ZBX_FS_UI64 "\t" ZBX_FS_UI64 "\t"
240 ZBX_FS_UI64 "\t" ZBX_FS_UI64 "\t"
241 ZBX_FS_UI64 "\t" ZBX_FS_UI64 "\n",
242 name,
243 &result->ibytes, /* bytes */
244 &result->ipackets, /* packets */
245 &result->ierr, /* errs */
246 &result->idrop, /* drop */
247 &result->ififo, /* fifo (overruns) */
248 &result->iframe, /* frame */
249 &result->icompressed, /* compressed */
250 &result->imulticast, /* multicast */
251 &result->obytes, /* bytes */
252 &result->opackets, /* packets */
253 &result->oerr, /* errs */
254 &result->odrop, /* drop */
255 &result->ofifo, /* fifo (overruns)*/
256 &result->ocolls, /* colls (collisions) */
257 &result->ocarrier, /* carrier */
258 &result->ocompressed)) /* compressed */
259 {
260 if (0 == strcmp(name, if_name))
261 {
262 ret = SYSINFO_RET_OK;
263 break;
264 }
265 }
266 }
267
268 zbx_fclose(f);
269
270 if (SYSINFO_RET_FAIL == ret)
271 {
272 *error = zbx_strdup(NULL, "Cannot find information for this network interface in /proc/net/dev.");
273 return SYSINFO_RET_FAIL;
274 }
275
276 return SYSINFO_RET_OK;
277 }
278
279 /******************************************************************************
280 * *
281 * Function: proc_read_tcp_listen *
282 * *
283 * Purpose: reads /proc/net/tcp(6) file by chunks until the last line in *
284 * in buffer has non-listening socket state *
285 * *
286 * Parameters: filename - [IN] the file to read *
287 * buffer - [IN/OUT] the output buffer *
288 * buffer_alloc - [IN/OUT] the output buffer size *
289 * *
290 * Return value: -1 error occurred during reading *
291 * 0 empty file (shouldn't happen) *
292 * >0 the number of bytes read *
293 * *
294 ******************************************************************************/
proc_read_tcp_listen(const char * filename,char ** buffer,int * buffer_alloc)295 static int proc_read_tcp_listen(const char *filename, char **buffer, int *buffer_alloc)
296 {
297 int n, fd, ret = -1, offset = 0;
298 char *start, *end;
299
300 if (-1 == (fd = open(filename, O_RDONLY)))
301 return -1;
302
303 while (0 != (n = read(fd, *buffer + offset, *buffer_alloc - offset)))
304 {
305 int count = 0;
306
307 if (-1 == n)
308 goto out;
309
310 offset += n;
311
312 if (offset == *buffer_alloc)
313 {
314 *buffer_alloc *= 2;
315 *buffer = (char *)zbx_realloc(*buffer, *buffer_alloc);
316 }
317
318 (*buffer)[offset] = '\0';
319
320 /* find the last full line */
321 for (start = *buffer + offset - 1; start > *buffer; start--)
322 {
323 if ('\n' == *start)
324 {
325 if (++count == 2)
326 break;
327
328 end = start;
329 }
330 }
331
332 /* check if the socket is in listening state */
333 if (2 == count)
334 {
335 start++;
336 count = 0;
337
338 while (' ' == *start++)
339 ;
340
341 while (count < 3 && start < end)
342 {
343 while (' ' != *start)
344 start++;
345
346 while (' ' == *start)
347 start++;
348
349 count++;
350 }
351
352 if (3 == count && 0 != strncmp(start, "0A", 2) && 0 != strncmp(start, "03", 2))
353 break;
354 }
355 }
356
357 ret = offset;
358 out:
359 close(fd);
360
361 return ret;
362 }
363
364 /******************************************************************************
365 * *
366 * Function: proc_read_file *
367 * *
368 * Purpose: reads whole file into a buffer in a single read operation *
369 * *
370 * Parameters: filename - [IN] the file to read *
371 * buffer - [IN/OUT] the output buffer *
372 * buffer_alloc - [IN/OUT] the output buffer size *
373 * *
374 * Return value: -1 error occurred during reading *
375 * 0 empty file (shouldn't happen) *
376 * >0 the number of bytes read *
377 * *
378 ******************************************************************************/
proc_read_file(const char * filename,char ** buffer,int * buffer_alloc)379 static int proc_read_file(const char *filename, char **buffer, int *buffer_alloc)
380 {
381 int n, fd, ret = -1, offset = 0;
382
383 if (-1 == (fd = open(filename, O_RDONLY)))
384 return -1;
385
386 while (0 != (n = read(fd, *buffer + offset, *buffer_alloc - offset)))
387 {
388 if (-1 == n)
389 goto out;
390
391 offset += n;
392
393 if (offset == *buffer_alloc)
394 {
395 *buffer_alloc *= 2;
396 *buffer = (char *)zbx_realloc(*buffer, *buffer_alloc);
397 }
398 }
399
400 ret = offset;
401 out:
402 close(fd);
403
404 return ret;
405 }
406
NET_IF_IN(AGENT_REQUEST * request,AGENT_RESULT * result)407 int NET_IF_IN(AGENT_REQUEST *request, AGENT_RESULT *result)
408 {
409 net_stat_t ns;
410 char *if_name, *mode, *error;
411
412 if (2 < request->nparam)
413 {
414 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
415 return SYSINFO_RET_FAIL;
416 }
417
418 if_name = get_rparam(request, 0);
419 mode = get_rparam(request, 1);
420
421 if (SYSINFO_RET_OK != get_net_stat(if_name, &ns, &error))
422 {
423 SET_MSG_RESULT(result, error);
424 return SYSINFO_RET_FAIL;
425 }
426
427 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* default parameter */
428 SET_UI64_RESULT(result, ns.ibytes);
429 else if (0 == strcmp(mode, "packets"))
430 SET_UI64_RESULT(result, ns.ipackets);
431 else if (0 == strcmp(mode, "errors"))
432 SET_UI64_RESULT(result, ns.ierr);
433 else if (0 == strcmp(mode, "dropped"))
434 SET_UI64_RESULT(result, ns.idrop);
435 else if (0 == strcmp(mode, "overruns"))
436 SET_UI64_RESULT(result, ns.ififo);
437 else if (0 == strcmp(mode, "frame"))
438 SET_UI64_RESULT(result, ns.iframe);
439 else if (0 == strcmp(mode, "compressed"))
440 SET_UI64_RESULT(result, ns.icompressed);
441 else if (0 == strcmp(mode, "multicast"))
442 SET_UI64_RESULT(result, ns.imulticast);
443 else
444 {
445 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
446 return SYSINFO_RET_FAIL;
447 }
448
449 return SYSINFO_RET_OK;
450 }
451
NET_IF_OUT(AGENT_REQUEST * request,AGENT_RESULT * result)452 int NET_IF_OUT(AGENT_REQUEST *request, AGENT_RESULT *result)
453 {
454 net_stat_t ns;
455 char *if_name, *mode, *error;
456
457 if (2 < request->nparam)
458 {
459 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
460 return SYSINFO_RET_FAIL;
461 }
462
463 if_name = get_rparam(request, 0);
464 mode = get_rparam(request, 1);
465
466 if (SYSINFO_RET_OK != get_net_stat(if_name, &ns, &error))
467 {
468 SET_MSG_RESULT(result, error);
469 return SYSINFO_RET_FAIL;
470 }
471
472 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* default parameter */
473 SET_UI64_RESULT(result, ns.obytes);
474 else if (0 == strcmp(mode, "packets"))
475 SET_UI64_RESULT(result, ns.opackets);
476 else if (0 == strcmp(mode, "errors"))
477 SET_UI64_RESULT(result, ns.oerr);
478 else if (0 == strcmp(mode, "dropped"))
479 SET_UI64_RESULT(result, ns.odrop);
480 else if (0 == strcmp(mode, "overruns"))
481 SET_UI64_RESULT(result, ns.ofifo);
482 else if (0 == strcmp(mode, "collisions"))
483 SET_UI64_RESULT(result, ns.ocolls);
484 else if (0 == strcmp(mode, "carrier"))
485 SET_UI64_RESULT(result, ns.ocarrier);
486 else if (0 == strcmp(mode, "compressed"))
487 SET_UI64_RESULT(result, ns.ocompressed);
488 else
489 {
490 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
491 return SYSINFO_RET_FAIL;
492 }
493
494 return SYSINFO_RET_OK;
495 }
496
NET_IF_TOTAL(AGENT_REQUEST * request,AGENT_RESULT * result)497 int NET_IF_TOTAL(AGENT_REQUEST *request, AGENT_RESULT *result)
498 {
499 net_stat_t ns;
500 char *if_name, *mode, *error;
501
502 if (2 < request->nparam)
503 {
504 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
505 return SYSINFO_RET_FAIL;
506 }
507
508 if_name = get_rparam(request, 0);
509 mode = get_rparam(request, 1);
510
511 if (SYSINFO_RET_OK != get_net_stat(if_name, &ns, &error))
512 {
513 SET_MSG_RESULT(result, error);
514 return SYSINFO_RET_FAIL;
515 }
516
517 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* default parameter */
518 SET_UI64_RESULT(result, ns.ibytes + ns.obytes);
519 else if (0 == strcmp(mode, "packets"))
520 SET_UI64_RESULT(result, ns.ipackets + ns.opackets);
521 else if (0 == strcmp(mode, "errors"))
522 SET_UI64_RESULT(result, ns.ierr + ns.oerr);
523 else if (0 == strcmp(mode, "dropped"))
524 SET_UI64_RESULT(result, ns.idrop + ns.odrop);
525 else if (0 == strcmp(mode, "overruns"))
526 SET_UI64_RESULT(result, ns.ififo + ns.ofifo);
527 else if (0 == strcmp(mode, "compressed"))
528 SET_UI64_RESULT(result, ns.icompressed + ns.ocompressed);
529 else
530 {
531 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
532 return SYSINFO_RET_FAIL;
533 }
534
535 return SYSINFO_RET_OK;
536 }
537
NET_IF_COLLISIONS(AGENT_REQUEST * request,AGENT_RESULT * result)538 int NET_IF_COLLISIONS(AGENT_REQUEST *request, AGENT_RESULT *result)
539 {
540 net_stat_t ns;
541 char *if_name, *error;
542
543 if (1 < request->nparam)
544 {
545 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
546 return SYSINFO_RET_FAIL;
547 }
548
549 if_name = get_rparam(request, 0);
550
551 if (SYSINFO_RET_OK != get_net_stat(if_name, &ns, &error))
552 {
553 SET_MSG_RESULT(result, error);
554 return SYSINFO_RET_FAIL;
555 }
556
557 SET_UI64_RESULT(result, ns.ocolls);
558
559 return SYSINFO_RET_OK;
560 }
561
NET_IF_DISCOVERY(AGENT_REQUEST * request,AGENT_RESULT * result)562 int NET_IF_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
563 {
564 char line[MAX_STRING_LEN], *p;
565 FILE *f;
566 struct zbx_json j;
567
568 ZBX_UNUSED(request);
569
570 if (NULL == (f = fopen("/proc/net/dev", "r")))
571 {
572 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /proc/net/dev: %s", zbx_strerror(errno)));
573 return SYSINFO_RET_FAIL;
574 }
575
576 zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
577
578 zbx_json_addarray(&j, ZBX_PROTO_TAG_DATA);
579
580 while (NULL != fgets(line, sizeof(line), f))
581 {
582 if (NULL == (p = strstr(line, ":")))
583 continue;
584
585 *p = '\0';
586
587 /* trim left spaces */
588 for (p = line; ' ' == *p && '\0' != *p; p++)
589 ;
590
591 zbx_json_addobject(&j, NULL);
592 zbx_json_addstring(&j, "{#IFNAME}", p, ZBX_JSON_TYPE_STRING);
593 zbx_json_close(&j);
594 }
595
596 zbx_fclose(f);
597
598 zbx_json_close(&j);
599
600 SET_STR_RESULT(result, strdup(j.buffer));
601
602 zbx_json_free(&j);
603
604 return SYSINFO_RET_OK;
605 }
606
NET_TCP_LISTEN(AGENT_REQUEST * request,AGENT_RESULT * result)607 int NET_TCP_LISTEN(AGENT_REQUEST *request, AGENT_RESULT *result)
608 {
609 char pattern[64], *port_str, *buffer = NULL;
610 unsigned short port;
611 zbx_uint64_t listen = 0;
612 int ret = SYSINFO_RET_FAIL, n, buffer_alloc = 64 * ZBX_KIBIBYTE;
613 #ifdef HAVE_INET_DIAG
614 int found;
615 #endif
616 if (1 < request->nparam)
617 {
618 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
619 return SYSINFO_RET_FAIL;
620 }
621
622 port_str = get_rparam(request, 0);
623
624 if (NULL == port_str || SUCCEED != is_ushort(port_str, &port))
625 {
626 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
627 return SYSINFO_RET_FAIL;
628 }
629
630 #ifdef HAVE_INET_DIAG
631 if (SUCCEED == find_tcp_port_by_state_nl(port, STATE_LISTEN, &found))
632 {
633 ret = SYSINFO_RET_OK;
634 listen = found;
635 }
636 else
637 {
638 const char *error;
639
640 switch (nlerr)
641 {
642 case NLERR_UNKNOWN:
643 error = "unrecognized netlink error occurred";
644 break;
645 case NLERR_SOCKCREAT:
646 error = "cannot create netlink socket";
647 break;
648 case NLERR_BADSEND:
649 error = "cannot send netlink message to kernel";
650 break;
651 case NLERR_BADRECV:
652 error = "cannot receive netlink message from kernel";
653 break;
654 case NLERR_RECVTIMEOUT:
655 error = "receiving netlink response timed out";
656 break;
657 case NLERR_RESPTRUNCAT:
658 error = "received truncated netlink response from kernel";
659 break;
660 case NLERR_OPNOTSUPPORTED:
661 error = "netlink operation not supported";
662 break;
663 case NLERR_UNKNOWNMSGTYPE:
664 error = "received message of unrecognized type from kernel";
665 break;
666 default:
667 error = "unknown error";
668 }
669
670 zabbix_log(LOG_LEVEL_DEBUG, "netlink interface error: %s", error);
671 zabbix_log(LOG_LEVEL_DEBUG, "falling back on reading /proc/net/tcp...");
672 #endif
673 buffer = (char *)zbx_malloc(NULL, buffer_alloc);
674
675 if (0 < (n = proc_read_tcp_listen("/proc/net/tcp", &buffer, &buffer_alloc)))
676 {
677 ret = SYSINFO_RET_OK;
678
679 zbx_snprintf(pattern, sizeof(pattern), "%04X 00000000:0000 0A", (unsigned int)port);
680
681 if (NULL != strstr(buffer, pattern))
682 {
683 listen = 1;
684 goto out;
685 }
686 }
687
688 if (0 < (n = proc_read_tcp_listen("/proc/net/tcp6", &buffer, &buffer_alloc)))
689 {
690 ret = SYSINFO_RET_OK;
691
692 zbx_snprintf(pattern, sizeof(pattern), "%04X 00000000000000000000000000000000:0000 0A",
693 (unsigned int)port);
694
695 if (NULL != strstr(buffer, pattern))
696 listen = 1;
697 }
698 out:
699 zbx_free(buffer);
700 #ifdef HAVE_INET_DIAG
701 }
702 #endif
703 SET_UI64_RESULT(result, listen);
704
705 return ret;
706 }
707
NET_UDP_LISTEN(AGENT_REQUEST * request,AGENT_RESULT * result)708 int NET_UDP_LISTEN(AGENT_REQUEST *request, AGENT_RESULT *result)
709 {
710 char pattern[64], *port_str, *buffer = NULL;
711 unsigned short port;
712 zbx_uint64_t listen = 0;
713 int ret = SYSINFO_RET_FAIL, n, buffer_alloc = 64 * ZBX_KIBIBYTE;
714
715 if (1 < request->nparam)
716 {
717 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
718 return SYSINFO_RET_FAIL;
719 }
720
721 port_str = get_rparam(request, 0);
722
723 if (NULL == port_str || SUCCEED != is_ushort(port_str, &port))
724 {
725 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
726 return SYSINFO_RET_FAIL;
727 }
728
729 buffer = (char *)zbx_malloc(NULL, buffer_alloc);
730
731 if (0 < (n = proc_read_file("/proc/net/udp", &buffer, &buffer_alloc)))
732 {
733 ret = SYSINFO_RET_OK;
734
735 zbx_snprintf(pattern, sizeof(pattern), "%04X 00000000:0000 07", (unsigned int)port);
736
737 buffer[n] = '\0';
738
739 if (NULL != strstr(buffer, pattern))
740 {
741 listen = 1;
742 goto out;
743 }
744 }
745
746 if (0 < (n = proc_read_file("/proc/net/udp6", &buffer, &buffer_alloc)))
747 {
748 ret = SYSINFO_RET_OK;
749
750 zbx_snprintf(pattern, sizeof(pattern), "%04X 00000000000000000000000000000000:0000 07",
751 (unsigned int)port);
752
753 buffer[n] = '\0';
754
755 if (NULL != strstr(buffer, pattern))
756 listen = 1;
757 }
758 out:
759 zbx_free(buffer);
760
761 SET_UI64_RESULT(result, listen);
762
763 return ret;
764 }
765