min/max calls replaced with std::min/std::max
[public/netxms.git] / src / agent / subagents / linux / net.cpp
1 /*
2 ** NetXMS subagent for GNU/Linux
3 ** Copyright (C) 2004-2015 Raden Solutions
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 **/
20
21 #include <linux_subagent.h>
22 #include <net/if_arp.h>
23
24 LONG H_NetIpForwarding(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session)
25 {
26 int nVer = CAST_FROM_POINTER(pArg, int);
27 int nRet = SYSINFO_RC_ERROR;
28 FILE *hFile;
29 const char *pFileName = NULL;
30
31 switch (nVer)
32 {
33 case 4:
34 pFileName = "/proc/sys/net/ipv4/conf/all/forwarding";
35 break;
36 case 6:
37 pFileName = "/proc/sys/net/ipv6/conf/all/forwarding";
38 break;
39 }
40
41 if (pFileName != NULL)
42 {
43 hFile = fopen(pFileName, "r");
44 if (hFile != NULL)
45 {
46 char szBuff[4];
47
48 if (fgets(szBuff, sizeof(szBuff), hFile) != NULL)
49 {
50 nRet = SYSINFO_RC_SUCCESS;
51 switch (szBuff[0])
52 {
53 case '0':
54 ret_int(pValue, 0);
55 break;
56 case '1':
57 ret_int(pValue, 1);
58 break;
59 default:
60 nRet = SYSINFO_RC_ERROR;
61 break;
62 }
63 }
64 fclose(hFile);
65 }
66 }
67
68 return nRet;
69 }
70
71 /**
72 * Handler for Net.ArpCache list
73 */
74 LONG H_NetArpCache(const TCHAR *pszParam, const TCHAR *pArg, StringList *pValue, AbstractCommSession *session)
75 {
76 int nRet = SYSINFO_RC_ERROR;
77 FILE *hFile;
78
79 hFile = fopen("/proc/net/arp", "r");
80 if (hFile != NULL)
81 {
82 char szBuff[256];
83 if (fgets(szBuff, sizeof(szBuff), hFile) != NULL) // skip first line
84 {
85 int nFd = socket(AF_INET, SOCK_DGRAM, 0);
86 if (nFd > 0)
87 {
88 nRet = SYSINFO_RC_SUCCESS;
89
90 while(fgets(szBuff, sizeof(szBuff), hFile) != NULL)
91 {
92 int nIP1, nIP2, nIP3, nIP4;
93 int nMAC1, nMAC2, nMAC3, nMAC4, nMAC5, nMAC6;
94 char szTmp1[256];
95 char szTmp2[256];
96 char szTmp3[256];
97 char szIf[256];
98
99 if (sscanf(szBuff,
100 "%d.%d.%d.%d %s %s %02X:%02X:%02X:%02X:%02X:%02X %s %s",
101 &nIP1, &nIP2, &nIP3, &nIP4,
102 szTmp1, szTmp2,
103 &nMAC1, &nMAC2, &nMAC3, &nMAC4, &nMAC5, &nMAC6,
104 szTmp3, szIf) == 14)
105 {
106 int nIndex;
107 struct ifreq irq;
108
109 if (nMAC1 == 0 && nMAC2 == 0 &&
110 nMAC3 == 0 && nMAC4 == 0 &&
111 nMAC5 == 0 && nMAC6 == 0)
112 {
113 // incomplete
114 continue;
115 }
116
117 strncpy(irq.ifr_name, szIf, IFNAMSIZ);
118 if (ioctl(nFd, SIOCGIFINDEX, &irq) != 0)
119 {
120 nIndex = 0;
121 }
122 else
123 {
124 nIndex = irq.ifr_ifindex;
125 }
126
127 TCHAR output[256];
128 _sntprintf(output, 256,
129 _T("%02X%02X%02X%02X%02X%02X %d.%d.%d.%d %d"),
130 nMAC1, nMAC2, nMAC3, nMAC4, nMAC5, nMAC6,
131 nIP1, nIP2, nIP3, nIP4,
132 nIndex);
133
134 pValue->add(output);
135 }
136 }
137 close(nFd);
138 }
139 }
140 fclose(hFile);
141 }
142
143 return nRet;
144 }
145
146 /**
147 * Handler for Net.IP.RoutingTable
148 */
149 LONG H_NetRoutingTable(const TCHAR *pszParam, const TCHAR *pArg, StringList *pValue, AbstractCommSession *session)
150 {
151 int nRet = SYSINFO_RC_ERROR;
152 FILE *hFile;
153 int nFd;
154
155 nFd = socket(AF_INET, SOCK_DGRAM, 0);
156 if (nFd <= 0)
157 {
158 return SYSINFO_RC_ERROR;
159 }
160
161 hFile = fopen("/proc/net/route", "r");
162 if (hFile == NULL)
163 {
164 close(nFd);
165 return SYSINFO_RC_ERROR;
166 }
167
168 char szLine[256];
169
170 if (fgets(szLine, sizeof(szLine), hFile) != NULL)
171 {
172 if (!strncmp(szLine,
173 "Iface\tDestination\tGateway \tFlags\tRefCnt\t"
174 "Use\tMetric\tMask", 55))
175 {
176 nRet = SYSINFO_RC_SUCCESS;
177
178 while(fgets(szLine, sizeof(szLine), hFile) != NULL)
179 {
180 char szIF[64];
181 int nTmp, nType = 0;
182 unsigned int nDestination, nGateway, nMask;
183
184 if (sscanf(szLine,
185 "%s\t%08X\t%08X\t%d\t%d\t%d\t%d\t%08X",
186 szIF,
187 &nDestination,
188 &nGateway,
189 &nTmp, &nTmp, &nTmp, &nTmp,
190 &nMask) == 8)
191 {
192 int nIndex;
193 struct ifreq irq;
194
195 strncpy(irq.ifr_name, szIF, IFNAMSIZ);
196 if (ioctl(nFd, SIOCGIFINDEX, &irq) != 0)
197 {
198 perror("ioctl()");
199 nIndex = 0;
200 }
201 else
202 {
203 nIndex = irq.ifr_ifindex;
204 }
205
206 TCHAR output[256], szBuf1[64], szBuf2[64];
207 _sntprintf(output, 256, _T("%s/%d %s %d %d"),
208 IpToStr(ntohl(nDestination), szBuf1),
209 BitsInMask(htonl(nMask)),
210 IpToStr(ntohl(nGateway), szBuf2),
211 nIndex,
212 nType);
213 pValue->add(output);
214 }
215 }
216 }
217 }
218
219 close(nFd);
220 fclose(hFile);
221
222 return nRet;
223 }
224
225 /**
226 * Send netlink message
227 */
228 static int SendMessage(int socket, unsigned short type)
229 {
230 sockaddr_nl kernel = {};
231 msghdr message = {};
232 iovec io;
233 NETLINK_REQ request = {};
234
235 kernel.nl_family = AF_NETLINK;
236
237 request.header.nlmsg_len = NLMSG_LENGTH(sizeof(rtgenmsg));
238 request.header.nlmsg_type = type;
239 request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
240 request.header.nlmsg_seq = 1;
241 request.header.nlmsg_pid = getpid();
242 //request.message.rtgen_family = AF_PACKET;
243 request.message.rtgen_family = AF_UNSPEC;
244
245 io.iov_base = &request;
246 io.iov_len = request.header.nlmsg_len;
247 message.msg_iov = &io;
248 message.msg_iovlen = 1;
249 message.msg_name = &kernel;
250 message.msg_namelen = sizeof(kernel);
251
252 return sendmsg(socket, (msghdr*) &message, 0);
253 }
254
255 /**
256 * Receive netlink message
257 */
258 static int ReceiveMessage(int socket, char *replyBuffer, size_t replyBufferSize)
259 {
260 iovec io;
261 msghdr reply = {};
262 sockaddr_nl kernel;
263
264 io.iov_base = replyBuffer;
265 io.iov_len = replyBufferSize;
266 kernel.nl_family = AF_NETLINK;
267 reply.msg_iov = &io;
268 reply.msg_iovlen = 1;
269 reply.msg_name = &kernel;
270 reply.msg_namelen = sizeof(kernel);
271
272 return recvmsg(socket, &reply, 0);
273 }
274
275 /**
276 * Interface type conversion table
277 */
278 static struct
279 {
280 int netlinkType;
281 int snmpType;
282 } s_ifTypeConversion[] =
283 {
284 { ARPHRD_ARCNET, IFTYPE_ARCNET },
285 { ARPHRD_ATM, IFTYPE_ATM },
286 { ARPHRD_DLCI, IFTYPE_FRDLCIENDPT },
287 { ARPHRD_ETHER, IFTYPE_ETHERNET_CSMACD },
288 { ARPHRD_EETHER, IFTYPE_ETHERNET_CSMACD },
289 { ARPHRD_FDDI, IFTYPE_FDDI },
290 { ARPHRD_IEEE1394, IFTYPE_IEEE1394 },
291 { ARPHRD_IEEE80211, IFTYPE_IEEE80211 },
292 { ARPHRD_IEEE80211_PRISM, IFTYPE_IEEE80211 },
293 { ARPHRD_IEEE80211_RADIOTAP, IFTYPE_IEEE80211 },
294 { ARPHRD_INFINIBAND, IFTYPE_INFINIBAND },
295 { ARPHRD_LOOPBACK, IFTYPE_SOFTWARE_LOOPBACK },
296 { ARPHRD_PPP, IFTYPE_PPP },
297 { ARPHRD_SLIP, IFTYPE_SLIP },
298 { ARPHRD_TUNNEL, IFTYPE_TUNNEL },
299 { ARPHRD_TUNNEL6, IFTYPE_TUNNEL },
300 { -1, -1 }
301 };
302
303 /**
304 * Parse interface information (RTM_NEWLINK) message
305 */
306 static LinuxInterfaceInfo *ParseInterfaceMessage(nlmsghdr *messageHeader)
307 {
308 LinuxInterfaceInfo *ifInfo = new LinuxInterfaceInfo();
309
310 struct ifinfomsg *interface = (ifinfomsg *)NLMSG_DATA(messageHeader);
311 int len = messageHeader->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
312
313 for(struct rtattr *attribute = IFLA_RTA(interface); RTA_OK(attribute, len); attribute = RTA_NEXT(attribute, len))
314 {
315 switch(attribute->rta_type)
316 {
317 case IFLA_IFNAME:
318 strncpy(ifInfo->name, (char *)RTA_DATA(attribute), sizeof(ifInfo->name));
319 break;
320 case IFLA_ADDRESS:
321 if (RTA_PAYLOAD(attribute) > 0)
322 {
323 memcpy(ifInfo->macAddr, (BYTE *)RTA_DATA(attribute), std::min(RTA_PAYLOAD(attribute), sizeof(ifInfo->macAddr)));
324 }
325 break;
326 case IFLA_MTU:
327 ifInfo->mtu = *((unsigned int *)RTA_DATA(attribute));
328 break;
329 }
330 }
331
332 ifInfo->index = interface->ifi_index;
333
334 ifInfo->type = IFTYPE_OTHER;
335 for(int i = 0; s_ifTypeConversion[i].netlinkType != -1; i++)
336 {
337 if (interface->ifi_type == s_ifTypeConversion[i].netlinkType)
338 {
339 ifInfo->type = s_ifTypeConversion[i].snmpType;
340 break;
341 }
342 }
343 return ifInfo;
344 }
345
346 /**
347 * Parse interface address (RTM_NEWADDR) message
348 */
349 static void ParseAddressMessage(nlmsghdr *messageHeader, ObjectArray<LinuxInterfaceInfo> *ifList)
350 {
351 struct ifaddrmsg *addrMsg = (struct ifaddrmsg *)NLMSG_DATA(messageHeader);
352 if ((addrMsg->ifa_family != AF_INET) && (addrMsg->ifa_family != AF_INET6))
353 return; // protocol not supported
354
355 // Find interface by index
356 LinuxInterfaceInfo *iface = NULL;
357 for(int i = 0; i < ifList->size(); i++)
358 {
359 if (ifList->get(i)->index == addrMsg->ifa_index)
360 {
361 iface = ifList->get(i);
362 break;
363 }
364 }
365 if (iface == NULL)
366 {
367 AgentWriteDebugLog(5, _T("ParseInterfaceMessage: cannot find interface with index %d"), addrMsg->ifa_index);
368 return; // interface not found
369 }
370
371 //int len = messageHeader->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
372 InetAddress *addr = NULL;
373 int len = IFA_PAYLOAD(messageHeader);
374 for(struct rtattr *attribute = IFA_RTA(addrMsg); RTA_OK(attribute, len); attribute = RTA_NEXT(attribute, len))
375 {
376 // Address may be given as IFA_ADDRESS or IFA_LOCAL
377 // We prefer IFA_LOCAL because it should be local address
378 // for point-to-point interfaces. For normal broadcast interfaces
379 // only IFA_ADDRESS may be set.
380 if ((attribute->rta_type == IFA_LOCAL) || (attribute->rta_type == IFA_ADDRESS))
381 {
382 delete addr; // if it was created from IFA_ADDRESS
383 addr = (addrMsg->ifa_family == AF_INET) ?
384 new InetAddress(ntohl(*((UINT32 *)RTA_DATA(attribute)))) :
385 new InetAddress((BYTE *)RTA_DATA(attribute));
386 if (attribute->rta_type == IFA_LOCAL)
387 break;
388 }
389 }
390
391 if (addr != NULL)
392 {
393 addr->setMaskBits(addrMsg->ifa_prefixlen);
394 iface->addrList.add(addr);
395 }
396 }
397
398 /**
399 * Get interface information
400 */
401 static ObjectArray<LinuxInterfaceInfo> *GetInterfaces()
402 {
403 int netlinkSocket = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
404 if (netlinkSocket == -1)
405 {
406 AgentWriteDebugLog(4, _T("GetInterfaces: failed to opens socket"));
407 return NULL;
408 }
409
410 setsockopt(netlinkSocket, SOL_SOCKET, SO_REUSEADDR, NULL, 0);
411
412 sockaddr_nl local = {};
413 local.nl_family = AF_NETLINK;
414 local.nl_pid = getpid();
415 local.nl_groups = 0;
416
417 bool done;
418 ObjectArray<LinuxInterfaceInfo> *ifList = NULL;
419
420 if (bind(netlinkSocket, (struct sockaddr *)&local, sizeof(local)) < 0)
421 {
422 AgentWriteDebugLog(4, _T("GetInterfaces: failed to bind socket"));
423 goto failure_1;
424 }
425
426 // Send request to read interface list
427 if (SendMessage(netlinkSocket, RTM_GETLINK) == -1)
428 {
429 AgentWriteDebugLog(4, _T("GetInterfaces: SendMessage(RTM_GETLINK) failed (%s)"), _tcserror(errno));
430 goto failure_1;
431 }
432
433 ifList = new ObjectArray<LinuxInterfaceInfo>(16, 16, true);
434
435 // Read and parse interface list
436 done = false;
437 while(!done)
438 {
439 char replyBuffer[8192];
440 int msgLen = ReceiveMessage(netlinkSocket, replyBuffer, sizeof(replyBuffer));
441 if (msgLen <= 0)
442 {
443 AgentWriteDebugLog(4, _T("GetInterfaces: ReceiveMessage failed (%s)"), _tcserror(errno));
444 goto failure_2;
445 }
446
447 for(struct nlmsghdr *msg_ptr = (struct nlmsghdr *)replyBuffer; NLMSG_OK(msg_ptr, msgLen); msg_ptr = NLMSG_NEXT(msg_ptr, msgLen))
448 {
449 if (msg_ptr->nlmsg_type == RTM_NEWLINK)
450 {
451 ifList->add(ParseInterfaceMessage(msg_ptr));
452 }
453 else if (msg_ptr->nlmsg_type == NLMSG_DONE)
454 {
455 done = true;
456 }
457 }
458 }
459
460 // Send request to read IP address list
461 if (SendMessage(netlinkSocket, RTM_GETADDR) == -1)
462 {
463 AgentWriteDebugLog(4, _T("GetInterfaces: SendMessage(RTM_GETADDR) failed (%s)"), _tcserror(errno));
464 goto failure_2;
465 }
466
467 // Read and parse address list
468 done = false;
469 while(!done)
470 {
471 char replyBuffer[8192];
472 int msgLen = ReceiveMessage(netlinkSocket, replyBuffer, sizeof(replyBuffer));
473 if (msgLen <= 0)
474 {
475 AgentWriteDebugLog(4, _T("GetInterfaces: ReceiveMessage failed (%s)"), _tcserror(errno));
476 goto failure_2;
477 }
478
479 for(struct nlmsghdr *msg_ptr = (struct nlmsghdr *)replyBuffer; NLMSG_OK(msg_ptr, msgLen); msg_ptr = NLMSG_NEXT(msg_ptr, msgLen))
480 {
481 if (msg_ptr->nlmsg_type == RTM_NEWADDR)
482 {
483 ParseAddressMessage(msg_ptr, ifList);
484 }
485 else if (msg_ptr->nlmsg_type == NLMSG_DONE)
486 {
487 done = true;
488 }
489 }
490 }
491
492 close(netlinkSocket);
493 return ifList;
494
495 failure_2:
496 delete ifList;
497
498 failure_1:
499 close(netlinkSocket);
500 return NULL;
501 }
502
503 /**
504 * Handler for Net.InterfaceList list
505 */
506 LONG H_NetIfList(const TCHAR* pszParam, const TCHAR* pArg, StringList* pValue, AbstractCommSession *session)
507 {
508 ObjectArray<LinuxInterfaceInfo> *ifList = GetInterfaces();
509 if (ifList == NULL)
510 {
511 AgentWriteDebugLog(4, _T("H_NetIfList: failed to get interface list"));
512 return SYSINFO_RC_ERROR;
513 }
514
515 TCHAR infoString[1024], macAddr[32], ipAddr[64];
516 for(int i = 0; i < ifList->size(); i++)
517 {
518 LinuxInterfaceInfo *iface = ifList->get(i);
519 if (iface->addrList.size() > 0)
520 {
521 for(int j = 0; j < iface->addrList.size(); j++)
522 {
523 const InetAddress *addr = iface->addrList.get(j);
524 if ((addr->getFamily() == AF_INET) || (session == NULL) || session->isIPv6Aware())
525 {
526 _sntprintf(infoString, 1024, _T("%d %s/%d %d %s %hs"),
527 iface->index,
528 addr->toString(ipAddr),
529 addr->getMaskBits(),
530 iface->type,
531 BinToStr(iface->macAddr, 6, macAddr),
532 iface->name);
533 pValue->add(infoString);
534 }
535 }
536 }
537 else
538 {
539 _sntprintf(infoString, 1024, _T("%d 0.0.0.0/0 %d %s %hs"),
540 iface->index,
541 iface->type,
542 BinToStr(iface->macAddr, 6, macAddr),
543 iface->name);
544 pValue->add(infoString);
545 }
546 }
547
548 delete ifList;
549 return SYSINFO_RC_SUCCESS;
550 }
551
552 /**
553 * Handler for Net.InterfaceNames list
554 */
555 LONG H_NetIfNames(const TCHAR* pszParam, const TCHAR* pArg, StringList* pValue, AbstractCommSession *session)
556 {
557 ObjectArray<LinuxInterfaceInfo> *ifList = GetInterfaces();
558 if (ifList == NULL)
559 {
560 AgentWriteDebugLog(4, _T("H_NetIfNames: failed to get interface list"));
561 return SYSINFO_RC_ERROR;
562 }
563
564 TCHAR infoString[1024], macAddr[32], ipAddr[64];
565 for(int i = 0; i < ifList->size(); i++)
566 {
567 #ifdef UNICODE
568 pValue->addPreallocated(WideStringFromMBString(ifList->get(i)->name));
569 #else
570 pValue->add(ifList->get(i)->name);
571 #endif
572 }
573
574 delete ifList;
575 return SYSINFO_RC_SUCCESS;
576 }
577
578 /**
579 * Handler for interface parameters (using ioctl)
580 */
581 LONG H_NetIfInfoFromIOCTL(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session)
582 {
583 char *eptr, szBuffer[256];
584 LONG nRet = SYSINFO_RC_SUCCESS;
585 struct ifreq ifr;
586 int fd;
587
588 if (!AgentGetParameterArgA(pszParam, 1, szBuffer, 256))
589 return SYSINFO_RC_UNSUPPORTED;
590
591 fd = socket(AF_INET, SOCK_DGRAM, 0);
592 if (fd == -1)
593 {
594 return 1;
595 }
596
597 // Check if we have interface name or index
598 ifr.ifr_ifindex = strtol(szBuffer, &eptr, 10);
599 if (*eptr == 0)
600 {
601 // Index passed as argument, convert to name
602 if (ioctl(fd, SIOCGIFNAME, &ifr) != 0)
603 nRet = SYSINFO_RC_ERROR;
604 }
605 else
606 {
607 // Name passed as argument
608 strncpy(ifr.ifr_name, szBuffer, IFNAMSIZ);
609 }
610
611 // Get interface information
612 if (nRet == SYSINFO_RC_SUCCESS)
613 {
614 switch ((long) pArg)
615 {
616 case IF_INFO_ADMIN_STATUS:
617 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
618 {
619 ret_int(pValue, (ifr.ifr_flags & IFF_UP) ? 1 : 2);
620 }
621 else
622 {
623 nRet = SYSINFO_RC_ERROR;
624 }
625 break;
626 case IF_INFO_OPER_STATUS:
627 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
628 {
629 // IFF_RUNNING should be set only if interface can
630 // transmit/receive data, but in fact looks like it
631 // always set. I have unverified information that
632 // newer kernels set this flag correctly.
633 ret_int(pValue, (ifr.ifr_flags & IFF_RUNNING) ? 1 : 0);
634 }
635 else
636 {
637 nRet = SYSINFO_RC_ERROR;
638 }
639 break;
640 case IF_INFO_DESCRIPTION:
641 ret_mbstring(pValue, ifr.ifr_name);
642 break;
643 default:
644 nRet = SYSINFO_RC_UNSUPPORTED;
645 break;
646 }
647 }
648
649 // Cleanup
650 close(fd);
651 return nRet;
652 }
653
654 /**
655 * Extract 32 bit value from line
656 */
657 static LONG ValueFromLine(char *pszLine, int nPos, TCHAR *pValue)
658 {
659 int i;
660 char *eptr, szBuffer[256];
661 const char *pszWord;
662 LONG nRet = SYSINFO_RC_ERROR;
663
664 for(i = 0, pszWord = pszLine; i <= nPos; i++)
665 pszWord = ExtractWordA(pszWord, szBuffer);
666
667 // On 64 bit systems interface counters are 64 bit
668 #if SIZEOF_LONG > 4
669 UINT32 value = (UINT32)(strtoull(szBuffer, &eptr, 0) & _ULL(0xFFFFFFFF));
670 #else
671 UINT32 value = strtoul(szBuffer, &eptr, 0);
672 #endif
673 if (*eptr == 0)
674 {
675 ret_uint(pValue, value);
676 nRet = SYSINFO_RC_SUCCESS;
677 }
678 return nRet;
679 }
680
681 /**
682 * Extract 64 bit value from line
683 */
684 static LONG ValueFromLine64(char *pszLine, int nPos, TCHAR *pValue)
685 {
686 int i;
687 char *eptr, szBuffer[256];
688 const char *pszWord;
689 LONG nRet = SYSINFO_RC_ERROR;
690
691 for(i = 0, pszWord = pszLine; i <= nPos; i++)
692 pszWord = ExtractWordA(pszWord, szBuffer);
693
694 UINT64 value = strtoull(szBuffer, &eptr, 0);
695 if (*eptr == 0)
696 {
697 ret_uint64(pValue, value);
698 nRet = SYSINFO_RC_SUCCESS;
699 }
700 return nRet;
701 }
702
703 /**
704 * Handler for interface parameters (using /proc file system)
705 */
706 LONG H_NetIfInfoFromProc(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session)
707 {
708 char *ptr, szBuffer[256], szName[IFNAMSIZ];
709 LONG nIndex, nRet = SYSINFO_RC_SUCCESS;
710 FILE *fp;
711
712 if (!AgentGetParameterArgA(pszParam, 1, szBuffer, 256))
713 return SYSINFO_RC_UNSUPPORTED;
714
715 // Check if we have interface name or index
716 nIndex = strtol(szBuffer, &ptr, 10);
717 if (*ptr == 0)
718 {
719 // Index passed as argument, convert to name
720 if (if_indextoname(nIndex, szName) == NULL)
721 nRet = SYSINFO_RC_ERROR;
722 }
723 else
724 {
725 // Name passed as argument
726 strncpy(szName, szBuffer, IFNAMSIZ);
727 }
728
729 // Get interface information
730 if (nRet == SYSINFO_RC_SUCCESS)
731 {
732 // If name is an alias (i.e. eth0:1), remove alias number
733 ptr = strchr(szName, ':');
734 if (ptr != NULL)
735 *ptr = 0;
736
737 fp = fopen("/proc/net/dev", "r");
738 if (fp != NULL)
739 {
740 while(1)
741 {
742 char *ret = fgets(szBuffer, 256, fp);
743 if (ret == NULL || feof(fp))
744 {
745 nRet = SYSINFO_RC_ERROR; // Interface record not found
746 break;
747 }
748
749 // We expect line in form interface:stats
750 StrStripA(szBuffer);
751 ptr = strchr(szBuffer, ':');
752 if (ptr == NULL)
753 continue;
754 *ptr = 0;
755
756 if (!stricmp(szBuffer, szName))
757 {
758 ptr++;
759 break;
760 }
761 }
762 fclose(fp);
763 }
764 else
765 {
766 nRet = SYSINFO_RC_ERROR;
767 }
768
769 if (nRet == SYSINFO_RC_SUCCESS)
770 {
771 StrStripA(ptr);
772 switch ((long) pArg)
773 {
774 case IF_INFO_BYTES_IN:
775 nRet = ValueFromLine(ptr, 0, pValue);
776 break;
777 case IF_INFO_BYTES_IN_64:
778 nRet = ValueFromLine64(ptr, 0, pValue);
779 break;
780 case IF_INFO_PACKETS_IN:
781 nRet = ValueFromLine(ptr, 1, pValue);
782 break;
783 case IF_INFO_PACKETS_IN_64:
784 nRet = ValueFromLine64(ptr, 1, pValue);
785 break;
786 case IF_INFO_ERRORS_IN:
787 nRet = ValueFromLine(ptr, 2, pValue);
788 break;
789 case IF_INFO_ERRORS_IN_64:
790 nRet = ValueFromLine64(ptr, 2, pValue);
791 break;
792 case IF_INFO_BYTES_OUT:
793 nRet = ValueFromLine(ptr, 8, pValue);
794 break;
795 case IF_INFO_BYTES_OUT_64:
796 nRet = ValueFromLine64(ptr, 8, pValue);
797 break;
798 case IF_INFO_PACKETS_OUT:
799 nRet = ValueFromLine(ptr, 9, pValue);
800 break;
801 case IF_INFO_PACKETS_OUT_64:
802 nRet = ValueFromLine64(ptr, 9, pValue);
803 break;
804 case IF_INFO_ERRORS_OUT:
805 nRet = ValueFromLine(ptr, 10, pValue);
806 break;
807 case IF_INFO_ERRORS_OUT_64:
808 nRet = ValueFromLine64(ptr, 10, pValue);
809 break;
810 default:
811 nRet = SYSINFO_RC_UNSUPPORTED;
812 break;
813 }
814 }
815 }
816
817 return nRet;
818 }