1 /*
2 * snmp_var_route.c - return a pointer to the named variable.
3 *
4 *
5 */
6 /* Portions of this file are subject to the following copyright(s). See
7 * the Net-SNMP's COPYING file for more details and other copyrights
8 * that may apply:
9 */
10 /***********************************************************
11 Copyright 1988, 1989 by Carnegie Mellon University
12 Copyright 1989 TGV, Incorporated
13
14 All Rights Reserved
15
16 Permission to use, copy, modify, and distribute this software and its
17 documentation for any purpose and without fee is hereby granted,
18 provided that the above copyright notice appear in all copies and that
19 both that copyright notice and this permission notice appear in
20 supporting documentation, and that the name of CMU and TGV not be used
21 in advertising or publicity pertaining to distribution of the software
22 without specific, written prior permission.
23
24 CMU AND TGV DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
25 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
26 EVENT SHALL CMU OR TGV BE LIABLE FOR ANY SPECIAL, INDIRECT OR
27 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
28 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
29 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
30 PERFORMANCE OF THIS SOFTWARE.
31 ******************************************************************/
32 /*
33 * Portions of this file are copyrighted by:
34 * Copyright � 2003 Sun Microsystems, Inc. All rights reserved.
35 * Use is subject to license terms specified in the COPYING file
36 * distributed with the Net-SNMP package.
37 */
38
39 /*
40 * additions, fixes and enhancements for Linux by Erik Schoenfelder
41 * (schoenfr@ibr.cs.tu-bs.de) 1994/1995.
42 * Linux additions taken from CMU to UCD stack by Jennifer Bray of Origin
43 * (jbray@origin-at.co.uk) 1997
44 * Support for sysctl({CTL_NET,PF_ROUTE,...) by Simon Leinen
45 * (simon@switch.ch) 1997
46 */
47
48
49 #include <net-snmp/net-snmp-config.h>
50 #include <net-snmp/net-snmp-features.h>
51
52 #include "route_headers.h"
53 #define CACHE_TIME (120) /* Seconds */
54
55 #if !defined(NETSNMP_CAN_USE_SYSCTL)
56
57 #include <net-snmp/net-snmp-includes.h>
58 #include <net-snmp/agent/net-snmp-agent-includes.h>
59 #include <net-snmp/agent/auto_nlist.h>
60 #include <net-snmp/data_access/interface.h>
61
62 #include "ip.h"
63 #include "kernel.h"
64 #include "interfaces.h"
65 #include "struct.h"
66 #include "util_funcs.h"
67
68 #if defined(cygwin) || defined(mingw32)
69 #include <winerror.h>
70 #endif
71
72 netsnmp_feature_child_of(get_routes, libnetsnmpmibs);
73
74 #ifndef MIN
75 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
76 #endif
77
78 #ifdef hpux11
79 #include <sys/mib.h>
80 #include <netinet/mib_kern.h>
81 #endif /* hpux */
82
83 #if !defined (WIN32) && !defined (cygwin)
84
85 #ifdef USE_SYSCTL_ROUTE_DUMP
86
87 static void Route_Scan_Reload(void);
88
89 static unsigned char *all_routes = 0;
90 static unsigned char *all_routes_end;
91 static size_t all_routes_size;
92
93 /*
94 * var_ipRouteEntry(...
95 * Arguments:
96 * vp IN - pointer to variable entry that points here
97 * name IN/OUT - IN/name requested, OUT/name found
98 * length IN/OUT - length of IN/OUT oid's
99 * exact IN - TRUE if an exact match was requested
100 * var_len OUT - length of variable or 0 if function returned
101 * write_method out - pointer to function to set variable, otherwise 0
102 */
103 u_char *
var_ipRouteEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)104 var_ipRouteEntry(struct variable *vp,
105 oid * name,
106 size_t * length,
107 int exact, size_t * var_len, WriteMethod ** write_method)
108 {
109 /*
110 * object identifier is of form:
111 * 1.3.6.1.2.1.4.21.1.1.A.B.C.D, where A.B.C.D is IP address.
112 * IPADDR starts at offset 10.
113 */
114 struct rt_msghdr *rtp, *saveRtp = 0;
115 register int Save_Valid, result;
116 static int saveNameLen = 0, saveExact = 0;
117 static oid saveName[MAX_OID_LEN], Current[MAX_OID_LEN];
118 u_char *cp;
119 u_char *ap;
120 oid *op;
121 static in_addr_t addr_ret;
122
123 *write_method = NULL; /* write_rte; XXX: SET support not really implemented */
124
125 #if 0
126 /**
127 ** this optimisation fails, if there is only a single route avail.
128 ** it is a very special case, but better leave it out ...
129 **/
130 #if 0
131 if (rtsize <= 1)
132 Save_Valid = 0;
133 else
134 #endif /* 0 */
135 /*
136 * OPTIMIZATION:
137 *
138 * If the name was the same as the last name, with the possible
139 * exception of the [9]th token, then don't read the routing table
140 *
141 */
142
143 if ((saveNameLen == *length) && (saveExact == exact)) {
144 register int temp = name[9];
145 name[9] = 0;
146 Save_Valid =
147 (snmp_oid_compare(name, *length, saveName, saveNameLen) == 0);
148 name[9] = temp;
149 } else
150 Save_Valid = 0;
151
152 if (Save_Valid && saveRtp) {
153 register int temp = name[9]; /* Fix up 'lowest' found entry */
154 memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
155 name[9] = temp;
156 *length = 14;
157 rtp = saveRtp;
158 } else {
159 #endif /* 0 */
160 /*
161 * fill in object part of name for current (less sizeof instance part)
162 */
163
164 memcpy((char *) Current, (char *) vp->name,
165 (int) (vp->namelen) * sizeof(oid));
166
167 #if 0
168 /*
169 * Only reload if this is the start of a wildcard
170 */
171 if (*length < 14) {
172 Route_Scan_Reload();
173 }
174 #else
175 Route_Scan_Reload();
176 #endif
177 for (ap = all_routes; ap < all_routes_end; ap += rtp->rtm_msglen) {
178 rtp = (struct rt_msghdr *) ap;
179 if (rtp->rtm_type == 0)
180 break;
181 if (rtp->rtm_version != RTM_VERSION) {
182 snmp_log(LOG_ERR,
183 "routing socket message version mismatch (%d instead of %d)\n",
184 rtp->rtm_version, RTM_VERSION);
185 break;
186 }
187 if (rtp->rtm_type != RTM_GET) {
188 snmp_log(LOG_ERR,
189 "routing socket returned message other than GET (%d)\n",
190 rtp->rtm_type);
191 continue;
192 }
193 if (!(rtp->rtm_addrs & RTA_DST))
194 continue;
195 cp = (u_char *) get_in_address((struct sockaddr *) (rtp + 1),
196 rtp->rtm_addrs, RTA_DST);
197 if (cp == NULL)
198 return NULL;
199
200 op = Current + 10;
201 *op++ = *cp++;
202 *op++ = *cp++;
203 *op++ = *cp++;
204 *op++ = *cp++;
205
206 result = snmp_oid_compare(name, *length, Current, 14);
207 if ((exact && (result == 0)) || (!exact && (result < 0)))
208 break;
209 }
210 if (ap >= all_routes_end || rtp->rtm_type == 0)
211 return 0;
212 /*
213 * Save in the 'cache'
214 */
215 memcpy((char *) saveName, (char *) name,
216 SNMP_MIN(*length, MAX_OID_LEN) * sizeof(oid));
217 saveName[9] = '\0';
218 saveNameLen = *length;
219 saveExact = exact;
220 saveRtp = rtp;
221 /*
222 * Return the name
223 */
224 memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
225 *length = 14;
226 #if 0
227 }
228 #endif /* 0 */
229
230 *var_len = sizeof(long_return);
231
232 switch (vp->magic) {
233 case IPROUTEDEST:
234 *var_len = sizeof(addr_ret);
235 return (u_char *) get_in_address((struct sockaddr *) (rtp + 1),
236 rtp->rtm_addrs, RTA_DST);
237 case IPROUTEIFINDEX:
238 long_return = (u_long) rtp->rtm_index;
239 return (u_char *) & long_return;
240 case IPROUTEMETRIC1:
241 long_return = (rtp->rtm_flags & RTF_UP) ? 1 : 0;
242 return (u_char *) & long_return;
243 case IPROUTEMETRIC2:
244 #if NETSNMP_NO_DUMMY_VALUES
245 return NULL;
246 #endif
247 long_return = -1;
248 return (u_char *) & long_return;
249 case IPROUTEMETRIC3:
250 #if NETSNMP_NO_DUMMY_VALUES
251 return NULL;
252 #endif
253 long_return = -1;
254 return (u_char *) & long_return;
255 case IPROUTEMETRIC4:
256 #if NETSNMP_NO_DUMMY_VALUES
257 return NULL;
258 #endif
259 long_return = -1;
260 return (u_char *) & long_return;
261 case IPROUTEMETRIC5:
262 #if NETSNMP_NO_DUMMY_VALUES
263 return NULL;
264 #endif
265 long_return = -1;
266 return (u_char *) & long_return;
267 case IPROUTENEXTHOP:
268 *var_len = sizeof(addr_ret);
269 return (u_char *) get_in_address((struct sockaddr *) (rtp + 1),
270 rtp->rtm_addrs, RTA_GATEWAY);
271 case IPROUTETYPE:
272 if (rtp->rtm_flags & RTF_UP) {
273 if (rtp->rtm_flags & RTF_GATEWAY) {
274 long_return = 4; /* indirect(4) */
275 } else {
276 long_return = 3; /* direct(3) */
277 }
278 } else {
279 long_return = 2; /* invalid(2) */
280 }
281 return (u_char *) & long_return;
282 case IPROUTEPROTO:
283 long_return = (rtp->rtm_flags & RTF_DYNAMIC)
284 ? 10 : (rtp->rtm_flags & RTF_STATIC)
285 ? 2 : (rtp->rtm_flags & RTF_DYNAMIC) ? 4 : 1;
286 return (u_char *) & long_return;
287 case IPROUTEAGE:
288 #if NETSNMP_NO_DUMMY_VALUES
289 return NULL;
290 #endif
291 long_return = 0;
292 return (u_char *) & long_return;
293 case IPROUTEMASK:
294 *var_len = sizeof(addr_ret);
295 if (rtp->rtm_flags & RTF_HOST) {
296 addr_ret = 0x00000001;
297 return (u_char *) & addr_ret;
298 } else {
299 return (u_char *) get_in_address((struct sockaddr *) (rtp + 1),
300 rtp->rtm_addrs, RTA_NETMASK);
301 }
302 case IPROUTEINFO:
303 *var_len = nullOidLen;
304 return (u_char *) nullOid;
305 default:
306 DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
307 vp->magic));
308 }
309 return NULL;
310 }
311
312 #else /* not USE_SYSCTL_ROUTE_DUMP */
313
314 #ifdef hpux11
315 static int rtsize = 0;
316 static mib_ipRouteEnt *rt = (mib_ipRouteEnt *) 0;
317 static void Route_Scan_Reload(void);
318 #elif !defined(solaris2)
319 static RTENTRY **rthead = NULL;
320 static int rtsize = 0, rtallocate = 0;
321
322 static void Route_Scan_Reload(void);
323
324 #ifndef NETSNMP_FEATURE_REMOVE_GET_ROUTES
netsnmp_get_routes(size_t * size)325 RTENTRY **netsnmp_get_routes(size_t *size) {
326 Route_Scan_Reload();
327 if (size)
328 *size = rtsize;
329 return rthead;
330 }
331 #endif /* NETSNMP_FEATURE_REMOVE_GET_ROUTES */
332 #endif /* hpux11 */
333
334 #if !(defined(linux) || defined(solaris2) || defined(hpux11)) && defined(RTHOST_SYMBOL) && defined(RTNET_SYMBOL)
335 #define NUM_ROUTE_SYMBOLS 2
336 static char *route_symbols[] = {
337 RTHOST_SYMBOL,
338 RTNET_SYMBOL
339 };
340 #endif
341 #endif
342
343 #ifdef USE_SYSCTL_ROUTE_DUMP
344
345 void
init_var_route(void)346 init_var_route(void)
347 {
348 #ifdef solaris2
349 init_kernel_sunos5();
350 #endif
351 }
352
353 static void
Route_Scan_Reload(void)354 Route_Scan_Reload(void)
355 {
356 size_t size = 0;
357 int name[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 };
358
359 if (sysctl(name, sizeof(name) / sizeof(int), 0, &size, 0, 0) == -1) {
360 snmp_log(LOG_ERR, "sysctl(CTL_NET,PF_ROUTE,0,0,NET_RT_DUMP,0)\n");
361 } else {
362 if (all_routes == 0 || all_routes_size < size) {
363 if (all_routes != 0) {
364 free(all_routes);
365 all_routes = 0;
366 }
367 if ((all_routes = malloc(size)) == 0) {
368 snmp_log(LOG_ERR,
369 "out of memory allocating route table\n");
370 }
371 all_routes_size = size;
372 } else {
373 size = all_routes_size;
374 }
375 if (sysctl(name, sizeof(name) / sizeof(int),
376 all_routes, &size, 0, 0) == -1) {
377 snmp_log(LOG_ERR,
378 "sysctl(CTL_NET,PF_ROUTE,0,0,NET_RT_DUMP,0)\n");
379 }
380 all_routes_end = all_routes + size;
381 }
382 }
383
384 #else /* not USE_SYSCTL_ROUTE_DUMP */
385
386 void
init_var_route(void)387 init_var_route(void)
388 {
389 #ifdef RTTABLES_SYMBOL
390 auto_nlist(RTTABLES_SYMBOL, 0, 0);
391 #endif
392 #ifdef RTHASHSIZE_SYMBOL
393 auto_nlist(RTHASHSIZE_SYMBOL, 0, 0);
394 #endif
395 #ifdef RTHOST_SYMBOL
396 auto_nlist(RTHOST_SYMBOL, 0, 0);
397 #endif
398 #ifdef RTNET_SYMBOL
399 auto_nlist(RTNET_SYMBOL, 0, 0);
400 #endif
401 }
402
403 #ifndef solaris2
404
405 #if NEED_KLGETSA
406 static union {
407 struct sockaddr_in sin;
408 u_short data[128];
409 } klgetsatmp;
410
411 static struct sockaddr_in *
klgetsa(struct sockaddr_in * dst)412 klgetsa(struct sockaddr_in *dst)
413 {
414 if (!NETSNMP_KLOOKUP(dst, (char *) &klgetsatmp.sin, sizeof klgetsatmp.sin)) {
415 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
416 return NULL;
417 }
418 if (klgetsatmp.sin.sin_len > sizeof(klgetsatmp.sin)) {
419 if (!NETSNMP_KLOOKUP(dst, (char *) &klgetsatmp.sin, klgetsatmp.sin.sin_len)) {
420 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
421 return NULL;
422 }
423 }
424 return (&klgetsatmp.sin);
425 }
426 #endif
427
428 u_char *
var_ipRouteEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)429 var_ipRouteEntry(struct variable * vp,
430 oid * name,
431 size_t * length,
432 int exact, size_t * var_len, WriteMethod ** write_method)
433 {
434 /*
435 * object identifier is of form:
436 * 1.3.6.1.2.1.4.21.1.1.A.B.C.D, where A.B.C.D is IP address.
437 * IPADDR starts at offset 10.
438 */
439 register int Save_Valid, result, RtIndex;
440 static size_t saveNameLen = 0;
441 static int saveExact = 0, saveRtIndex = 0;
442 static oid saveName[MAX_OID_LEN], Current[MAX_OID_LEN];
443 u_char *cp;
444 oid *op;
445 static in_addr_t addr_ret;
446 #if NEED_KLGETSA
447 struct sockaddr_in *sa;
448 #endif
449 #if !defined(linux) && !defined(hpux11)
450 struct ifnet rt_ifnet;
451 struct in_ifaddr rt_ifnetaddr;
452 #endif
453
454 *write_method = NULL; /* write_rte; XXX: SET support not really implemented */
455
456 /**
457 ** this optimisation fails, if there is only a single route avail.
458 ** it is a very special case, but better leave it out ...
459 **/
460 #if NETSNMP_NO_DUMMY_VALUES
461 saveNameLen = 0;
462 #endif
463 if (rtsize <= 1)
464 Save_Valid = 0;
465 else
466 /*
467 * OPTIMIZATION:
468 *
469 * If the name was the same as the last name, with the possible
470 * exception of the [9]th token, then don't read the routing table
471 *
472 */
473
474 if ((saveNameLen == *length) && (saveExact == exact)) {
475 register int temp = name[9];
476 name[9] = 0;
477 Save_Valid =
478 (snmp_oid_compare(name, *length, saveName, saveNameLen) == 0);
479 name[9] = temp;
480 } else
481 Save_Valid = 0;
482
483 if (Save_Valid) {
484 register int temp = name[9]; /* Fix up 'lowest' found entry */
485 memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
486 name[9] = temp;
487 *length = 14;
488 RtIndex = saveRtIndex;
489 } else {
490 /*
491 * fill in object part of name for current (less sizeof instance part)
492 */
493
494 memcpy((char *) Current, (char *) vp->name,
495 (int) (vp->namelen) * sizeof(oid));
496
497 #if 0
498 /*
499 * Only reload if this is the start of a wildcard
500 */
501 if (*length < 14) {
502 Route_Scan_Reload();
503 }
504 #else
505 Route_Scan_Reload();
506 #endif
507 for (RtIndex = 0; RtIndex < rtsize; RtIndex++) {
508 #if NEED_KLGETSA
509 sa = klgetsa((struct sockaddr_in *) rthead[RtIndex]->rt_dst);
510 cp = (u_char *) & (sa->sin_addr.s_addr);
511 #elif defined(hpux11)
512 cp = (u_char *) & rt[RtIndex].Dest;
513 #else
514 cp = (u_char *) &
515 (((struct sockaddr_in *) &(rthead[RtIndex]->rt_dst))->
516 sin_addr.s_addr);
517 #endif
518 op = Current + 10;
519 *op++ = *cp++;
520 *op++ = *cp++;
521 *op++ = *cp++;
522 *op++ = *cp++;
523
524 result = snmp_oid_compare(name, *length, Current, 14);
525 if ((exact && (result == 0)) || (!exact && (result < 0)))
526 break;
527 }
528 if (RtIndex >= rtsize)
529 return (NULL);
530 /*
531 * Save in the 'cache'
532 */
533 memcpy((char *) saveName, (char *) name,
534 SNMP_MIN(*length, MAX_OID_LEN) * sizeof(oid));
535 saveName[9] = 0;
536 saveNameLen = *length;
537 saveExact = exact;
538 saveRtIndex = RtIndex;
539 /*
540 * Return the name
541 */
542 memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
543 *length = 14;
544 }
545
546 *var_len = sizeof(long_return);
547
548 switch (vp->magic) {
549 case IPROUTEDEST:
550 *var_len = sizeof(addr_ret);
551 #if NEED_KLGETSA
552 sa = klgetsa((struct sockaddr_in *) rthead[RtIndex]->rt_dst);
553 return (u_char *) & (sa->sin_addr.s_addr);
554 #elif defined(hpux11)
555 addr_ret = rt[RtIndex].Dest;
556 return (u_char *) & addr_ret;
557 #else
558 return (u_char *) & ((struct sockaddr_in *) &rthead[RtIndex]->
559 rt_dst)->sin_addr.s_addr;
560 #endif
561 case IPROUTEIFINDEX:
562 #ifdef hpux11
563 long_return = rt[RtIndex].IfIndex;
564 #else
565 long_return = (u_long) rthead[RtIndex]->rt_unit;
566 #endif
567 return (u_char *) & long_return;
568 case IPROUTEMETRIC1:
569 #ifdef hpux11
570 long_return = rt[RtIndex].Metric1;
571 #else
572 long_return = (rthead[RtIndex]->rt_flags & RTF_GATEWAY) ? 1 : 0;
573 #endif
574 return (u_char *) & long_return;
575 case IPROUTEMETRIC2:
576 #ifdef hpux11
577 long_return = rt[RtIndex].Metric2;
578 return (u_char *) & long_return;
579 #elif defined(NETSNMP_NO_DUMMY_VALUES)
580 return NULL;
581 #endif
582 long_return = -1;
583 return (u_char *) & long_return;
584 case IPROUTEMETRIC3:
585 #ifdef hpux11
586 long_return = rt[RtIndex].Metric3;
587 return (u_char *) & long_return;
588 #elif defined(NETSNMP_NO_DUMMY_VALUES)
589 return NULL;
590 #endif
591 long_return = -1;
592 return (u_char *) & long_return;
593 case IPROUTEMETRIC4:
594 #ifdef hpux11
595 long_return = rt[RtIndex].Metric4;
596 return (u_char *) & long_return;
597 #elif defined(NETSNMP_NO_DUMMY_VALUES)
598 return NULL;
599 #endif
600 long_return = -1;
601 return (u_char *) & long_return;
602 case IPROUTEMETRIC5:
603 #if NETSNMP_NO_DUMMY_VALUES
604 return NULL;
605 #endif
606 long_return = -1;
607 return (u_char *) & long_return;
608 case IPROUTENEXTHOP:
609 *var_len = sizeof(addr_ret);
610 #if NEED_KLGETSA
611 sa = klgetsa((struct sockaddr_in *) rthead[RtIndex]->rt_gateway);
612 return (u_char *) & (sa->sin_addr.s_addr);
613 #elif defined(hpux11)
614 addr_ret = rt[RtIndex].NextHop;
615 return (u_char *) & addr_ret;
616 #else
617 return (u_char *) & ((struct sockaddr_in *) &rthead[RtIndex]->
618 rt_gateway)->sin_addr.s_addr;
619 #endif /* *bsd */
620 case IPROUTETYPE:
621 #ifdef hpux11
622 long_return = rt[RtIndex].Type;
623 #else
624 if (rthead[RtIndex]->rt_flags & RTF_UP) {
625 if (rthead[RtIndex]->rt_flags & RTF_GATEWAY) {
626 long_return = 4; /* indirect(4) */
627 } else {
628 long_return = 3; /* direct(3) */
629 }
630 } else {
631 long_return = 2; /* invalid(2) */
632 }
633 #endif
634 return (u_char *) & long_return;
635 case IPROUTEPROTO:
636 #ifdef hpux11
637 long_return = rt[RtIndex].Proto;
638 #else
639 long_return = (rthead[RtIndex]->rt_flags & RTF_DYNAMIC) ? 4 : 2;
640 #endif
641 return (u_char *) & long_return;
642 case IPROUTEAGE:
643 #ifdef hpux11
644 long_return = rt[RtIndex].Age;
645 return (u_char *) & long_return;
646 #elif defined(NETSNMP_NO_DUMMY_VALUES)
647 return NULL;
648 #endif
649 long_return = 0;
650 return (u_char *) & long_return;
651 case IPROUTEMASK:
652 *var_len = sizeof(addr_ret);
653 #if NEED_KLGETSA
654 /*
655 * XXX - Almost certainly not right
656 * but I don't have a suitable system to test this on
657 */
658 #if NETSNMP_NO_DUMMY_VALUES
659 return NULL;
660 #endif
661 addr_ret = 0;
662 #elif defined(hpux11)
663 addr_ret = rt[RtIndex].Mask;
664 return (u_char *) & addr_ret;
665 #else /* !NEED_KLGETSA && !hpux11 */
666 if (((struct sockaddr_in *) &rthead[RtIndex]->rt_dst)->sin_addr.
667 s_addr == 0)
668 addr_ret = 0; /* Default route */
669 else {
670 #ifndef linux
671 if (!NETSNMP_KLOOKUP(rthead[RtIndex]->rt_ifp,
672 (char *) &rt_ifnet, sizeof(rt_ifnet))) {
673 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
674 return NULL;
675 }
676 if (!NETSNMP_KLOOKUP(rt_ifnet.if_addrlist,
677 (char *) &rt_ifnetaddr, sizeof(rt_ifnetaddr))) {
678 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
679 return NULL;
680 }
681
682 addr_ret = rt_ifnetaddr.ia_subnetmask;
683 #else /* linux */
684 cp = (u_char *) &
685 (((struct sockaddr_in *) &(rthead[RtIndex]->rt_dst))->
686 sin_addr.s_addr);
687 return (u_char *) &
688 (((struct sockaddr_in *) &(rthead[RtIndex]->rt_genmask))->
689 sin_addr.s_addr);
690 #endif /* linux */
691 }
692 #endif /* NEED_KLGETSA */
693 return (u_char *) & addr_ret;
694 case IPROUTEINFO:
695 *var_len = nullOidLen;
696 return (u_char *) nullOid;
697 default:
698 DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
699 vp->magic));
700 }
701 return NULL;
702 }
703
704 #else /* solaris2 */
705
706 static int
IP_Cmp_Route(void * addr,void * ep)707 IP_Cmp_Route(void *addr, void *ep)
708 {
709 mib2_ipRouteEntry_t *Ep = ep, *Addr = addr;
710
711 if ((Ep->ipRouteDest == Addr->ipRouteDest) &&
712 (Ep->ipRouteNextHop == Addr->ipRouteNextHop) &&
713 (Ep->ipRouteType == Addr->ipRouteType) &&
714 (Ep->ipRouteProto == Addr->ipRouteProto) &&
715 (Ep->ipRouteMask == Addr->ipRouteMask) &&
716 (Ep->ipRouteInfo.re_max_frag == Addr->ipRouteInfo.re_max_frag) &&
717 (Ep->ipRouteInfo.re_rtt == Addr->ipRouteInfo.re_rtt) &&
718 (Ep->ipRouteInfo.re_ref == Addr->ipRouteInfo.re_ref) &&
719 (Ep->ipRouteInfo.re_frag_flag == Addr->ipRouteInfo.re_frag_flag) &&
720 (Ep->ipRouteInfo.re_src_addr == Addr->ipRouteInfo.re_src_addr) &&
721 (Ep->ipRouteInfo.re_ire_type == Addr->ipRouteInfo.re_ire_type) &&
722 (Ep->ipRouteInfo.re_obpkt == Addr->ipRouteInfo.re_obpkt) &&
723 (Ep->ipRouteInfo.re_ibpkt == Addr->ipRouteInfo.re_ibpkt)
724 )
725 return (0);
726 else
727 return (1); /* Not found */
728 }
729
730 u_char *
var_ipRouteEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)731 var_ipRouteEntry(struct variable * vp,
732 oid * name,
733 size_t * length,
734 int exact, size_t * var_len, WriteMethod ** write_method)
735 {
736 /*
737 * object identifier is of form:
738 * 1.3.6.1.2.1.4.21.1.1.A.B.C.D, where A.B.C.D is IP address.
739 * IPADDR starts at offset 10.
740 */
741 #define IP_ROUTENAME_LENGTH 14
742 #define IP_ROUTEADDR_OFF 10
743 oid current[IP_ROUTENAME_LENGTH],
744 lowest[IP_ROUTENAME_LENGTH];
745 u_char *cp;
746 oid *op;
747 mib2_ipRouteEntry_t Lowentry, Nextentry, entry;
748 int Found = 0;
749 req_e req_type;
750 static in_addr_t addr_ret;
751
752 *write_method = NULL; /* write_rte; XXX: SET support not really implemented */
753
754 /*
755 * fill in object part of name for current (less sizeof instance part)
756 */
757
758 memcpy((char *) current, (char *) vp->name, vp->namelen * sizeof(oid));
759 if (*length == IP_ROUTENAME_LENGTH) /* Assume that the input name is the lowest */
760 memcpy((char *) lowest, (char *) name,
761 IP_ROUTENAME_LENGTH * sizeof(oid));
762 else {
763 name[IP_ROUTEADDR_OFF] = (oid) - 1; /* Grhhh: to prevent accidental comparison :-( */
764 lowest[0] = 0xff;
765 }
766 for (Nextentry.ipRouteDest = (u_long) - 2, req_type = GET_FIRST;;
767 Nextentry = entry, req_type = GET_NEXT) {
768 if (getMibstat(MIB_IP_ROUTE, &entry, sizeof(mib2_ipRouteEntry_t),
769 req_type, &IP_Cmp_Route, &Nextentry) != 0)
770 break;
771 #ifdef HAVE_DEFINED_IRE_CACHE
772 if(entry.ipRouteInfo.re_ire_type&IRE_CACHE)
773 continue;
774 #endif /* HAVE_DEFINED_IRE_CACHE */
775 if(entry.ipRouteInfo.re_ire_type & IRE_BROADCAST)
776 continue;
777 COPY_IPADDR(cp, (u_char *) & entry.ipRouteDest, op,
778 current + IP_ROUTEADDR_OFF);
779 if (exact) {
780 if (snmp_oid_compare
781 (current, IP_ROUTENAME_LENGTH, name, *length) == 0) {
782 memcpy((char *) lowest, (char *) current,
783 IP_ROUTENAME_LENGTH * sizeof(oid));
784 Lowentry = entry;
785 Found++;
786 break; /* no need to search further */
787 }
788 } else {
789 if ((snmp_oid_compare
790 (current, IP_ROUTENAME_LENGTH, name, *length) > 0)
791 && ((Nextentry.ipRouteDest == (u_long) - 2)
792 ||
793 (snmp_oid_compare
794 (current, IP_ROUTENAME_LENGTH, lowest,
795 IP_ROUTENAME_LENGTH) < 0)
796 ||
797 (snmp_oid_compare
798 (name, IP_ROUTENAME_LENGTH, lowest,
799 IP_ROUTENAME_LENGTH) == 0))) {
800
801 /*
802 * if new one is greater than input and closer to input than
803 * * previous lowest, and is not equal to it, save this one as the "next" one.
804 */
805 memcpy((char *) lowest, (char *) current,
806 IP_ROUTENAME_LENGTH * sizeof(oid));
807 Lowentry = entry;
808 Found++;
809 }
810 }
811 }
812 if (Found == 0)
813 return (NULL);
814 memcpy((char *) name, (char *) lowest,
815 IP_ROUTENAME_LENGTH * sizeof(oid));
816 *length = IP_ROUTENAME_LENGTH;
817 *var_len = sizeof(long_return);
818
819 switch (vp->magic) {
820 case IPROUTEDEST:
821 *var_len = sizeof(addr_ret);
822 addr_ret = Lowentry.ipRouteDest;
823 return (u_char *) & addr_ret;
824 case IPROUTEIFINDEX:
825 Lowentry.ipRouteIfIndex.o_bytes[Lowentry.ipRouteIfIndex.o_length] = '\0';
826 long_return =
827 netsnmp_access_interface_index_find(
828 Lowentry.ipRouteIfIndex.o_bytes);
829 return (u_char *) & long_return;
830 case IPROUTEMETRIC1:
831 long_return = Lowentry.ipRouteMetric1;
832 return (u_char *) & long_return;
833 case IPROUTEMETRIC2:
834 long_return = Lowentry.ipRouteMetric2;
835 return (u_char *) & long_return;
836 case IPROUTEMETRIC3:
837 long_return = Lowentry.ipRouteMetric3;
838 return (u_char *) & long_return;
839 case IPROUTEMETRIC4:
840 long_return = Lowentry.ipRouteMetric4;
841 return (u_char *) & long_return;
842 case IPROUTENEXTHOP:
843 *var_len = sizeof(addr_ret);
844 addr_ret = Lowentry.ipRouteNextHop;
845 return (u_char *) & addr_ret;
846 case IPROUTETYPE:
847 long_return = Lowentry.ipRouteType;
848 return (u_char *) & long_return;
849 case IPROUTEPROTO:
850 long_return = Lowentry.ipRouteProto;
851 if (long_return == -1)
852 long_return = 1;
853 return (u_char *) & long_return;
854 case IPROUTEAGE:
855 long_return = Lowentry.ipRouteAge;
856 return (u_char *) & long_return;
857 case IPROUTEMASK:
858 *var_len = sizeof(addr_ret);
859 addr_ret = Lowentry.ipRouteMask;
860 return (u_char *) & addr_ret;
861 default:
862 DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
863 vp->magic));
864 };
865 return NULL;
866 }
867
868 #endif /* solaris2 - var_IProute */
869
870 #ifndef solaris2
871 static int qsort_compare(const void *, const void *);
872 #endif
873
874 #if defined(RTENTRY_4_4) || defined(RTENTRY_RT_NEXT) || defined (hpux11)
875
876 #if defined(RTENTRY_4_4) && !defined(hpux11)
877 static void
load_rtentries(struct radix_node * pt)878 load_rtentries(struct radix_node *pt)
879 {
880 struct radix_node node;
881 RTENTRY rt;
882 struct ifnet ifnet;
883 char name[16], temp[16];
884 #if !HAVE_STRUCT_IFNET_IF_XNAME
885 register char *cp;
886 #endif
887
888 if (!NETSNMP_KLOOKUP(pt, (char *) &node, sizeof(struct radix_node))) {
889 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
890 return;
891 }
892 if (node.rn_b >= 0) {
893 load_rtentries(node.rn_r);
894 load_rtentries(node.rn_l);
895 } else {
896 if (node.rn_flags & RNF_ROOT) {
897 /*
898 * root node
899 */
900 if (node.rn_dupedkey)
901 load_rtentries(node.rn_dupedkey);
902 return;
903 }
904 /*
905 * get the route
906 */
907 if (!NETSNMP_KLOOKUP(pt, (char *) &rt, sizeof(RTENTRY))) {
908 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
909 return;
910 }
911
912 if (rt.rt_ifp != 0) {
913 if (!NETSNMP_KLOOKUP(rt.rt_ifp, (char *) &ifnet, sizeof(ifnet))) {
914 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
915 return;
916 }
917 #if HAVE_STRUCT_IFNET_IF_XNAME
918 #if defined(netbsd1) || defined(openbsd2)
919 strlcpy(name, ifnet.if_xname, sizeof(name));
920 #else
921 if (!NETSNMP_KLOOKUP(ifnet.if_xname, name, sizeof name)) {
922 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
923 return;
924 }
925 #endif
926 name[sizeof(name) - 1] = '\0';
927 #else
928 #ifdef NETSNMP_FEATURE_CHECKIN
929 /* this exists here just so we don't copy ifdef logic elsewhere */
930 netsnmp_feature_require(string_append_int);
931 #endif
932 if (!NETSNMP_KLOOKUP(ifnet.if_name, name, sizeof name)) {
933 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
934 return;
935 }
936 name[sizeof(name) - 1] = '\0';
937 cp = (char *) strchr(name, '\0');
938 string_append_int(cp, ifnet.if_unit);
939 #endif
940 #ifdef NETSNMP_FEATURE_CHECKIN
941 netsnmp_feature_require(interface_legacy)
942 #endif /* NETSNMP_FEATURE_CHECKIN */
943 Interface_Scan_Init();
944 rt.rt_unit = 0;
945 while (Interface_Scan_Next
946 ((short *) &(rt.rt_unit), temp, NULL, NULL) != 0) {
947 if (strcmp(name, temp) == 0)
948 break;
949 }
950 }
951 #if CHECK_RT_FLAGS
952 if (((rt.rt_flags & RTF_CLONING) != RTF_CLONING)
953 && ((rt.rt_flags & RTF_LLINFO) != RTF_LLINFO)) {
954 #endif
955 /*
956 * check for space and malloc
957 */
958 if (rtsize >= rtallocate) {
959 rthead =
960 (RTENTRY **) realloc((char *) rthead,
961 2 * rtallocate *
962 sizeof(RTENTRY *));
963 memset((char *) &rthead[rtallocate], (0),
964 rtallocate * sizeof(RTENTRY *));
965
966 rtallocate *= 2;
967 }
968 if (!rthead[rtsize])
969 rthead[rtsize] = (RTENTRY *) malloc(sizeof(RTENTRY));
970 /*
971 * Add this to the database
972 */
973 memcpy((char *) rthead[rtsize], (char *) &rt, sizeof(RTENTRY));
974 rtsize++;
975 #if CHECK_RT_FLAGS
976 }
977 #endif
978
979 if (node.rn_dupedkey)
980 load_rtentries(node.rn_dupedkey);
981 }
982 }
983 #endif /* RTENTRY_4_4 && !hpux11 */
984
985 static void
Route_Scan_Reload(void)986 Route_Scan_Reload(void)
987 {
988 #ifdef hpux11
989
990 int fd;
991 struct nmparms p;
992 int val;
993 unsigned int ulen;
994 int ret;
995
996 if (rt)
997 free(rt);
998 rt = (mib_ipRouteEnt *) 0;
999 rtsize = 0;
1000
1001 if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) {
1002 p.objid = ID_ipRouteNumEnt;
1003 p.buffer = (void *) &val;
1004 ulen = sizeof(int);
1005 p.len = &ulen;
1006 if ((ret = get_mib_info(fd, &p)) == 0)
1007 rtsize = val;
1008
1009 if (rtsize > 0) {
1010 ulen = (unsigned) rtsize *sizeof(mib_ipRouteEnt);
1011 rt = (mib_ipRouteEnt *) malloc(ulen);
1012 p.objid = ID_ipRouteTable;
1013 p.buffer = (void *) rt;
1014 p.len = &ulen;
1015 if ((ret = get_mib_info(fd, &p)) < 0)
1016 rtsize = 0;
1017 }
1018
1019 close_mib(fd);
1020 }
1021
1022 /*
1023 * Sort it!
1024 */
1025 qsort((char *) rt, rtsize, sizeof(rt[0]),
1026 #ifdef __STDC__
1027 (int (*)(const void *, const void *)) qsort_compare
1028 #else
1029 qsort_compare
1030 #endif
1031 );
1032
1033 #else /* hpux11 */
1034 #if defined(RTENTRY_4_4)
1035 struct radix_node_head head, *rt_table[AF_MAX + 1];
1036 int i;
1037 #else
1038 RTENTRY **routehash, mb;
1039 register RTENTRY *m;
1040 RTENTRY *rt;
1041 struct ifnet ifnet;
1042 int i, table;
1043 register char *cp;
1044 char name[16], temp[16];
1045 int hashsize;
1046 #endif
1047 static time_t Time_Of_Last_Reload;
1048 struct timeval now;
1049
1050 netsnmp_get_monotonic_clock(&now);
1051 if (Time_Of_Last_Reload + CACHE_TIME > now.tv_sec)
1052 return;
1053 Time_Of_Last_Reload = now.tv_sec;
1054
1055 /*
1056 * * Makes sure we have SOME space allocated for new routing entries
1057 */
1058 if (!rthead) {
1059 rthead = (RTENTRY **) malloc(100 * sizeof(RTENTRY *));
1060 if (!rthead) {
1061 snmp_log(LOG_ERR, "route table malloc fail\n");
1062 return;
1063 }
1064 memset((char *) rthead, (0), 100 * sizeof(RTENTRY *));
1065 rtallocate = 100;
1066 }
1067
1068 /*
1069 * reset the routing table size to zero -- was a CMU memory leak
1070 */
1071 rtsize = 0;
1072
1073 #ifdef RTENTRY_4_4
1074 /*
1075 * rtentry is a BSD 4.4 compat
1076 */
1077
1078 #if !defined(AF_UNSPEC)
1079 #define AF_UNSPEC AF_INET
1080 #endif
1081
1082 auto_nlist(RTTABLES_SYMBOL, (char *) rt_table, sizeof(rt_table));
1083 for (i = 0; i <= AF_MAX; i++) {
1084 if (rt_table[i] == 0)
1085 continue;
1086 if (NETSNMP_KLOOKUP(rt_table[i], (char *) &head, sizeof(head))) {
1087 load_rtentries(head.rnh_treetop);
1088 }
1089 }
1090
1091 #else /* rtentry is a BSD 4.3 compat */
1092 #ifdef NETSNMP_FEATURE_CHECKIN
1093 /* this exists here just so we don't copy ifdef logic elsewhere */
1094 netsnmp_feature_require(string_append_int);
1095 netsnmp_feature_require(interface_legacy)
1096 #endif
1097 for (table = 0; table < NUM_ROUTE_SYMBOLS; table++) {
1098 auto_nlist(RTHASHSIZE_SYMBOL, (char *) &hashsize,
1099 sizeof(hashsize));
1100 routehash = (RTENTRY **) malloc(hashsize * sizeof(struct mbuf *));
1101 auto_nlist(route_symbols[table], (char *) routehash,
1102 hashsize * sizeof(struct mbuf *));
1103 for (i = 0; i < hashsize; i++) {
1104 if (routehash[i] == 0)
1105 continue;
1106 m = routehash[i];
1107 while (m) {
1108 /*
1109 * Dig the route out of the kernel...
1110 */
1111 if (!NETSNMP_KLOOKUP(m, (char *) &mb, sizeof(mb))) {
1112 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
1113 return;
1114 }
1115 m = mb.rt_next;
1116
1117 rt = &mb;
1118 if (rt->rt_ifp != 0) {
1119 if (!NETSNMP_KLOOKUP(rt->rt_ifp, (char *) &ifnet, sizeof(ifnet))) {
1120 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
1121 return;
1122 }
1123 if (!NETSNMP_KLOOKUP(ifnet.if_name, name, 16)) {
1124 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
1125 return;
1126 }
1127 name[15] = '\0';
1128 cp = (char *) strchr(name, '\0');
1129 string_append_int(cp, ifnet.if_unit);
1130
1131 Interface_Scan_Init();
1132 while (Interface_Scan_Next
1133 ((short *) &rt->rt_unit, temp, NULL,
1134 NULL) != 0) {
1135 if (strcmp(name, temp) == 0)
1136 break;
1137 }
1138 }
1139 /*
1140 * Allocate a block to hold it and add it to the database
1141 */
1142 if (rtsize >= rtallocate) {
1143 rthead =
1144 (RTENTRY **) realloc((char *) rthead,
1145 2 * rtallocate *
1146 sizeof(RTENTRY *));
1147 memset((char *) &rthead[rtallocate], (0),
1148 rtallocate * sizeof(RTENTRY *));
1149
1150 rtallocate *= 2;
1151 }
1152 if (!rthead[rtsize])
1153 rthead[rtsize] = (RTENTRY *) malloc(sizeof(RTENTRY));
1154 /*
1155 * Add this to the database
1156 */
1157 memcpy((char *) rthead[rtsize], (char *) rt,
1158 sizeof(RTENTRY));
1159 rtsize++;
1160 }
1161 }
1162 free(routehash);
1163 }
1164 #endif
1165 /*
1166 * Sort it!
1167 */
1168 qsort((char *) rthead, rtsize, sizeof(rthead[0]),
1169 #ifdef __STDC__
1170 (int (*)(const void *, const void *)) qsort_compare
1171 #else
1172 qsort_compare
1173 #endif
1174 );
1175 #endif /* hpux11 */
1176 }
1177
1178 #else
1179
1180 #if HAVE_SYS_MBUF_H
1181 netsnmp_feature_require(string_append_int);
1182 netsnmp_feature_require(interface_legacy);
1183 static void
Route_Scan_Reload(void)1184 Route_Scan_Reload(void)
1185 {
1186 struct mbuf **routehash, mb;
1187 register struct mbuf *m;
1188 struct ifnet ifnet;
1189 RTENTRY *rt;
1190 int i, table;
1191 register char *cp;
1192 char name[16], temp[16];
1193 static time_t Time_Of_Last_Reload;
1194 struct timeval now;
1195 int hashsize;
1196
1197 netsnmp_get_monotonic_clock(&now);
1198 if (Time_Of_Last_Reload + CACHE_TIME > now.tv_sec)
1199 return;
1200 Time_Of_Last_Reload = now.tv_sec;
1201
1202 /*
1203 * Makes sure we have SOME space allocated for new routing entries
1204 */
1205 if (!rthead) {
1206 rthead = (RTENTRY **) malloc(100 * sizeof(RTENTRY *));
1207 if (!rthead) {
1208 snmp_log(LOG_ERR, "route table malloc fail\n");
1209 return;
1210 }
1211 memset((char *) rthead, (0), 100 * sizeof(RTENTRY *));
1212 rtallocate = 100;
1213 }
1214
1215 /*
1216 * reset the routing table size to zero -- was a CMU memory leak
1217 */
1218 rtsize = 0;
1219
1220 for (table = 0; table < NUM_ROUTE_SYMBOLS; table++) {
1221 #ifdef sunV3
1222 hashsize = RTHASHSIZ;
1223 #else
1224 auto_nlist(RTHASHSIZE_SYMBOL, (char *) &hashsize,
1225 sizeof(hashsize));
1226 #endif
1227 routehash =
1228 (struct mbuf **) malloc(hashsize * sizeof(struct mbuf *));
1229 auto_nlist(route_symbols[table], (char *) routehash,
1230 hashsize * sizeof(struct mbuf *));
1231 for (i = 0; i < hashsize; i++) {
1232 if (routehash[i] == 0)
1233 continue;
1234 m = routehash[i];
1235 while (m) {
1236 /*
1237 * Dig the route out of the kernel...
1238 */
1239 if (!NETSNMP_KLOOKUP(m, (char *) &mb, sizeof(mb))) {
1240 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
1241 return;
1242 }
1243 m = mb.m_next;
1244 rt = mtod(&mb, RTENTRY *);
1245
1246 if (rt->rt_ifp != 0) {
1247
1248 if (!NETSNMP_KLOOKUP(rt->rt_ifp, (char *) &ifnet, sizeof(ifnet))) {
1249 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
1250 return;
1251 }
1252 if (!NETSNMP_KLOOKUP(ifnet.if_name, name, 16)) {
1253 DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
1254 return;
1255 }
1256 name[15] = '\0';
1257 cp = (char *) strchr(name, '\0');
1258 string_append_int(cp, ifnet.if_unit);
1259 if (strcmp(name, "lo0") == 0)
1260 continue;
1261
1262 Interface_Scan_Init();
1263 while (Interface_Scan_Next
1264 ((short *) &rt->rt_unit, temp, NULL,
1265 NULL) != 0) {
1266 if (strcmp(name, temp) == 0)
1267 break;
1268 }
1269 }
1270 /*
1271 * Allocate a block to hold it and add it to the database
1272 */
1273 if (rtsize >= rtallocate) {
1274 rthead =
1275 (RTENTRY **) realloc((char *) rthead,
1276 2 * rtallocate *
1277 sizeof(RTENTRY *));
1278 memset((char *) &rthead[rtallocate], (0),
1279 rtallocate * sizeof(RTENTRY *));
1280
1281 rtallocate *= 2;
1282 }
1283 if (!rthead[rtsize])
1284 rthead[rtsize] = (RTENTRY *) malloc(sizeof(RTENTRY));
1285 /*
1286 * * Add this to the database
1287 */
1288 memcpy((char *) rthead[rtsize], (char *) rt,
1289 sizeof(RTENTRY));
1290 rtsize++;
1291 }
1292 }
1293 free(routehash);
1294 }
1295 /*
1296 * Sort it!
1297 */
1298 qsort((char *) rthead, rtsize, sizeof(rthead[0]), qsort_compare);
1299 }
1300 #else
1301 #ifdef linux
1302 static void
Route_Scan_Reload(void)1303 Route_Scan_Reload(void)
1304 {
1305 FILE *in;
1306 char line[256];
1307 struct rtentry *rt;
1308 char name[16];
1309 static time_t Time_Of_Last_Reload;
1310 struct timeval now;
1311
1312 netsnmp_get_monotonic_clock(&now);
1313 if (Time_Of_Last_Reload + CACHE_TIME > now.tv_sec)
1314 return;
1315 Time_Of_Last_Reload = now.tv_sec;
1316
1317 /*
1318 * Makes sure we have SOME space allocated for new routing entries
1319 */
1320 if (!rthead) {
1321 rthead = (struct rtentry **) calloc(100, sizeof(struct rtentry *));
1322 if (!rthead) {
1323 snmp_log(LOG_ERR, "route table malloc fail\n");
1324 return;
1325 }
1326 rtallocate = 100;
1327 }
1328
1329 /*
1330 * fetch routes from the proc file-system:
1331 */
1332
1333 rtsize = 0;
1334
1335 if (!(in = fopen("/proc/net/route", "r"))) {
1336 NETSNMP_LOGONCE((LOG_ERR, "cannot open /proc/net/route - burps\n"));
1337 return;
1338 }
1339
1340 while (fgets(line, sizeof(line), in)) {
1341 struct rtentry rtent;
1342 char rtent_name[32];
1343 int refcnt, metric;
1344 unsigned flags, use;
1345
1346 rt = &rtent;
1347 memset((char *) rt, (0), sizeof(*rt));
1348 rt->rt_dev = rtent_name;
1349
1350 /*
1351 * as with 1.99.14:
1352 * Iface Dest GW Flags RefCnt Use Metric Mask MTU Win IRTT
1353 * eth0 0A0A0A0A 00000000 05 0 0 0 FFFFFFFF 1500 0 0
1354 */
1355 if (8 != sscanf(line, "%s %x %x %x %d %u %d %x %*d %*d %*d\n",
1356 rt->rt_dev,
1357 &(((struct sockaddr_in *) &(rtent.rt_dst))->sin_addr.s_addr),
1358 &(((struct sockaddr_in *) &(rtent.rt_gateway))->sin_addr.s_addr),
1359 /*
1360 * XXX: fix type of the args
1361 */
1362 &flags, &refcnt, &use, &metric,
1363 &(((struct sockaddr_in *) &(rtent.rt_genmask))->sin_addr.s_addr)))
1364 continue;
1365
1366 strlcpy(name, rt->rt_dev, sizeof(name));
1367
1368 rt->rt_flags = flags, rt->rt_refcnt = refcnt;
1369 rt->rt_use = use, rt->rt_metric = metric;
1370
1371 rt->rt_unit = netsnmp_access_interface_index_find(name);
1372
1373 /*
1374 * Allocate a block to hold it and add it to the database
1375 */
1376 if (rtsize >= rtallocate) {
1377 rthead = (struct rtentry **) realloc((char *) rthead,
1378 2 * rtallocate *
1379 sizeof(struct rtentry *));
1380 memset(&rthead[rtallocate], 0,
1381 rtallocate * sizeof(struct rtentry *));
1382 rtallocate *= 2;
1383 }
1384 if (!rthead[rtsize])
1385 rthead[rtsize] =
1386 (struct rtentry *) malloc(sizeof(struct rtentry));
1387 /*
1388 * Add this to the database
1389 */
1390 memcpy((char *) rthead[rtsize], (char *) rt,
1391 sizeof(struct rtentry));
1392 rtsize++;
1393 }
1394
1395 fclose(in);
1396
1397 /*
1398 * Sort it!
1399 */
1400 qsort((char *) rthead, rtsize, sizeof(rthead[0]), qsort_compare);
1401 }
1402 #endif
1403 #endif
1404 #endif
1405
1406
1407 #ifndef solaris2
1408 /*
1409 * Create a host table
1410 */
1411 #ifdef hpux11
1412 static int
qsort_compare(const void * v1,const void * v2)1413 qsort_compare(const void *v1, const void *v2)
1414 {
1415 const mib_ipRouteEnt *r1 = (const mib_ipRouteEnt *) v1;
1416 const mib_ipRouteEnt *r2 = (const mib_ipRouteEnt *) v2;
1417 /*
1418 * Do the comparison
1419 */
1420 if (r1->Dest == r2->Dest)
1421 return (0);
1422 if (r1->Dest > r2->Dest)
1423 return (1);
1424 return (-1);
1425 }
1426 #else
1427 static int
qsort_compare(const void * v1,const void * v2)1428 qsort_compare(const void *v1, const void *v2)
1429 {
1430 RTENTRY * const *r1 = (RTENTRY * const *) v1;
1431 RTENTRY * const *r2 = (RTENTRY * const *) v2;
1432 #if NEED_KLGETSA
1433 register u_long dst1 =
1434 ntohl(klgetsa((const struct sockaddr_in *) (*r1)->rt_dst)->
1435 sin_addr.s_addr);
1436 register u_long dst2 =
1437 ntohl(klgetsa((const struct sockaddr_in *) (*r2)->rt_dst)->
1438 sin_addr.s_addr);
1439 #else
1440 register u_long dst1 =
1441 ntohl(((const struct sockaddr_in *) &((*r1)->rt_dst))->sin_addr.
1442 s_addr);
1443 register u_long dst2 =
1444 ntohl(((const struct sockaddr_in *) &((*r2)->rt_dst))->sin_addr.
1445 s_addr);
1446 #endif /* NEED_KLGETSA */
1447
1448 /*
1449 * Do the comparison
1450 */
1451 if (dst1 == dst2)
1452 return (0);
1453 if (dst1 > dst2)
1454 return (1);
1455 return (-1);
1456 }
1457 #endif /* hpux11 */
1458 #endif /* not USE_SYSCTL_ROUTE_DUMP */
1459
1460 #endif /* solaris2 */
1461
1462 #elif defined(HAVE_IPHLPAPI_H) /* WIN32 cygwin */
1463 #include <iphlpapi.h>
1464 #ifndef MIB_IPPROTO_NETMGMT
1465 #define MIB_IPPROTO_NETMGMT 3
1466 #endif
1467
1468 PMIB_IPFORWARDROW route_row;
1469 int create_flag;
1470 void
init_var_route(void)1471 init_var_route(void)
1472 {
1473 }
1474
1475 u_char *
var_ipRouteEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)1476 var_ipRouteEntry(struct variable *vp,
1477 oid * name,
1478 size_t * length,
1479 int exact, size_t * var_len, WriteMethod ** write_method)
1480 {
1481 /*
1482 * object identifier is of form:
1483 * 1.3.6.1.2.1.4.21.1.?.A.B.C.D, where A.B.C.D is IP address.
1484 * IPADDR starts at offset 10.
1485 */
1486 register int Save_Valid, result, RtIndex = 0;
1487 static int saveNameLen = 0, saveExact = 0, saveRtIndex =
1488 0, rtsize = 0;
1489 static oid saveName[MAX_OID_LEN], Current[MAX_OID_LEN];
1490 u_char *cp;
1491 oid *op;
1492 DWORD status = NO_ERROR;
1493 DWORD dwActualSize = 0;
1494 static PMIB_IPFORWARDTABLE pIpRtrTable = NULL;
1495 struct timeval now;
1496 static time_t Time_Of_Last_Reload;
1497 static in_addr_t addr_ret;
1498
1499
1500 /**
1501 ** this optimisation fails, if there is only a single route avail.
1502 ** it is a very special case, but better leave it out ...
1503 **/
1504 #if NETSNMP_NO_DUMMY_VALUES
1505 saveNameLen = 0;
1506 #endif
1507 if (route_row == NULL) {
1508 /*
1509 * Free allocated memory in case of SET request's FREE phase
1510 */
1511 route_row = (PMIB_IPFORWARDROW) malloc(sizeof(MIB_IPFORWARDROW));
1512 }
1513 netsnmp_get_monotonic_clock(&now);
1514 if ((rtsize <= 1) || (Time_Of_Last_Reload + 5 <= now.tv_sec))
1515 Save_Valid = 0;
1516 else
1517 /*
1518 * OPTIMIZATION:
1519 *
1520 * If the name was the same as the last name, with the possible
1521 * exception of the [9]th token, then don't read the routing table
1522 *
1523 */
1524
1525 if ((saveNameLen == (int) *length) && (saveExact == exact)) {
1526 register int temp = name[9];
1527 name[9] = 0;
1528 Save_Valid =
1529 (snmp_oid_compare(name, *length, saveName, saveNameLen) == 0);
1530 name[9] = temp;
1531 } else
1532 Save_Valid = 0;
1533
1534 if (Save_Valid) {
1535 register int temp = name[9]; /* Fix up 'lowest' found entry */
1536 memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
1537 name[9] = temp;
1538 *length = 14;
1539 RtIndex = saveRtIndex;
1540 } else {
1541 /*
1542 * fill in object part of name for current(less sizeof instance part)
1543 */
1544
1545 memcpy((char *) Current, (char *) vp->name,
1546 (int) (vp->namelen) * sizeof(oid));
1547
1548
1549 if ((Time_Of_Last_Reload + 5 <= now.tv_sec)
1550 || (pIpRtrTable == NULL)) {
1551 if (pIpRtrTable != NULL)
1552 free(pIpRtrTable);
1553 Time_Of_Last_Reload = now.tv_sec;
1554 /*
1555 * query for buffer size needed
1556 */
1557 status = GetIpForwardTable(pIpRtrTable, &dwActualSize, TRUE);
1558 if (status == ERROR_INSUFFICIENT_BUFFER) {
1559 pIpRtrTable = (PMIB_IPFORWARDTABLE) malloc(dwActualSize);
1560 if (pIpRtrTable != NULL) {
1561 /*
1562 * Get the sorted IP Route Table
1563 */
1564 status =
1565 GetIpForwardTable(pIpRtrTable, &dwActualSize,
1566 TRUE);
1567 }
1568 }
1569 }
1570 if (status == NO_ERROR) {
1571 rtsize = pIpRtrTable->dwNumEntries;
1572 for (RtIndex = 0; RtIndex < rtsize; RtIndex++) {
1573 cp = (u_char *) & pIpRtrTable->table[RtIndex].
1574 dwForwardDest;
1575 op = Current + 10;
1576 *op++ = *cp++;
1577 *op++ = *cp++;
1578 *op++ = *cp++;
1579 *op++ = *cp++;
1580
1581 result = snmp_oid_compare(name, *length, Current, 14);
1582 if ((exact && (result == 0)) || (!exact && (result < 0)))
1583 break;
1584 }
1585 }
1586 if (RtIndex >= rtsize) {
1587 /*
1588 * for creation of new row, only ipNetToMediaTable case is considered
1589 */
1590 if (*length == 14) {
1591 u_char dest_addr[4];
1592 MIB_IPFORWARDROW temp_row;
1593
1594 create_flag = 1;
1595 *write_method = write_rte;
1596 dest_addr[0] = (u_char) name[10];
1597 dest_addr[1] = (u_char) name[11];
1598 dest_addr[2] = (u_char) name[12];
1599 dest_addr[3] = (u_char) name[13];
1600 memset(&temp_row, 0, sizeof(temp_row));
1601 temp_row.dwForwardDest = *((DWORD *) dest_addr);
1602 temp_row.dwForwardPolicy = 0;
1603 temp_row.dwForwardProto = MIB_IPPROTO_NETMGMT;
1604 *route_row = temp_row;
1605 }
1606 free(pIpRtrTable);
1607 pIpRtrTable = NULL;
1608 rtsize = 0;
1609 return (NULL);
1610 }
1611 create_flag = 0;
1612 /*
1613 * Save in the 'cache'
1614 */
1615 memcpy((char *) saveName, (char *) name,
1616 SNMP_MIN(*length, MAX_OID_LEN) * sizeof(oid));
1617 saveName[9] = 0;
1618 saveNameLen = *length;
1619 saveExact = exact;
1620 saveRtIndex = RtIndex;
1621
1622 /*
1623 * Return the name
1624 */
1625 memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
1626 *length = 14;
1627 }
1628 *var_len = sizeof(long_return);
1629 *route_row = pIpRtrTable->table[RtIndex];
1630
1631 switch (vp->magic) {
1632 case IPROUTEDEST:
1633 *var_len = sizeof(addr_ret);
1634 *write_method = write_rte;
1635 addr_ret = pIpRtrTable->table[RtIndex].dwForwardDest;
1636 return (u_char *) & addr_ret;
1637 case IPROUTEIFINDEX:
1638 *write_method = write_rte;
1639 long_return = pIpRtrTable->table[RtIndex].dwForwardIfIndex;
1640 return (u_char *) & long_return;
1641 case IPROUTEMETRIC1:
1642 *write_method = write_rte;
1643 long_return = pIpRtrTable->table[RtIndex].dwForwardMetric1;
1644 return (u_char *) & long_return;
1645 case IPROUTEMETRIC2:
1646 *write_method = write_rte;
1647 long_return = pIpRtrTable->table[RtIndex].dwForwardMetric2;
1648 return (u_char *) & long_return;
1649 case IPROUTEMETRIC3:
1650 *write_method = write_rte;
1651 long_return = pIpRtrTable->table[RtIndex].dwForwardMetric3;
1652 return (u_char *) & long_return;
1653 case IPROUTEMETRIC4:
1654 *write_method = write_rte;
1655 long_return = pIpRtrTable->table[RtIndex].dwForwardMetric4;
1656 return (u_char *) & long_return;
1657 case IPROUTEMETRIC5:
1658 *write_method = write_rte;
1659 long_return = pIpRtrTable->table[RtIndex].dwForwardMetric5;
1660 return (u_char *) & long_return;
1661 case IPROUTENEXTHOP:
1662 *var_len = sizeof(addr_ret);
1663 *write_method = write_rte;
1664 addr_ret = pIpRtrTable->table[RtIndex].dwForwardNextHop;
1665 return (u_char *) & addr_ret;
1666 case IPROUTETYPE:
1667 *write_method = write_rte;
1668 long_return = pIpRtrTable->table[RtIndex].dwForwardType;
1669 return (u_char *) & long_return;
1670 case IPROUTEPROTO:
1671 long_return = pIpRtrTable->table[RtIndex].dwForwardProto;
1672 return (u_char *) & long_return;
1673 case IPROUTEAGE:
1674 *write_method = write_rte;
1675 long_return = pIpRtrTable->table[RtIndex].dwForwardAge;
1676 return (u_char *) & long_return;
1677 case IPROUTEMASK:
1678 *write_method = write_rte;
1679 *var_len = sizeof(addr_ret);
1680 addr_ret = pIpRtrTable->table[RtIndex].dwForwardMask;
1681 return (u_char *) & addr_ret;
1682 case IPROUTEINFO:
1683 *var_len = nullOidLen;
1684 return (u_char *) nullOid;
1685 default:
1686 DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
1687 vp->magic));
1688 }
1689 return NULL;
1690 }
1691
1692 #endif /* WIN32 cygwin */
1693
1694 #else /* NETSNMP_CAN_USE_SYSCTL */
1695
1696 static
1697 TAILQ_HEAD(, snmprt)
1698 rthead;
1699 static char *rtbuf;
1700 static size_t rtbuflen;
1701 static time_t lasttime;
1702
1703 struct snmprt {
1704 TAILQ_ENTRY(snmprt) link;
1705 struct rt_msghdr *hdr;
1706 struct in_addr dest;
1707 struct in_addr gateway;
1708 struct in_addr netmask;
1709 int index;
1710 struct in_addr ifa;
1711 };
1712
1713 static void
rtmsg(struct rt_msghdr * rtm)1714 rtmsg(struct rt_msghdr *rtm)
1715 {
1716 struct snmprt *rt;
1717 struct sockaddr *sa;
1718 int bit, gotdest, gotmask;
1719
1720 rt = malloc(sizeof *rt);
1721 if (rt == 0)
1722 return;
1723 rt->hdr = rtm;
1724 rt->ifa.s_addr = 0;
1725 rt->dest = rt->gateway = rt->netmask = rt->ifa;
1726 rt->index = rtm->rtm_index;
1727
1728 gotdest = gotmask = 0;
1729 sa = (struct sockaddr *) (rtm + 1);
1730 for (bit = 1; ((char *) sa < (char *) rtm + rtm->rtm_msglen) && bit;
1731 bit <<= 1) {
1732 if ((rtm->rtm_addrs & bit) == 0)
1733 continue;
1734 switch (bit) {
1735 case RTA_DST:
1736 #define satosin(sa) ((struct sockaddr_in *)(sa))
1737 rt->dest = satosin(sa)->sin_addr;
1738 gotdest = 1;
1739 break;
1740 case RTA_GATEWAY:
1741 if (sa->sa_family == AF_INET)
1742 rt->gateway = satosin(sa)->sin_addr;
1743 break;
1744 case RTA_NETMASK:
1745 if (sa->sa_len >= offsetof(struct sockaddr_in, sin_addr))
1746 rt->netmask = satosin(sa)->sin_addr;
1747 gotmask = 1;
1748 break;
1749 case RTA_IFA:
1750 if (sa->sa_family == AF_INET)
1751 rt->ifa = satosin(sa)->sin_addr;
1752 break;
1753 }
1754 /*
1755 * from rtsock.c
1756 */
1757 #define ROUNDUP(a) \
1758 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1759 sa = (struct sockaddr *) ((char *) sa + ROUNDUP(sa->sa_len));
1760 }
1761 if (!gotdest) {
1762 /*
1763 * XXX can't happen if code above is correct
1764 */
1765 snmp_log(LOG_ERR, "route no dest?\n");
1766 free(rt);
1767 } else {
1768 /*
1769 * If no mask provided, it was a host route.
1770 */
1771 if (!gotmask)
1772 rt->netmask.s_addr = ~0;
1773 TAILQ_INSERT_TAIL(&rthead, rt, link);
1774 }
1775 }
1776
1777 static int
suck_krt(int force)1778 suck_krt(int force)
1779 {
1780 time_t now;
1781 struct snmprt *rt, *next;
1782 size_t len;
1783 static int name[6] =
1784 { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0 };
1785 char *cp;
1786 struct rt_msghdr *rtm;
1787
1788 time(&now);
1789 if (now < (lasttime + CACHE_TIME) && !force)
1790 return 0;
1791 lasttime = now;
1792
1793 for (rt = rthead.tqh_first; rt; rt = next) {
1794 next = rt->link.tqe_next;
1795 free(rt);
1796 }
1797 TAILQ_INIT(&rthead);
1798
1799 if (sysctl(name, 6, 0, &len, 0, 0) < 0) {
1800 syslog(LOG_WARNING, "sysctl net-route-dump: %m");
1801 return -1;
1802 }
1803
1804 if (len > rtbuflen) {
1805 char *newbuf;
1806 newbuf = realloc(rtbuf, len);
1807 if (newbuf == 0)
1808 return -1;
1809 rtbuf = newbuf;
1810 rtbuflen = len;
1811 }
1812
1813 if (sysctl(name, 6, rtbuf, &len, 0, 0) < 0) {
1814 syslog(LOG_WARNING, "sysctl net-route-dump: %m");
1815 return -1;
1816 }
1817
1818 cp = rtbuf;
1819 while (cp < rtbuf + len) {
1820 rtm = (struct rt_msghdr *) cp;
1821 /*
1822 * NB:
1823 * You might want to exclude routes with RTF_WASCLONED
1824 * set. This keeps the cloned host routes (and thus also
1825 * ARP entries) out of the routing table. Thus, it also
1826 * presents management stations with an incomplete view.
1827 * I believe that it should be possible for a management
1828 * station to examine (and perhaps delete) such routes.
1829 */
1830 if (rtm->rtm_version == RTM_VERSION && rtm->rtm_type == RTM_GET)
1831 rtmsg(rtm);
1832 cp += rtm->rtm_msglen;
1833 }
1834 return 0;
1835 }
1836
1837 u_char *
var_ipRouteEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)1838 var_ipRouteEntry(struct variable * vp,
1839 oid * name,
1840 size_t * length,
1841 int exact, size_t * var_len, WriteMethod ** write_method)
1842 {
1843 /*
1844 * object identifier is of form:
1845 * 1.3.6.1.2.1.4.21.1.1.A.B.C.D, where A.B.C.D is IP address.
1846 * IPADDR starts at offset 10.
1847 */
1848 int Save_Valid, result;
1849 u_char *cp;
1850 oid *op;
1851 struct snmprt *rt;
1852 static struct snmprt *savert;
1853 static int saveNameLen, saveExact;
1854 static oid saveName[14], Current[14];
1855 static in_addr_t addr_ret;
1856
1857 *write_method = NULL; /* write_rte; XXX: SET support not really implemented */
1858
1859 #if 0
1860 /*
1861 * OPTIMIZATION:
1862 *
1863 * If the name was the same as the last name, with the possible
1864 * exception of the [9]th token, then don't read the routing table
1865 *
1866 */
1867
1868 if ((saveNameLen == *length) && (saveExact == exact)) {
1869 int temp = name[9];
1870 name[9] = 0;
1871 Save_Valid =
1872 !snmp_oid_compare(name, *length, saveName, saveNameLen);
1873 name[9] = temp;
1874 } else {
1875 Save_Valid = 0;
1876 }
1877 #else
1878 Save_Valid = 0;
1879 #endif
1880
1881 if (Save_Valid) {
1882 int temp = name[9];
1883 memcpy(name, Current, 14 * sizeof(oid));
1884 name[9] = temp;
1885 *length = 14;
1886 rt = savert;
1887 } else {
1888 /*
1889 * fill in object part of name for current
1890 * (less sizeof instance part)
1891 */
1892
1893 memcpy(Current, vp->name, SNMP_MIN(sizeof(Current), (int)(vp->namelen) * sizeof(oid)));
1894
1895 suck_krt(0);
1896
1897 for (rt = rthead.tqh_first; rt; rt = rt->link.tqe_next) {
1898 op = Current + 10;
1899 cp = (u_char *) & rt->dest;
1900 *op++ = *cp++;
1901 *op++ = *cp++;
1902 *op++ = *cp++;
1903 *op++ = *cp++;
1904 result = snmp_oid_compare(name, *length, Current, 14);
1905 if ((exact && (result == 0))
1906 || (!exact && (result < 0)))
1907 break;
1908 }
1909 if (rt == NULL)
1910 return NULL;
1911
1912 /*
1913 * Save in the 'cache'
1914 */
1915 memcpy(saveName, name, SNMP_MIN(sizeof(saveName), *length * sizeof(oid)));
1916 saveName[9] = 0;
1917 saveNameLen = *length;
1918 saveExact = exact;
1919 savert = rt;
1920
1921 /*
1922 * Return the name
1923 */
1924 memcpy(name, Current, 14 * sizeof(oid));
1925 *length = 14;
1926 }
1927
1928 *var_len = sizeof(long_return);
1929
1930 switch (vp->magic) {
1931 case IPROUTEDEST:
1932 addr_ret = rt->dest.s_addr;
1933 *var_len = sizeof(addr_ret);
1934 return (u_char *) & addr_ret;
1935
1936 case IPROUTEIFINDEX:
1937 long_return = rt->index;
1938 return (u_char *) & long_return;
1939
1940 case IPROUTEMETRIC1:
1941 long_return = (rt->hdr->rtm_flags & RTF_GATEWAY) ? 1 : 0;
1942 return (u_char *) & long_return;
1943 case IPROUTEMETRIC2:
1944 long_return = rt->hdr->rtm_rmx.rmx_rtt;
1945 return (u_char *) & long_return;
1946 case IPROUTEMETRIC3:
1947 long_return = rt->hdr->rtm_rmx.rmx_rttvar;
1948 return (u_char *) & long_return;
1949 case IPROUTEMETRIC4:
1950 long_return = rt->hdr->rtm_rmx.rmx_ssthresh;
1951 return (u_char *) & long_return;
1952 case IPROUTEMETRIC5:
1953 long_return = rt->hdr->rtm_rmx.rmx_mtu;
1954 return (u_char *) & long_return;
1955
1956 case IPROUTENEXTHOP:
1957 *var_len = sizeof(addr_ret);
1958 if (rt->gateway.s_addr == 0 && rt->ifa.s_addr == 0)
1959 addr_ret = 0;
1960 else if (rt->gateway.s_addr == 0)
1961 addr_ret = rt->ifa.s_addr;
1962 else
1963 addr_ret = rt->gateway.s_addr;
1964 return (u_char *) & addr_ret;
1965
1966 case IPROUTETYPE:
1967 if (rt->hdr->rtm_flags & RTF_UP) {
1968 if (rt->hdr->rtm_flags & RTF_GATEWAY) {
1969 long_return = 4; /* indirect(4) */
1970 } else {
1971 long_return = 3; /* direct(3) */
1972 }
1973 } else {
1974 long_return = 2; /* invalid(2) */
1975 }
1976 return (u_char *) & long_return;
1977
1978 case IPROUTEPROTO:
1979 long_return = (rt->hdr->rtm_flags & RTF_DYNAMIC) ? 4 : 2;
1980 return (u_char *) & long_return;
1981
1982 case IPROUTEAGE:
1983 #if NETSNMP_NO_DUMMY_VALUES
1984 return NULL;
1985 #endif
1986 long_return = 0;
1987 return (u_char *) & long_return;
1988
1989 case IPROUTEMASK:
1990 addr_ret = rt->netmask.s_addr;
1991 *var_len = sizeof(addr_ret);
1992 return (u_char *) & addr_ret;
1993
1994 case IPROUTEINFO:
1995 *var_len = nullOidLen;
1996 return (u_char *) nullOid;
1997 default:
1998 DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
1999 vp->magic));
2000 }
2001 return NULL;
2002 }
2003
2004 void
init_var_route(void)2005 init_var_route(void)
2006 {
2007 ;
2008 }
2009
2010 #endif /* NETSNMP_CAN_USE_SYSCTL */
2011
2012 #if defined(HAVE_SYS_SYSCTL_H) && !defined(linux)
2013 /*
2014 * get_address()
2015 *
2016 * Traverse the address structures after a routing socket message and
2017 * extract a specific one.
2018 *
2019 * Some of this is peculiar to IRIX 6.2, which doesn't have sa_len in
2020 * the sockaddr structure yet. With sa_len, skipping an address entry
2021 * would be much easier.
2022 */
2023 #include <sys/un.h>
2024
2025 /*
2026 * returns the length of a socket structure
2027 */
2028
2029 size_t
snmp_socket_length(int family)2030 snmp_socket_length(int family)
2031 {
2032 size_t length;
2033
2034 switch (family) {
2035 #ifndef cygwin
2036 #if !defined (WIN32) && !defined (cygwin)
2037 #ifdef AF_UNIX
2038 case AF_UNIX:
2039 length = sizeof(struct sockaddr_un);
2040 break;
2041 #endif /* AF_UNIX */
2042 #endif
2043 #endif
2044
2045 #ifndef aix3
2046 #ifdef AF_LINK
2047 case AF_LINK:
2048 #ifdef _MAX_SA_LEN
2049 length = _MAX_SA_LEN;
2050 #elif SOCK_MAXADDRLEN
2051 length = SOCK_MAXADDRLEN;
2052 #else
2053 length = sizeof(struct sockaddr_dl);
2054 #endif
2055 break;
2056 #endif /* AF_LINK */
2057 #endif
2058
2059 case AF_INET:
2060 length = sizeof(struct sockaddr_in);
2061 break;
2062 default:
2063 length = sizeof(struct sockaddr);
2064 break;
2065 }
2066
2067 return length;
2068 }
2069
2070 const struct sockaddr *
get_address(const void * _ap,int addresses,int wanted)2071 get_address(const void *_ap, int addresses, int wanted)
2072 {
2073 const struct sockaddr *ap = (const struct sockaddr *) _ap;
2074 int iindex;
2075 int bitmask;
2076
2077 for (iindex = 0, bitmask = 1;
2078 iindex < RTAX_MAX; ++iindex, bitmask <<= 1) {
2079 if (bitmask == wanted) {
2080 if (bitmask & addresses) {
2081 return ap;
2082 } else {
2083 return 0;
2084 }
2085 } else if (bitmask & addresses) {
2086 unsigned length =
2087 (unsigned) snmp_socket_length(ap->sa_family);
2088 while (length % sizeof(long) != 0)
2089 ++length;
2090 ap = (const struct sockaddr *) ((const char *) ap + length);
2091 }
2092 }
2093 return 0;
2094 }
2095
2096 /*
2097 * get_in_address()
2098 *
2099 * Convenience function for the special case of get_address where an
2100 * AF_INET address is desired, and we're only interested in the in_addr
2101 * part.
2102 */
2103 const struct in_addr *
get_in_address(const void * ap,int addresses,int wanted)2104 get_in_address(const void *ap, int addresses, int wanted)
2105 {
2106 const struct sockaddr_in *a;
2107
2108 a = (const struct sockaddr_in *) get_address(ap, addresses, wanted);
2109 if (a == NULL)
2110 return NULL;
2111
2112 if (a->sin_family != AF_INET) {
2113 DEBUGMSGTL(("snmpd",
2114 "unknown socket family %d [AF_INET expected] in var_ipRouteEntry.\n",
2115 a->sin_family));
2116 }
2117 return &a->sin_addr;
2118 }
2119 #endif /* HAVE_SYS_SYSCTL_H */
2120