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 <unistd.h>
21 #include <stropts.h>
22 #include <sys/dlpi.h>
23 #include <sys/dlpi_ext.h>
24 #include <sys/mib.h>
25
26 #include "common.h"
27 #include "sysinfo.h"
28 #include "zbxjson.h"
29
30 #define PPA(n) (*(dl_hp_ppa_info_t *)(ppa_data_buf + n * sizeof(dl_hp_ppa_info_t)))
31
32 static char buf_ctl[1024];
33
34 /* Low Level Discovery needs a way to get the list of network interfaces available */
35 /* on the monitored system. HP-UX versions starting from 11.31 have if_nameindex() */
36 /* available in libc, older versions have it in libipv6 which we do not want to */
37 /* depend on. So for older versions we use different code to get that list. */
38 /* More information: */
39 /* h20000.www2.hp.com/bc/docs/support/SupportManual/c02258083/c02258083.pdf */
40
41 static struct strbuf ctlbuf =
42 {
43 sizeof(buf_ctl),
44 0,
45 buf_ctl
46 };
47
48 #if HPUX_VERSION < 1131
49
50 #define ZBX_IF_SEP ','
51
add_if_name(char ** if_list,size_t * if_list_alloc,size_t * if_list_offset,const char * name)52 static void add_if_name(char **if_list, size_t *if_list_alloc, size_t *if_list_offset, const char *name)
53 {
54 if (FAIL == str_in_list(*if_list, name, ZBX_IF_SEP))
55 {
56 if ('\0' != **if_list)
57 zbx_chrcpy_alloc(if_list, if_list_alloc, if_list_offset, ZBX_IF_SEP);
58
59 zbx_strcpy_alloc(if_list, if_list_alloc, if_list_offset, name);
60 }
61 }
62
get_if_names(char ** if_list,size_t * if_list_alloc,size_t * if_list_offset)63 static int get_if_names(char **if_list, size_t *if_list_alloc, size_t *if_list_offset)
64 {
65 int s, ifreq_size, numifs, i, family = AF_INET;
66 struct sockaddr *from;
67 u_char *buffer = NULL;
68 struct ifconf ifc;
69 struct ifreq *ifr;
70 struct if_laddrconf lifc;
71 struct if_laddrreq *lifr;
72
73 if (-1 == (s = socket(family, SOCK_DGRAM, 0)))
74 return FAIL;
75
76 ifc.ifc_buf = 0;
77 ifc.ifc_len = 0;
78
79 if (0 == ioctl(s, SIOCGIFCONF, (caddr_t)&ifc) && 0 != ifc.ifc_len)
80 ifreq_size = 2 * ifc.ifc_len;
81 else
82 ifreq_size = 2 * 512;
83
84 buffer = zbx_malloc(buffer, ifreq_size);
85 memset(buffer, 0, ifreq_size);
86
87 ifc.ifc_buf = (caddr_t)buffer;
88 ifc.ifc_len = ifreq_size;
89
90 if (-1 == ioctl(s, SIOCGIFCONF, &ifc))
91 goto next;
92
93 /* check all IPv4 interfaces */
94 ifr = (struct ifreq *)ifc.ifc_req;
95 while ((u_char *)ifr < (u_char *)(buffer + ifc.ifc_len))
96 {
97 from = &ifr->ifr_addr;
98
99 if (AF_INET6 != from->sa_family && AF_INET != from->sa_family)
100 continue;
101
102 add_if_name(if_list, if_list_alloc, if_list_offset, ifr->ifr_name);
103
104 #ifdef _SOCKADDR_LEN
105 ifr = (struct ifreq *)((char *)ifr + sizeof(*ifr) + (from->sa_len > sizeof(*from) ? from->sa_len - sizeof(*from) : 0));
106 #else
107 ifr++;
108 #endif
109 }
110 next:
111 zbx_free(buffer);
112 close(s);
113
114 #if defined (SIOCGLIFCONF)
115 family = AF_INET6;
116
117 if (-1 == (s = socket(family, SOCK_DGRAM, 0)))
118 return FAIL;
119
120 i = ioctl(s, SIOCGLIFNUM, (char *)&numifs);
121 if (0 == numifs)
122 {
123 close(s);
124 return SUCCEED;
125 }
126
127 lifc.iflc_len = numifs * sizeof(struct if_laddrreq);
128 lifc.iflc_buf = zbx_malloc(NULL, lifc.iflc_len);
129 buffer = (u_char *)lifc.iflc_buf;
130
131 if (-1 == ioctl(s, SIOCGLIFCONF, &lifc))
132 goto end;
133
134 /* check all IPv6 interfaces */
135 for (lifr = lifc.iflc_req; '\0' != *lifr->iflr_name; lifr++)
136 {
137 from = (struct sockaddr *)&lifr->iflr_addr;
138
139 if (AF_INET6 != from->sa_family && AF_INET != from->sa_family)
140 continue;
141
142 add_if_name(if_list, if_list_alloc, if_list_offset, lifr->iflr_name);
143 }
144 end:
145 zbx_free(buffer);
146 close(s);
147 #else
148 ZBX_UNUSED(numifs);
149 ZBX_UNUSED(i);
150 ZBX_UNUSED(lifc);
151 ZBX_UNUSED(lifr);
152 #endif
153 return SUCCEED;
154 }
155
156 #endif /* HPUX_VERSION < 1131 */
157
NET_IF_DISCOVERY(AGENT_REQUEST * request,AGENT_RESULT * result)158 int NET_IF_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
159 {
160 struct zbx_json j;
161 char *if_name;
162 #if HPUX_VERSION < 1131
163 char *if_list = NULL, *if_name_end;
164 size_t if_list_alloc = 64, if_list_offset = 0;
165
166 if_list = zbx_malloc(if_list, if_list_alloc);
167 *if_list = '\0';
168
169 if (FAIL == get_if_names(&if_list, &if_list_alloc, &if_list_offset))
170 {
171 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain network interface information."));
172 zbx_free(if_list);
173 return SYSINFO_RET_FAIL;
174 }
175
176 zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
177
178 if_name = if_list;
179
180 while (NULL != if_name)
181 {
182 if (NULL != (if_name_end = strchr(if_name, ZBX_IF_SEP)))
183 *if_name_end = '\0';
184
185 zbx_json_addobject(&j, NULL);
186 zbx_json_addstring(&j, "{#IFNAME}", if_name, ZBX_JSON_TYPE_STRING);
187 zbx_json_close(&j);
188
189 if (NULL != if_name_end)
190 {
191 *if_name_end = ZBX_IF_SEP;
192 if_name = if_name_end + 1;
193 }
194 else
195 if_name = NULL;
196 }
197
198 zbx_free(if_list);
199 #else
200 struct if_nameindex *ni;
201 int i;
202
203 if (NULL == (ni = if_nameindex()))
204 {
205 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
206 return SYSINFO_RET_FAIL;
207 }
208
209 zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
210
211 for (i = 0; 0 != ni[i].if_index; i++)
212 {
213 zbx_json_addobject(&j, NULL);
214 zbx_json_addstring(&j, "{#IFNAME}", ni[i].if_name, ZBX_JSON_TYPE_STRING);
215 zbx_json_close(&j);
216 }
217
218 if_freenameindex(ni);
219 #endif
220 zbx_json_close(&j);
221
222 SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
223
224 zbx_json_free(&j);
225
226 return SYSINFO_RET_OK;
227 }
228
229 /* attaches to a PPA via an already open stream to DLPI provider */
dlpi_attach(int fd,int ppa)230 static int dlpi_attach(int fd, int ppa)
231 {
232 dl_attach_req_t attach_req;
233 int flags = RS_HIPRI;
234
235 attach_req.dl_primitive = DL_ATTACH_REQ;
236 attach_req.dl_ppa = ppa;
237
238 ctlbuf.len = sizeof(attach_req);
239 ctlbuf.buf = (char *)&attach_req;
240
241 if (0 != putmsg(fd, &ctlbuf, NULL, flags))
242 return FAIL;
243
244 ctlbuf.buf = buf_ctl;
245 ctlbuf.maxlen = sizeof(buf_ctl);
246
247 if (0 > getmsg(fd, &ctlbuf, NULL, &flags))
248 return FAIL;
249
250 if (DL_OK_ACK != *(int *)buf_ctl)
251 return FAIL;
252
253 /* Successfully attached to a PPA. */
254 return SUCCEED;
255 }
256
257 /* Detaches from a PPA via an already open stream to DLPI provider. */
dlpi_detach(int fd)258 static int dlpi_detach(int fd)
259 {
260 dl_detach_req_t detach_req;
261 int flags = RS_HIPRI;
262
263 detach_req.dl_primitive = DL_DETACH_REQ;
264
265 ctlbuf.len = sizeof(detach_req);
266 ctlbuf.buf = (char *)&detach_req;
267
268 if (0 != putmsg(fd, &ctlbuf, NULL, flags))
269 return FAIL;
270
271 ctlbuf.buf = buf_ctl;
272 ctlbuf.maxlen = sizeof(buf_ctl);
273
274 if (0 > getmsg(fd, &ctlbuf, NULL, &flags))
275 return FAIL;
276
277 if (DL_OK_ACK != *(int *)buf_ctl)
278 return FAIL;
279
280 /* successfully detached */
281 return SUCCEED;
282 }
283
dlpi_get_stats(int fd,Ext_mib_t * mib)284 static int dlpi_get_stats(int fd, Ext_mib_t *mib)
285 {
286 dl_get_statistics_req_t stat_req;
287 dl_get_statistics_ack_t stat_msg;
288 int flags = RS_HIPRI;
289
290 stat_req.dl_primitive = DL_GET_STATISTICS_REQ;
291
292 ctlbuf.len = sizeof(stat_req);
293 ctlbuf.buf = (char *)&stat_req;
294
295 if (0 != putmsg(fd, &ctlbuf, NULL, flags))
296 return FAIL;
297
298 ctlbuf.buf = buf_ctl;
299 ctlbuf.maxlen = sizeof(buf_ctl);
300
301 if (0 > getmsg(fd, &ctlbuf, NULL, &flags))
302 return FAIL;
303
304 if (DL_GET_STATISTICS_ACK != *(int *)buf_ctl)
305 return FAIL;
306
307 stat_msg = *(dl_get_statistics_ack_t *)buf_ctl;
308
309 memcpy(mib, (Ext_mib_t *)(buf_ctl + stat_msg.dl_stat_offset), sizeof(Ext_mib_t));
310
311 return SUCCEED;
312 }
313
get_ppa(int fd,const char * if_name,int * ppa)314 static int get_ppa(int fd, const char *if_name, int *ppa)
315 {
316 dl_hp_ppa_req_t ppa_req;
317 dl_hp_ppa_ack_t *dlp;
318 int i, ret = FAIL, flags = RS_HIPRI, res;
319 char *buf = NULL, *ppa_data_buf = NULL;
320
321 ppa_req.dl_primitive = DL_HP_PPA_REQ;
322
323 ctlbuf.len = sizeof(ppa_req);
324 ctlbuf.buf = (char *)&ppa_req;
325
326 if (0 != putmsg(fd, &ctlbuf, NULL, flags))
327 return ret;
328
329 ctlbuf.buf = buf_ctl;
330 ctlbuf.maxlen = DL_HP_PPA_ACK_SIZE;
331
332 res = getmsg(fd, &ctlbuf, NULL, &flags);
333
334 /* get the head first */
335 if (0 > res)
336 return ret;
337
338 dlp = (dl_hp_ppa_ack_t *)ctlbuf.buf;
339
340 if (DL_HP_PPA_ACK != dlp->dl_primitive)
341 return ret;
342
343 if (DL_HP_PPA_ACK_SIZE > ctlbuf.len)
344 return ret;
345
346 if (MORECTL == res)
347 {
348 size_t if_name_sz = strlen(if_name) + 1;
349
350 ctlbuf.maxlen = dlp->dl_count * sizeof(dl_hp_ppa_info_t);
351 ctlbuf.len = 0;
352
353 ppa_data_buf = zbx_malloc(ppa_data_buf, (size_t)ctlbuf.maxlen);
354
355 ctlbuf.buf = ppa_data_buf;
356
357 /* get the data */
358 if (0 > getmsg(fd, &ctlbuf, NULL, &flags) || ctlbuf.len < dlp->dl_length)
359 {
360 zbx_free(ppa_data_buf);
361 return ret;
362 }
363
364 buf = zbx_malloc(buf, if_name_sz);
365
366 for (i = 0; i < dlp->dl_count; i++)
367 {
368 zbx_snprintf(buf, if_name_sz, "%s%d", PPA(i).dl_module_id_1, PPA(i).dl_ppa);
369
370 if (0 == strcmp(if_name, buf))
371 {
372 *ppa = PPA(i).dl_ppa;
373 ret = SUCCEED;
374 break;
375 }
376 }
377
378 zbx_free(buf);
379 zbx_free(ppa_data_buf);
380 }
381
382 return ret;
383 }
384
get_net_stat(Ext_mib_t * mib,const char * if_name)385 static int get_net_stat(Ext_mib_t *mib, const char *if_name)
386 {
387 int fd, ppa;
388
389 if (-1 == (fd = open("/dev/dlpi", O_RDWR)))
390 return FAIL;
391
392 if (FAIL == get_ppa(fd, if_name, &ppa))
393 {
394 close(fd);
395 return FAIL;
396 }
397
398 if (FAIL == dlpi_attach(fd, ppa))
399 return FAIL;
400
401 if (FAIL == dlpi_get_stats(fd, mib))
402 return FAIL;
403
404 dlpi_detach(fd);
405
406 close(fd);
407
408 return SUCCEED;
409 }
410
NET_IF_IN(AGENT_REQUEST * request,AGENT_RESULT * result)411 int NET_IF_IN(AGENT_REQUEST *request, AGENT_RESULT *result)
412 {
413 char *if_name, *mode;
414 Ext_mib_t mib;
415
416 if (2 < request->nparam)
417 {
418 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
419 return SYSINFO_RET_FAIL;
420 }
421
422 if_name = get_rparam(request, 0);
423 mode = get_rparam(request, 1);
424
425 if (FAIL == get_net_stat(&mib, if_name))
426 {
427 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain network interface information."));
428 return SYSINFO_RET_FAIL;
429 }
430
431 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes"))
432 SET_UI64_RESULT(result, mib.mib_if.ifInOctets);
433 else if (0 == strcmp(mode, "packets"))
434 SET_UI64_RESULT(result, mib.mib_if.ifInUcastPkts + mib.mib_if.ifInNUcastPkts);
435 else if (0 == strcmp(mode, "errors"))
436 SET_UI64_RESULT(result, mib.mib_if.ifInErrors);
437 else if (0 == strcmp(mode, "dropped"))
438 SET_UI64_RESULT(result, mib.mib_if.ifInDiscards);
439 else
440 {
441 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
442 return SYSINFO_RET_FAIL;
443 }
444
445 return SYSINFO_RET_OK;
446 }
447
NET_IF_OUT(AGENT_REQUEST * request,AGENT_RESULT * result)448 int NET_IF_OUT(AGENT_REQUEST *request, AGENT_RESULT *result)
449 {
450 char *if_name, *mode;
451 Ext_mib_t mib;
452
453 if (2 < request->nparam)
454 {
455 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
456 return SYSINFO_RET_FAIL;
457 }
458
459 if_name = get_rparam(request, 0);
460 mode = get_rparam(request, 1);
461
462 if (FAIL == get_net_stat(&mib, if_name))
463 {
464 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain network interface information."));
465 return SYSINFO_RET_FAIL;
466 }
467
468 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes"))
469 SET_UI64_RESULT(result, mib.mib_if.ifOutOctets);
470 else if (0 == strcmp(mode, "packets"))
471 SET_UI64_RESULT(result, mib.mib_if.ifOutUcastPkts + mib.mib_if.ifOutNUcastPkts);
472 else if (0 == strcmp(mode, "errors"))
473 SET_UI64_RESULT(result, mib.mib_if.ifOutErrors);
474 else if (0 == strcmp(mode, "dropped"))
475 SET_UI64_RESULT(result, mib.mib_if.ifOutDiscards);
476 else
477 {
478 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
479 return SYSINFO_RET_FAIL;
480 }
481
482 return SYSINFO_RET_OK;
483 }
484
NET_IF_TOTAL(AGENT_REQUEST * request,AGENT_RESULT * result)485 int NET_IF_TOTAL(AGENT_REQUEST *request, AGENT_RESULT *result)
486 {
487 char *if_name, *mode;
488 Ext_mib_t mib;
489
490 if (2 < request->nparam)
491 {
492 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
493 return SYSINFO_RET_FAIL;
494 }
495
496 if_name = get_rparam(request, 0);
497 mode = get_rparam(request, 1);
498
499 if (FAIL == get_net_stat(&mib, if_name))
500 {
501 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain network interface information."));
502 return SYSINFO_RET_FAIL;
503 }
504
505 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes"))
506 {
507 SET_UI64_RESULT(result, mib.mib_if.ifInOctets + mib.mib_if.ifOutOctets);
508 }
509 else if (0 == strcmp(mode, "packets"))
510 {
511 SET_UI64_RESULT(result, mib.mib_if.ifInUcastPkts + mib.mib_if.ifInNUcastPkts
512 + mib.mib_if.ifOutUcastPkts + mib.mib_if.ifOutNUcastPkts);
513 }
514 else if (0 == strcmp(mode, "errors"))
515 {
516 SET_UI64_RESULT(result, mib.mib_if.ifInErrors + mib.mib_if.ifOutErrors);
517 }
518 else if (0 == strcmp(mode, "dropped"))
519 {
520 SET_UI64_RESULT(result, mib.mib_if.ifInDiscards + mib.mib_if.ifOutDiscards);
521 }
522 else
523 {
524 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
525 return SYSINFO_RET_FAIL;
526 }
527
528 return SYSINFO_RET_OK;
529 }
530