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