500b4d22f9cdee02ef58e0ee3931378a54cc6c53
[public/netxms.git] / src / agent / subagents / ipso / net.cpp
1 /* $Id$ */
2
3 /*
4 ** NetXMS subagent for FreeBSD
5 ** Copyright (C) 2004 Alex Kirhenshtein
6 **
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation; either version 2 of the License, or
10 ** (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 **
21 **/
22
23 #include "ipso.h"
24 #include <sys/file.h>
25 #include <sys/sysctl.h>
26 #include <sys/sockio.h>
27 #include <net/if.h>
28 #include <net/if_media.h>
29 #include <net/if_dl.h>
30 #include <net/if_types.h>
31 #include <net/route.h>
32 #include <netinet/if_ether.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <net/ethernet.h>
36
37
38 //
39 // Internal data structures
40 //
41
42 #define MAX_IF_NAME 128
43
44 typedef struct t_IfData
45 {
46 char szName[MAX_IF_NAME];
47 LONG nIndex;
48 LONG nType;
49 char szMacAddr[24];
50 BOOL isLogical;
51 char szPhysIfName[MAX_IF_NAME];
52 int nAddrCount;
53 char szIpAddr[16];
54 int nMask;
55 } IFDATA;
56
57 typedef struct t_IfList
58 {
59 int nSize;
60 IFDATA *pData;
61 int nHandle;
62 int nCurr;
63 } IFLIST;
64
65 typedef struct t_cbp
66 {
67 int nHandle;
68 NETXMS_VALUES_LIST *pList;
69 } CBP;
70
71
72 //
73 // Index to name resolution callback parameters
74 //
75
76 typedef struct
77 {
78 int nHandle;
79 int nIndex;
80 char *pszName;
81 char *pszResult;
82 } IRPARAM;
83
84
85 //
86 // Callback for index to name resolution
87 //
88
89 static void IndexCallback(char *pszPath, IRPARAM *pArg)
90 {
91 char *ptr, szCtl[256];
92 LONG nIndex;
93
94 snprintf(szCtl, 256, "%s:index", pszPath);
95 if (IPSCTLGetInt(pArg->nHandle, szCtl, &nIndex) == SYSINFO_RC_SUCCESS)
96 {
97 if (nIndex == pArg->nIndex)
98 {
99 ptr = strrchr(pszPath, ':');
100 if (ptr != NULL)
101 ptr++;
102 else
103 ptr = pszPath;
104 nx_strncpy(pArg->pszName, ptr, MAX_IF_NAME);
105 pArg->pszResult = pArg->pszName;
106 }
107 }
108 }
109
110
111 //
112 // Convert logical interface index to name
113 //
114
115 static char *IndexToName(int nIndex, char *pszName, BOOL *pbIsLogical)
116 {
117 IRPARAM data;
118
119 if (nIndex >= 0x01000000)
120 {
121 *pbIsLogical = TRUE;
122 return if_indextoname(nIndex - 0x01000000, pszName);
123 }
124
125 *pbIsLogical = FALSE;
126
127 data.pszResult = NULL;
128 data.nHandle = ipsctl_open();
129 if (data.nHandle > 0)
130 {
131 data.nIndex = nIndex;
132 data.pszName = pszName;
133 ipsctl_iterate(data.nHandle, "ifphys", IndexCallback, &data);
134 ipsctl_close(data.nHandle);
135 }
136 return data.pszResult;
137 }
138
139
140 //
141 // Handler for Net.IP.Forwarding parameter
142 //
143
144 LONG H_NetIpForwarding(char *pszParam, char *pArg, char *pValue)
145 {
146 int nVer = (int)pArg;
147 int nRet = SYSINFO_RC_ERROR;
148 LONG nVal;
149
150 if (nVer == 6)
151 {
152 return ERR_NOT_IMPLEMENTED;
153 }
154
155 nRet = IPSCTLGetInt(0, "net:ip:forward:noforwarding", &nVal);
156 if (nRet == SYSINFO_RC_SUCCESS)
157 ret_int(pValue, !nVal);
158
159 return nRet;
160 }
161
162
163 //
164 // Handler for Net.Interface.XXX parameters
165 //
166
167 LONG H_NetIfStats(char *pszParam, char *pArg, char *pValue)
168 {
169 LONG nTemp, nRet = SYSINFO_RC_SUCCESS;
170 char szName[MAX_IF_NAME], szRequest[256];
171 BOOL isLogical;
172 static char *pszRqListLog[] =
173 {
174 "interface:%s:name",
175 "interface:%s:flags:link_avail",
176 "interface:%s:flags:up",
177 "interface:%s:stats:ibytes",
178 "interface:%s:stats:obytes",
179 "interface:%s:stats:ipackets",
180 "interface:%s:stats:opackets"
181 };
182 static char *pszRqListPhy[] =
183 {
184 "ifphys:%s:dev_type",
185 "ifphys:%s:flags:link",
186 "ifphys:%s:flags:up",
187 "ifphys:%s:stats:ibytes",
188 "ifphys:%s:stats:obytes",
189 "ifphys:%s:stats:ipackets",
190 "ifphys:%s:stats:opackets"
191 };
192
193 if (!NxGetParameterArg(pszParam, 1, szName, sizeof(szName)))
194 return SYSINFO_RC_UNSUPPORTED;
195
196 if (szName[0] != 0)
197 {
198 // Convert interface index to name if needed
199 if (szName[0] >= '0' && szName[0] <= '9')
200 {
201 // index
202 if (IndexToName(atoi(szName), szName, &isLogical) != szName)
203 {
204 // not found
205 nRet = SYSINFO_RC_ERROR;
206 }
207 }
208 else
209 {
210 // Check if interface is physical or logical
211 snprintf(szRequest, sizeof(szRequest), "ifphys:%s:index", szName);
212 isLogical = (IPSCTLGetInt(0, szRequest, &nTemp) == SYSINFO_RC_SUCCESS) ? FALSE : TRUE;
213 }
214
215 if (nRet == SYSINFO_RC_SUCCESS)
216 {
217 snprintf(szRequest, sizeof(szRequest),
218 isLogical ? pszRqListLog[(int)pArg] : pszRqListPhy[(int)pArg],
219 szName);
220 nRet = IPSCTLGetString(0, szRequest, pValue, MAX_RESULT_LENGTH);
221 }
222 }
223 else
224 {
225 nRet = SYSINFO_RC_UNSUPPORTED;
226 }
227
228 return nRet;
229 }
230
231
232 //
233 // Callback for ARP cache enumeration
234 //
235
236 static void ArpCallback(char *pszPath, CBP *pArg)
237 {
238 char *ptr, szBuffer[1024], szMacAddr[32], szIfName[MAX_IF_NAME];
239
240 snprintf(szBuffer, 1024, "%s:macaddr", pszPath);
241 if (IPSCTLGetString(pArg->nHandle, szBuffer, szMacAddr, 32) != SYSINFO_RC_SUCCESS)
242 return;
243
244 snprintf(szBuffer, 1024, "%s:ifname", pszPath);
245 if (IPSCTLGetString(pArg->nHandle, szBuffer, szIfName, MAX_IF_NAME) != SYSINFO_RC_SUCCESS)
246 return;
247
248 ptr = strrchr(pszPath, ':');
249 if (ptr == NULL)
250 return;
251 ptr++;
252
253 TranslateStr(szMacAddr, ":", "");
254 snprintf(szBuffer, 1024, "%s %s %d", szMacAddr, ptr,
255 if_nametoindex(szIfName) + 0x01000000);
256 NxAddResultString(pArg->pList, szBuffer);
257 }
258
259
260 //
261 // Handler for Net.ArpCache enum
262 //
263
264 LONG H_NetArpCache(char *pszParam, char *pArg, NETXMS_VALUES_LIST *pValue)
265 {
266 LONG nRet = SYSINFO_RC_ERROR;
267 CBP data;
268
269 data.nHandle = ipsctl_open();
270 if (data.nHandle > 0)
271 {
272 data.pList = pValue;
273 if (ipsctl_iterate(data.nHandle, "net:ip:arp:entry", ArpCallback, &data) == 0)
274 nRet = SYSINFO_RC_SUCCESS;
275 ipsctl_close(data.nHandle);
276 }
277
278 return nRet;
279 }
280
281 LONG H_NetRoutingTable(char *pszParam, char *pArg, NETXMS_VALUES_LIST *pValue)
282 {
283 #define sa2sin(x) ((struct sockaddr_in *)x)
284 #define ROUNDUP(a) \
285 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
286 int nRet = SYSINFO_RC_ERROR;
287 int mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0 };
288 char *pRT = NULL, *pNext = NULL;
289 size_t nReqSize = 0;
290 struct rt_msghdr *rtm;
291 struct sockaddr *sa;
292 struct sockaddr *rti_info[RTAX_MAX];
293
294 if (sysctl(mib, 6, NULL, &nReqSize, NULL, 0) == 0)
295 {
296 if (nReqSize > 0)
297 {
298 pRT = (char *)malloc(nReqSize);
299 if (pRT != NULL)
300 {
301 if (sysctl(mib, 6, pRT, &nReqSize, NULL, 0) < 0)
302 {
303 free(pRT);
304 pRT = NULL;
305 }
306 }
307 }
308 }
309
310 if (pRT != NULL)
311 {
312 nRet = SYSINFO_RC_SUCCESS;
313
314 for (pNext = pRT; pNext < pRT + nReqSize; pNext += rtm->rtm_msglen)
315 {
316 rtm = (struct rt_msghdr *)pNext;
317 sa = (struct sockaddr *)(rtm + 1);
318
319 if (sa->sa_family != AF_INET)
320 {
321 continue;
322 }
323
324 for (int i = 0; i < RTAX_MAX; i++)
325 {
326 if (rtm->rtm_addrs & (1 << i))
327 {
328 rti_info[i] = sa;
329 sa = (struct sockaddr *)((char *)(sa) + ROUNDUP(sa->sa_len));
330 }
331 else
332 {
333 rti_info[i] = NULL;
334 }
335 }
336
337 if (rti_info[RTAX_DST] != NULL && !(rtm->rtm_flags & RTF_WASCLONED))
338 {
339 char szOut[1024];
340 char szTmp[64];
341
342 if (sa2sin(rti_info[RTAX_DST])->sin_addr.s_addr == INADDR_ANY)
343 {
344 strcpy(szOut, "0.0.0.0/0 ");
345 }
346 else
347 {
348 if ((rtm->rtm_flags & RTF_HOST) || rti_info[RTAX_NETMASK]==NULL)
349 {
350 // host
351 strcpy(szOut,
352 inet_ntoa(sa2sin(rti_info[RTAX_DST])->sin_addr));
353 strcat(szOut, "/32 ");
354 }
355 else
356 {
357 // net
358 int nMask =
359 rti_info[RTAX_NETMASK] ?
360 ntohl(sa2sin(rti_info[RTAX_NETMASK])->sin_addr.s_addr)
361 : 0;
362
363 sprintf(szOut, "%s/%d ",
364 inet_ntoa(sa2sin(rti_info[RTAX_DST])->sin_addr),
365 nMask ? 33 - ffs(nMask) : 0);
366 }
367 }
368
369 if (rti_info[RTAX_GATEWAY]->sa_family != AF_INET)
370 {
371 strcat(szOut, "0.0.0.0 ");
372 }
373 else
374 {
375 strcat(szOut,
376 inet_ntoa(sa2sin(rti_info[RTAX_GATEWAY])->sin_addr));
377 strcat(szOut, " ");
378 }
379 snprintf(szTmp, sizeof(szTmp), "%d %d",
380 rtm->rtm_index,
381 (rtm->rtm_flags & RTF_GATEWAY) == 0 ? 3 : 4);
382 strcat(szOut, szTmp);
383
384 NxAddResultString(pValue, szOut);
385 }
386 }
387
388 free(pRT);
389 }
390
391 #undef ROUNDUP
392 #undef sa2sin
393
394 return nRet;
395 }
396
397
398 //
399 // Callback for physical interface enumeration
400 //
401
402 static void PhysicalIfCallback(char *pszPath, IFLIST *pList)
403 {
404 char *ptr, szCtl[256], szBuffer[256];
405 IFDATA *pCurr;
406
407 // Extract interface name from path
408 ptr = strrchr(pszPath, ':');
409 if (ptr == NULL) // Should never happen
410 ptr = pszPath;
411 else
412 ptr++;
413
414 // Allocate new interface data structure
415 pList->pData = (IFDATA *)realloc(pList->pData, sizeof(IFDATA) * (pList->nSize + 1));
416 pCurr = &pList->pData[pList->nSize];
417 memset(pCurr, 0, sizeof(IFDATA));
418 pList->nSize++;
419
420 // Fill interface data
421 nx_strncpy(pCurr->szName, ptr, MAX_IF_NAME);
422 strcpy(pCurr->szIpAddr, "0.0.0.0");
423
424 // Interface index
425 snprintf(szCtl, 256, "%s:index", pszPath);
426 IPSCTLGetInt(pList->nHandle, szCtl, &pCurr->nIndex);
427
428 // Interface type
429 snprintf(szCtl, 256, "%s:type", pszPath);
430 if (IPSCTLGetString(pList->nHandle, szCtl, szBuffer, 256) == SYSINFO_RC_SUCCESS)
431 {
432 if (!strcmp(szBuffer, "ethernet"))
433 pCurr->nType = IFTYPE_ETHERNET_CSMACD;
434 else if (!strcmp(szBuffer, "loopback"))
435 pCurr->nType = IFTYPE_SOFTWARE_LOOPBACK;
436 else if (!strcmp(szBuffer, "pppoe"))
437 pCurr->nType = IFTYPE_EON;
438 else
439 pCurr->nType = IFTYPE_OTHER;
440 }
441 else
442 {
443 pCurr->nType = IFTYPE_OTHER;
444 }
445
446 // MAC address
447 snprintf(szCtl, 256, "%s:macaddr", pszPath);
448 IPSCTLGetString(pList->nHandle, szCtl, pCurr->szMacAddr, 24);
449 TranslateStr(pCurr->szMacAddr, ":", "");
450 }
451
452
453 //
454 // Callback for logical interface enumeration
455 //
456
457 static void LogicalIfCallback(char *pszPath, IFLIST *pList)
458 {
459 char *ptr, szCtl[256], szBuffer[256];
460 IFDATA *pCurr;
461
462 // Extract interface name from path
463 ptr = strrchr(pszPath, ':');
464 if (ptr == NULL) // Should never happen
465 ptr = pszPath;
466 else
467 ptr++;
468
469 // Allocate new interface data structure
470 pList->pData = (IFDATA *)realloc(pList->pData, sizeof(IFDATA) * (pList->nSize + 1));
471 pCurr = &pList->pData[pList->nSize];
472 memset(pCurr, 0, sizeof(IFDATA));
473 pList->nSize++;
474
475 // Fill interface data
476 nx_strncpy(pCurr->szName, ptr, MAX_IF_NAME);
477 pCurr->isLogical = TRUE;
478
479 // Interface index
480 snprintf(szCtl, 256, "%s:index", pszPath);
481 IPSCTLGetInt(pList->nHandle, szCtl, &pCurr->nIndex);
482 pCurr->nIndex += 0x01000000;
483
484 // Get underlaying physical interface
485 snprintf(szCtl, 256, "%s:phys", pszPath);
486 IPSCTLGetString(pList->nHandle, szCtl, pCurr->szPhysIfName, MAX_IF_NAME);
487
488 // Interface type
489 snprintf(szCtl, 256, "ifphys:%s:type", pCurr->szPhysIfName);
490 if (IPSCTLGetString(pList->nHandle, szCtl, szBuffer, 256) == SYSINFO_RC_SUCCESS)
491 {
492 if (!strcmp(szBuffer, "ethernet"))
493 pCurr->nType = IFTYPE_ETHERNET_CSMACD;
494 else if (!strcmp(szBuffer, "loopback"))
495 pCurr->nType = IFTYPE_SOFTWARE_LOOPBACK;
496 else if (!strcmp(szBuffer, "pppoe"))
497 pCurr->nType = IFTYPE_EON;
498 else
499 pCurr->nType = IFTYPE_OTHER;
500 }
501 else
502 {
503 pCurr->nType = IFTYPE_OTHER;
504 }
505
506 // MAC address
507 snprintf(szCtl, 256, "ifphys:%s:macaddr", pCurr->szPhysIfName);
508 IPSCTLGetString(pList->nHandle, szCtl, pCurr->szMacAddr, 24);
509 TranslateStr(pCurr->szMacAddr, ":", "");
510 }
511
512
513 //
514 // Callback for IP address enumeration
515 //
516
517 static void IpAddrCallback(char *pszPath, IFLIST *pList)
518 {
519 IFDATA *pCurr;
520 struct ipsctl_value *pValue;
521 char *ptr, szCtl[256];
522
523 if (pList->pData[pList->nCurr].szIpAddr[0] != 0)
524 {
525 // Interface already has IP address, create additional entry
526 pList->pData = (IFDATA *)realloc(pList->pData, sizeof(IFDATA) * (pList->nSize + 1));
527 pCurr = &pList->pData[pList->nSize];
528 memcpy(pCurr, &pList->pData[pList->nCurr], sizeof(IFDATA));
529 pList->nSize++;
530 }
531 else
532 {
533 pCurr = &pList->pData[pList->nCurr];
534 }
535
536 ptr = strrchr(pszPath, ':');
537 if (ptr != NULL)
538 ptr++;
539 else
540 ptr = pszPath;
541 nx_strncpy(pCurr->szIpAddr, ptr, 16);
542
543 snprintf(szCtl, 256, "%s:dest", pszPath);
544 if (ipsctl_get(pList->nHandle, szCtl, &pValue) == 0)
545 {
546 pCurr->nMask = pValue->data.ipAddr.nMaskBits;
547 }
548 }
549
550
551 //
552 // Handler for Net.InterfaceList enum
553 //
554
555 LONG H_NetIfList(char *pszParam, char *pArg, NETXMS_VALUES_LIST *pValue)
556 {
557 int i, nSize, nHandle;
558 IFLIST ifList;
559 char szBuffer[1024];
560 LONG nRet = SYSINFO_RC_ERROR;
561
562 nHandle = ipsctl_open();
563 if (nHandle > 0)
564 {
565 ifList.nSize = 0;
566 ifList.pData = NULL;
567 ifList.nHandle = nHandle;
568 if ((ipsctl_iterate(nHandle, "ifphys",
569 PhysicalIfCallback, &ifList) == 0) &&
570 (ipsctl_iterate(nHandle, "interface",
571 LogicalIfCallback, &ifList) == 0))
572 {
573 nRet = SYSINFO_RC_SUCCESS;
574
575 // Gather IP addresses
576 nSize = ifList.nSize;
577 for(i = 0; i < nSize; i++)
578 {
579 if (ifList.pData[i].isLogical)
580 {
581 sprintf(szBuffer, "interface:%s:family:inet:addr",
582 ifList.pData[i].szName);
583 ifList.nCurr = i;
584 ipsctl_iterate(nHandle, szBuffer, IpAddrCallback, &ifList);
585 if (ifList.pData[i].szIpAddr[0] == 0)
586 strcpy(ifList.pData[i].szIpAddr, "0.0.0.0");
587 }
588 }
589
590 for(i = 0; i < ifList.nSize; i++)
591 {
592 sprintf(szBuffer, "%d %s/%d %d %s %s", ifList.pData[i].nIndex,
593 ifList.pData[i].szIpAddr, ifList.pData[i].nMask,
594 ifList.pData[i].nType, ifList.pData[i].szMacAddr,
595 ifList.pData[i].szName);
596 NxAddResultString(pValue, szBuffer);
597 }
598 }
599 ipsctl_close(nHandle);
600 }
601
602 return nRet;
603 }
604
605 ///////////////////////////////////////////////////////////////////////////////
606 /*
607
608 $Log: not supported by cvs2svn $
609 Revision 1.3 2006/08/16 22:26:09 victor
610 - Most of Net.Interface.XXX functions implemented on IPSO
611 - Added function MACToStr
612
613 Revision 1.2 2006/07/21 16:22:44 victor
614 Some parameters are working
615
616 Revision 1.1 2006/07/21 11:48:35 victor
617 Initial commit
618
619 */