imported svn:keywords properties
[public/netxms.git] / src / agent / subagents / freebsd / 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 <nms_common.h>
24 #include <nms_agent.h>
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/file.h>
29 #include <sys/socket.h>
30 #include <sys/sysctl.h>
31 #include <sys/sockio.h>
32 #include <net/if.h>
33 #include <net/if_media.h>
34 #include <net/if_dl.h>
35 #include <net/if_types.h>
36 #include <net/route.h>
37 #include <net/iso88025.h>
38 #include <netinet/if_ether.h>
39 #include <netinet/in.h>
40 #include <ifaddrs.h>
41 #include <arpa/inet.h>
42 #include <net/ethernet.h>
43
44 typedef struct t_Addr
45 {
46 struct in_addr ip;
47 int mask;
48 } ADDR;
49
50 typedef struct t_IfList
51 {
52 char *name;
53 struct ether_addr *mac;
54 ADDR *addr;
55 int addrCount;
56 int index;
57 } IFLIST;
58
59 LONG H_NetIpForwarding(char *pszParam, char *pArg, char *pValue)
60 {
61 int nVer = (int)pArg;
62 int nRet = SYSINFO_RC_ERROR;
63 int mib[4];
64 size_t nSize = sizeof(mib), nValSize;
65 int nVal;
66
67 if (nVer == 6)
68 {
69 return ERR_NOT_IMPLEMENTED;
70 }
71
72 if (sysctlnametomib("net.inet.ip.forwarding", mib, &nSize) != 0)
73 {
74 return SYSINFO_RC_ERROR;
75 }
76
77 nValSize = sizeof(nVal);
78 if (sysctl(mib, nSize, &nVal, &nValSize, NULL, 0) == 0)
79 {
80 if (nVal == 0 || nVal == 1)
81 {
82 ret_int(pValue, nVal);
83 nRet = SYSINFO_RC_SUCCESS;
84 }
85 }
86
87 return nRet;
88 }
89
90 LONG H_NetIfAdmStatus(char *pszParam, char *pArg, char *pValue)
91 {
92 int nRet = SYSINFO_RC_SUCCESS;
93 char szArg[512];
94
95 NxGetParameterArg(pszParam, 1, szArg, sizeof(szArg));
96
97 if (szArg[0] != 0)
98 {
99 if (szArg[0] >= '0' && szArg[0] <= '9')
100 {
101 // index
102 if (if_indextoname(atoi(szArg), szArg) != szArg)
103 {
104 // not found
105 nRet = SYSINFO_RC_ERROR;
106 }
107 }
108
109 if (nRet == SYSINFO_RC_SUCCESS)
110 {
111 int nSocket;
112
113 nRet = SYSINFO_RC_ERROR;
114
115 nSocket = socket(AF_INET, SOCK_DGRAM, 0);
116 if (nSocket > 0)
117 {
118 struct ifreq ifr;
119 int flags;
120
121 memset(&ifr, 0, sizeof(ifr));
122 nx_strncpy(ifr.ifr_name, szArg, sizeof(ifr.ifr_name));
123 if (ioctl(nSocket, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0)
124 {
125 flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
126 if ((flags & IFF_UP) == IFF_UP)
127 {
128 // enabled
129 ret_int(pValue, 1);
130 nRet = SYSINFO_RC_SUCCESS;
131 }
132 else
133 {
134 ret_int(pValue, 2);
135 nRet = SYSINFO_RC_SUCCESS;
136 }
137 }
138 close(nSocket);
139 }
140 }
141 }
142
143 return nRet;
144 }
145
146 LONG H_NetIfLink(char *pszParam, char *pArg, char *pValue)
147 {
148 int nRet = SYSINFO_RC_SUCCESS;
149 char szArg[512];
150
151 NxGetParameterArg(pszParam, 1, szArg, sizeof(szArg));
152
153 if (szArg[0] != 0)
154 {
155 if (szArg[0] >= '0' && szArg[0] <= '9')
156 {
157 // index
158 if (if_indextoname(atoi(szArg), szArg) != szArg)
159 {
160 // not found
161 nRet = SYSINFO_RC_ERROR;
162 }
163 }
164
165 if (nRet == SYSINFO_RC_SUCCESS)
166 {
167 int nSocket;
168
169 nRet = SYSINFO_RC_ERROR;
170
171 nSocket = socket(AF_INET, SOCK_DGRAM, 0);
172 if (nSocket > 0)
173 {
174 struct ifmediareq ifmr;
175
176 memset(&ifmr, 0, sizeof(ifmr));
177 nx_strncpy(ifmr.ifm_name, szArg, sizeof(ifmr.ifm_name));
178 if (ioctl(nSocket, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0)
179 {
180 if ((ifmr.ifm_status & IFM_AVALID) == IFM_AVALID &&
181 (ifmr.ifm_status & IFM_ACTIVE) == IFM_ACTIVE)
182 {
183 ret_int(pValue, 1);
184 nRet = SYSINFO_RC_SUCCESS;
185 }
186 else
187 {
188 ret_int(pValue, 0);
189 nRet = SYSINFO_RC_SUCCESS;
190 }
191 }
192 close(nSocket);
193 }
194 }
195 }
196
197 return nRet;
198 }
199
200 LONG H_NetArpCache(char *pszParam, char *pArg, NETXMS_VALUES_LIST *pValue)
201 {
202 int nRet = SYSINFO_RC_ERROR;
203 FILE *hFile;
204 int mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO };
205 size_t nNeeded;
206 char *pNext, *pBuff;
207 struct rt_msghdr *pRtm = NULL;
208 struct sockaddr_inarp *pSin;
209 struct sockaddr_dl *pSdl;
210 char *pLim;
211
212 if (sysctl(mib, 6, NULL, &nNeeded, NULL, 0) != 0)
213 {
214 return SYSINFO_RC_ERROR;
215 }
216 if ((pBuff = (char *)malloc(nNeeded)) == NULL)
217 {
218 return SYSINFO_RC_ERROR;
219 }
220 if (sysctl(mib, 6, pBuff, &nNeeded, NULL, 0) != 0)
221 {
222 return SYSINFO_RC_ERROR;
223 }
224
225 nRet = SYSINFO_RC_SUCCESS;
226 pLim = pBuff + nNeeded;
227 for (pNext = pBuff; pNext < pLim; pNext += pRtm->rtm_msglen)
228 {
229 char szBuff[256];
230 struct ether_addr *pEa;
231
232 pRtm = (struct rt_msghdr *)pNext;
233 pSin = (struct sockaddr_inarp *)(pRtm + 1);
234
235 pSdl = (struct sockaddr_dl *)((char *)pSin + (pSin->sin_len > 0
236 ?
237 (1 + ((pSin->sin_len - 1) | (sizeof(long) - 1)))
238 :
239 sizeof(long))
240 );
241
242 if (pSdl->sdl_alen != 6)
243 {
244 continue;
245 }
246
247 pEa = (struct ether_addr *)LLADDR(pSdl);
248
249 if (memcmp(pEa->octet, "\377\377\377\377\377\377", 6) == 0)
250 {
251 // broadcast
252 continue;
253 }
254
255 snprintf(szBuff, sizeof(szBuff),
256 "%02X%02X%02X%02X%02X%02X %s %d",
257 pEa->octet[0], pEa->octet[1],
258 pEa->octet[2], pEa->octet[3],
259 pEa->octet[4], pEa->octet[5],
260 inet_ntoa(pSin->sin_addr),
261 pSdl->sdl_index);
262
263 NxAddResultString(pValue, szBuff);
264 }
265
266 return nRet;
267 }
268
269 LONG H_NetRoutingTable(char *pszParam, char *pArg, NETXMS_VALUES_LIST *pValue)
270 {
271 #define sa2sin(x) ((struct sockaddr_in *)x)
272 #define ROUNDUP(a) \
273 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
274 int nRet = SYSINFO_RC_ERROR;
275 int mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0 };
276 char *pRT = NULL, *pNext = NULL;
277 size_t nReqSize = 0;
278 struct rt_msghdr *rtm;
279 struct sockaddr *sa;
280 struct sockaddr *rti_info[RTAX_MAX];
281
282 if (sysctl(mib, 6, NULL, &nReqSize, NULL, 0) == 0)
283 {
284 if (nReqSize > 0)
285 {
286 pRT = (char *)malloc(nReqSize);
287 if (pRT != NULL)
288 {
289 if (sysctl(mib, 6, pRT, &nReqSize, NULL, 0) < 0)
290 {
291 free(pRT);
292 pRT = NULL;
293 }
294 }
295 }
296 }
297
298 if (pRT != NULL)
299 {
300 nRet = SYSINFO_RC_SUCCESS;
301
302 for (pNext = pRT; pNext < pRT + nReqSize; pNext += rtm->rtm_msglen)
303 {
304 rtm = (struct rt_msghdr *)pNext;
305 sa = (struct sockaddr *)(rtm + 1);
306
307 if (sa->sa_family != AF_INET)
308 {
309 continue;
310 }
311
312 for (int i = 0; i < RTAX_MAX; i++)
313 {
314 if (rtm->rtm_addrs & (1 << i))
315 {
316 rti_info[i] = sa;
317 sa = (struct sockaddr *)((char *)(sa) + ROUNDUP(sa->sa_len));
318 }
319 else
320 {
321 rti_info[i] = NULL;
322 }
323 }
324
325 if (rti_info[RTAX_DST] != NULL && !(rtm->rtm_flags & RTF_WASCLONED))
326 {
327 char szOut[1024];
328 char szTmp[64];
329
330 if (sa2sin(rti_info[RTAX_DST])->sin_addr.s_addr == INADDR_ANY)
331 {
332 strcpy(szOut, "0.0.0.0/0 ");
333 }
334 else
335 {
336 if ((rtm->rtm_flags & RTF_HOST) || rti_info[RTAX_NETMASK]==NULL)
337 {
338 // host
339 strcpy(szOut,
340 inet_ntoa(sa2sin(rti_info[RTAX_DST])->sin_addr));
341 strcat(szOut, "/32 ");
342 }
343 else
344 {
345 // net
346 int nMask =
347 rti_info[RTAX_NETMASK] ?
348 ntohl(sa2sin(rti_info[RTAX_NETMASK])->sin_addr.s_addr)
349 : 0;
350
351 sprintf(szOut, "%s/%d ",
352 inet_ntoa(sa2sin(rti_info[RTAX_DST])->sin_addr),
353 nMask ? 33 - ffs(nMask) : 0);
354 }
355 }
356
357 if (rti_info[RTAX_GATEWAY]->sa_family != AF_INET)
358 {
359 strcat(szOut, "0.0.0.0 ");
360 }
361 else
362 {
363 strcat(szOut,
364 inet_ntoa(sa2sin(rti_info[RTAX_GATEWAY])->sin_addr));
365 strcat(szOut, " ");
366 }
367 snprintf(szTmp, sizeof(szTmp), "%d %d",
368 rtm->rtm_index,
369 (rtm->rtm_flags & RTF_GATEWAY) == 0 ? 3 : 4);
370 strcat(szOut, szTmp);
371
372 NxAddResultString(pValue, szOut);
373 }
374 }
375
376 free(pRT);
377 }
378
379 #undef ROUNDUP
380 #undef sa2sin
381
382 return nRet;
383 }
384
385 LONG H_NetIfList(char *pszParam, char *pArg, NETXMS_VALUES_LIST *pValue)
386 {
387 int nRet = SYSINFO_RC_ERROR;
388 struct ifaddrs *pIfAddr, *pNext;
389 if (getifaddrs(&pIfAddr) == 0)
390 {
391 char *pName = NULL;
392 int nIndex, nMask, i;
393 int nIfCount = 0;
394 IFLIST *pList = NULL;
395
396 nRet = SYSINFO_RC_SUCCESS;
397
398 pNext = pIfAddr;
399 while (pNext != NULL)
400 {
401 if (pName != pNext->ifa_name)
402 {
403 IFLIST *pTmp;
404
405 nIfCount++;
406 pTmp = (IFLIST *)realloc(pList, nIfCount * sizeof(IFLIST));
407 if (pTmp == NULL)
408 {
409 // out of memoty
410 nIfCount--;
411 nRet = SYSINFO_RC_ERROR;
412 break;
413 }
414 pList = pTmp;
415
416 memset(&(pList[nIfCount-1]), 0, sizeof(IFLIST));
417 pList[nIfCount-1].name = pNext->ifa_name;
418 pName = pNext->ifa_name;
419 }
420
421 switch (pNext->ifa_addr->sa_family)
422 {
423 case AF_INET:
424 {
425 ADDR *pTmp;
426 pList[nIfCount-1].addrCount++;
427 pTmp = (ADDR *)realloc(pList[nIfCount-1].addr,
428 pList[nIfCount-1].addrCount * sizeof(ADDR));
429 if (pTmp == NULL)
430 {
431 pList[nIfCount-1].addrCount--;
432 nRet = SYSINFO_RC_ERROR;
433 break;
434 }
435 pList[nIfCount-1].addr = pTmp;
436 pList[nIfCount-1].addr[pList[nIfCount-1].addrCount-1].ip =
437 ((struct sockaddr_in *)(pNext->ifa_addr))->sin_addr;
438 pList[nIfCount-1].addr[pList[nIfCount-1].addrCount-1].mask =
439 BitsInMask(htonl(((struct sockaddr_in *)
440 (pNext->ifa_netmask))->sin_addr.s_addr));
441 }
442 break;
443 case AF_LINK:
444 {
445 struct sockaddr_dl *pSdl;
446
447 pSdl = (struct sockaddr_dl *)pNext->ifa_addr;
448 pList[nIfCount-1].mac = (struct ether_addr *)LLADDR(pSdl);
449 pList[nIfCount-1].index = pSdl->sdl_index;
450 }
451 break;
452 }
453
454 if (nRet == SYSINFO_RC_ERROR)
455 {
456 break;
457 }
458 pNext = pNext->ifa_next;
459 }
460
461 if (nRet == SYSINFO_RC_SUCCESS)
462 {
463 for (i = 0; i < nIfCount; i++)
464 {
465 int j;
466 char szOut[1024];
467
468 if (pList[i].addrCount == 0)
469 {
470 snprintf(szOut, sizeof(szOut), "%d 0.0.0.0/0 %d %s %s",
471 pList[i].index,
472 IFTYPE_OTHER,
473 ether_ntoa(pList[i].mac),
474 pList[i].name);
475 NxAddResultString(pValue, szOut);
476 }
477 else
478 {
479 for (j = 0; j < pList[i].addrCount; j++)
480 {
481 if (j > 0)
482 {
483 snprintf(szOut, sizeof(szOut), "%d %s/%d %d %s %s:%d",
484 pList[i].index,
485 inet_ntoa(pList[i].addr[j].ip),
486 pList[i].addr[j].mask,
487 IFTYPE_OTHER,
488 ether_ntoa(pList[i].mac),
489 pList[i].name,
490 j - 1);
491 }
492 else
493 {
494 snprintf(szOut, sizeof(szOut), "%d %s/%d %d %s %s",
495 pList[i].index,
496 inet_ntoa(pList[i].addr[j].ip),
497 pList[i].addr[j].mask,
498 IFTYPE_OTHER,
499 ether_ntoa(pList[i].mac),
500 pList[i].name);
501 }
502 NxAddResultString(pValue, szOut);
503 }
504 }
505 }
506 }
507
508 for (i = 0; i < nIfCount; i++)
509 {
510 if (pList[i].addr != NULL)
511 {
512 free(pList[i].addr);
513 pList[i].addr = NULL;
514 pList[i].addrCount = 0;
515 }
516 }
517 if (pList != NULL)
518 {
519 free(pList);
520 pList = NULL;
521 }
522
523 freeifaddrs(pIfAddr);
524 }
525 else
526 {
527 perror("getifaddrs()");
528 }
529 return nRet;
530 }
531
532 ///////////////////////////////////////////////////////////////////////////////
533 /*
534
535 $Log: not supported by cvs2svn $
536 Revision 1.9 2005/08/22 23:00:05 alk
537 Net.IP.RoutingTable added
538
539 Revision 1.8 2005/06/12 17:58:36 victor
540 Net.Interface.AdminStatus should return 2 for disabled interfaces
541
542 Revision 1.7 2005/05/30 16:31:58 alk
543 fix: InterfaceList now return interfaces w/o IP address
544
545 Revision 1.6 2005/05/23 20:30:28 alk
546 ! memory allocation for address list now in sizeof * count, fixes "mixing" lists of aliases
547
548 Revision 1.5 2005/03/10 19:04:07 alk
549 implemented:
550 Net.Interface.AdminStatus(*)
551 Net.Interface.Link(*)
552
553 Revision 1.4 2005/03/10 12:23:56 alk
554 issue #18
555 alias handling on inet interfaces
556 status: fixed
557
558 Revision 1.3 2005/02/14 17:03:37 alk
559 issue #9
560
561 mask calculation chaged to BitsInMask()
562
563 Revision 1.2 2005/01/23 05:08:06 alk
564 + System.CPU.Count
565 + System.Memory.Physical.*
566 + System.ProcessCount
567 + System.ProcessList
568
569 Revision 1.1 2005/01/17 17:14:32 alk
570 freebsd agent, incomplete (but working)
571
572 Revision 1.4 2005/01/05 12:21:24 victor
573 - Added wrappers for new and delete from gcc2 libraries
574 - sys/stat.h and fcntl.h included in nms_common.h
575
576 Revision 1.3 2004/11/25 08:01:27 victor
577 Processing of interface list will be stopped on error
578
579 Revision 1.2 2004/10/23 22:53:23 alk
580 ArpCache: ignore incomplete entries
581
582 Revision 1.1 2004/10/22 22:08:34 alk
583 source restructured;
584 implemented:
585 Net.IP.Forwarding
586 Net.IP6.Forwarding
587 Process.Count(*)
588 Net.ArpCache
589 Net.InterfaceList (if-type not implemented yet)
590 System.ProcessList
591
592
593 */