xref: /netbsd/usr.sbin/mrouted/snmp.c (revision 761f7beb)
1 /*	$NetBSD: snmp.c,v 1.11 2003/05/16 18:10:38 itojun Exp $	*/
2 
3 /*
4  * Copyright (c) 1992, 2001 Xerox Corporation.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without modification,
7  * are permitted provided that the following conditions are met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * Neither name of the Xerox, PARC, nor the names of its contributors may be used
17  * to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE XEROX CORPORATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "defs.h"
34 #include <netinet/in_var.h>
35 #include "snmp.h"
36 #include "snmplib/asn1.h"
37 #include "snmplib/party.h"
38 #include "snmplib/snmp_impl.h"
39 #define MROUTED
40 #include "snmpd/snmp_vars.h"
41 
42     in_port_t dest_port = 0;
43     int sdlen = 0;
44 
45 struct addrCache {
46     u_long addr;
47     int status;
48 #define UNUSED 0
49 #define USED   1
50 #define OLD 2
51 };
52 
53 static struct addrCache addrCache[10];
54 
55 /*
56  * Initialize the SNMP part of mrouted
57  */
58 int /* returns: 0 on success, true on error */
snmp_init(dest_port)59 snmp_init(dest_port)
60     in_port_t dest_port;
61 {
62    u_long myaddr;
63    int ret;
64    struct partyEntry *pp;
65    struct sockaddr_in  me;
66    int index, sd, portlist[32];
67 
68    init_snmp();
69    /* init_mib(); why was this here? */
70     if (read_party_database("/etc/party.conf") > 0){
71    fprintf(stderr, "Couldn't read party database from /etc/party.conf\n");
72    exit(0);
73     }
74     if (read_context_database("/etc/context.conf") > 0){
75    fprintf(stderr, "Couldn't read context database from /etc/context.conf\n");
76    exit(0);
77     }
78     if (read_acl_database("/etc/acl.conf") > 0){
79    fprintf(stderr, "Couldn't read acl database from /etc/acl.conf\n");
80    exit(0);
81     }
82     if (read_view_database("/etc/view.conf") > 0){
83    fprintf(stderr, "Couldn't read view database from /etc/view.conf\n");
84    exit(0);
85     }
86 
87     myaddr = get_myaddr();
88     if (ret = agent_party_init(myaddr, ".1.3.6.1")){
89    if (ret == 1){
90        fprintf(stderr, "Conflict found with initial noAuth/noPriv parties... continuing\n");
91    } else if (ret == -1){
92        fprintf(stderr, "Error installing initial noAuth/noPriv parties, exiting\n");
93        exit(1);
94    } else {
95        fprintf(stderr, "Unknown error, exiting\n");
96        exit(2);
97    }
98     }
99 
100     printf("Opening port(s): ");
101     fflush(stdout);
102     party_scanInit();
103     for(pp = party_scanNext(); pp; pp = party_scanNext()){
104    if ((pp->partyTDomain != DOMAINSNMPUDP)
105        || bcmp((char *)&myaddr, pp->partyTAddress, 4))
106        continue;  /* don't listen for non-local parties */
107 
108    dest_port = 0;
109    bcopy(pp->partyTAddress + 4, &dest_port, 2);
110    for(index = 0; index < sdlen; index++)
111        if (dest_port == portlist[index])
112       break;
113    if (index < sdlen)  /* found a hit before the end of the list */
114        continue;
115    printf("%u ", dest_port);
116    fflush(stdout);
117    /* Set up connections */
118    sd = socket(AF_INET, SOCK_DGRAM, 0);
119    if (sd < 0){
120        perror("socket");
121        return 1;
122    }
123    memset(&me, 0, sizeof(me));
124    me.sin_family = AF_INET;
125    me.sin_addr.s_addr = INADDR_ANY;
126    /* already in network byte order (I think) */
127    me.sin_port = dest_port;
128    if (bind(sd, (struct sockaddr *)&me, sizeof(me)) != 0){
129        perror("bind");
130        return 2;
131    }
132    register_input_handler(sd, snmp_read_packet);
133    portlist[sdlen] = dest_port;
134    if (++sdlen == 32){
135        printf("No more sockets... ignoring rest of file\n");
136        break;
137    }
138     }
139     printf("\n");
140     bzero((char *)addrCache, sizeof(addrCache));
141 }
142 
143 /*
144  * Place an IP address into an OID starting at element n
145  */
146 void
put_address(name,addr,n)147 put_address(name, addr, n)
148    oid	 *name;
149    u_long addr;
150    int n;
151 {
152    int i;
153 
154    for (i=n+3; i>=n+0; i--) {
155       name[i] = addr & 0xFF;
156       addr >>= 8;
157    }
158 }
159 
160 /* Get an IP address from an OID starting at element n */
161 int
get_address(name,length,addr,n)162 get_address(name, length, addr, n)
163    oid	 *name;
164    int	  length;
165    u_long *addr;
166    int n;
167 {
168    int i;
169    int ok = 1;
170 
171    (*addr) = 0;
172 
173    if (length < n+4)
174       return 0;
175 
176    for (i=n; i<n+4; i++) {
177       (*addr) <<= 8;
178       if (i >= length)
179           ok = 0;
180       else
181          (*addr) |= name[i];
182    }
183    return ok;
184 }
185 
186 /*
187  * Implements scalar objects from DVMRP and Multicast MIBs
188  */
189 u_char *
o_scalar(vp,name,length,exact,var_len,write_method)190 o_scalar(vp, name, length, exact, var_len, write_method)
191     struct variable *vp;   /* IN - pointer to variable entry that points here */
192     oid	*name;	    /* IN/OUT - input name requested, output name found */
193     int	*length;    /* IN/OUT - length of input and output oid's */
194     int			exact;	    /* IN - TRUE if an exact match was requested. */
195     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
196     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
197 {
198     int result;
199 
200     *write_method = 0;
201     result = compare(name, *length, vp->name, (int)vp->namelen);
202     if ((exact && (result != 0)) || (!exact && (result >= 0)))
203    return NULL;
204 
205 	bcopy((char *)vp->name, (char *)name,
206      (int)vp->namelen * sizeof(oid));
207 	*length = vp->namelen;
208 	*var_len = sizeof(long);
209 
210     switch (vp->magic) {
211 
212     case ipMRouteEnable:
213        long_return = 1;
214        return (u_char *) &long_return;
215 
216     case dvmrpVersion: {
217        static char buff[15];
218 
219        snprintf(buff, sizeof(buff), "mrouted%d.%d", PROTOCOL_VERSION,
220 	       MROUTED_VERSION);
221        *var_len = strlen(buff);
222        return (u_char *)buff;
223     }
224 
225     case dvmrpGenerationId:
226        long_return = dvmrp_genid;
227        return (u_char *) &long_return;
228 
229     default:
230        ERROR("");
231     }
232     return NULL;
233 }
234 
235 /*
236  * Find if a specific scoped boundary exists on a Vif
237  */
238 struct vif_acl *
find_boundary(vifi,addr,mask)239 find_boundary(vifi, addr, mask)
240    vifi_t vifi;
241    u_long addr;
242    u_long mask;
243 {
244    struct vif_acl *n;
245 
246    for (n = uvifs[vifi].uv_acl; n != NULL; n = n->acl_next) {
247       if (addr == n->acl_addr && mask==n->acl_mask)
248          return n;
249    }
250    return NULL;
251 }
252 
253 /*
254  * Find the lowest boundary >= (V,A,M) spec
255  */
256 struct vif_acl *
next_boundary(vifi,addr,mask)257 next_boundary(vifi, addr, mask)
258    vifi_t *vifi;
259    u_long  addr;
260    u_long  mask;
261 {
262    struct vif_acl *bestn, *n;
263    int  i;
264 
265    for (i = *vifi; i < numvifs; i++) {
266       bestn = NULL;
267       for (n = uvifs[i].uv_acl; n; n=n->acl_next) {
268          if ((i > *vifi || n->acl_addr > addr
269            || (n->acl_addr == addr && n->acl_mask >= mask))
270           && (!bestn || n->acl_addr < bestn->acl_addr
271            || (n->acl_addr==bestn->acl_addr && n->acl_mask<bestn->acl_mask)))
272             bestn = n;
273       }
274       if (bestn) {
275          *vifi = i;
276          return bestn;
277       }
278    }
279    return NULL;
280 }
281 
282 /*
283  * Implements the Boundary Table portion of the DVMRP MIB
284  */
285 u_char *
o_dvmrpBoundaryTable(vp,name,length,exact,var_len,write_method)286 o_dvmrpBoundaryTable(vp, name, length, exact, var_len, write_method)
287     struct variable *vp;   /* IN - pointer to variable entry that points here */
288     oid	*name;	    /* IN/OUT - input name requested, output name found */
289     int	*length;    /* IN/OUT - length of input and output oid's */
290     int			exact;	    /* IN - TRUE if an exact match was requested. */
291     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
292     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
293 {
294     vifi_t     vifi;
295     u_long	   addr, mask;
296     struct vif_acl *bound;
297     oid        newname[MAX_NAME_LEN];
298     int        len;
299 
300     /* Copy name OID to new OID */
301     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
302 
303     if (exact) {
304 	    if (*length != vp->namelen + 9)
305 		return NULL;
306 
307       if ((vifi = name[vp->namelen]) >= numvifs)
308       return NULL;
309 
310       if (!get_address(name, *length, &addr, vp->namelen+1)
311        || !get_address(name, *length, &mask, vp->namelen+5))
312 		return NULL;
313 
314       if (!(bound = find_boundary(vifi, addr, mask)))
315 		return NULL;
316 
317        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
318 	 } else {
319        len = *length;
320        if (compare(name, *length, vp->name, vp->namelen) < 0)
321           len = vp->namelen;
322 
323 	    if (len < vp->namelen + 9) { /* get first entry */
324 
325          if (len == vp->namelen) {
326             vifi = addr = mask = 0;
327          } else {
328             vifi = name[vp->namelen];
329             get_address(name, len, &addr, vp->namelen+1);
330             get_address(name, len, &mask, vp->namelen+5);
331          }
332 
333          bound = next_boundary(&vifi,addr,mask);
334          if (!bound)
335             return NULL;
336 
337    		newname[vp->namelen] = vifi;
338          put_address(newname, bound->acl_addr, vp->namelen+1);
339          put_address(newname, bound->acl_mask, vp->namelen+5);
340 	    } else {  /* get next entry given previous */
341 		   vifi = name[vp->namelen];
342          get_address(name, *length, &addr, vp->namelen+1);
343          get_address(name, *length, &mask, vp->namelen+5);
344 
345          if (!(bound = next_boundary(&vifi,addr,mask+1)))
346             return NULL;
347 
348 		   newname[vp->namelen] = vifi;
349          put_address(newname, bound->acl_addr, vp->namelen+1);
350          put_address(newname, bound->acl_mask, vp->namelen+5);
351 	    }
352     }
353 
354     /* Save new OID */
355     *length = vp->namelen + 9;
356     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
357     *write_method = 0;
358     *var_len = sizeof(long);
359 
360     switch (vp->magic) {
361 
362    case dvmrpBoundaryVifIndex:
363        long_return = vifi;
364        return (u_char *) &long_return;
365 
366     default:
367        ERROR("");
368     }
369     return NULL;
370 }
371 
372 /*
373  * Find the lowest neighbor >= (V,A) spec
374  */
375 struct listaddr *
next_neighbor(vifi,addr)376 next_neighbor(vifi, addr)
377    vifi_t *vifi;
378    u_long  addr;
379 {
380    struct listaddr *bestn, *n;
381    int  i;
382 
383    for (i = *vifi; i < numvifs; i++) {
384       bestn = NULL;
385       for (n = uvifs[i].uv_neighbors; n; n=n->al_next) {
386          if ((i > *vifi || n->al_addr >= addr)
387           && (!bestn || n->al_addr < bestn->al_addr))
388             bestn = n;
389       }
390       if (bestn) {
391          *vifi = i;
392          return bestn;
393       }
394    }
395    return NULL;
396 }
397 
398 /*
399  * Find a neighbor, if it exists off a given Vif
400  */
401 struct listaddr *
find_neighbor(vifi,addr)402 find_neighbor(vifi, addr)
403    vifi_t vifi;
404    u_long addr;
405 {
406    struct listaddr *n;
407 
408    for (n = uvifs[vifi].uv_neighbors; n != NULL; n = n->al_next) {
409       if (addr == n->al_addr)
410          return n;
411    }
412    return NULL;
413 }
414 
415 u_char *
o_dvmrpNeighborTable(vp,name,length,exact,var_len,write_method)416 o_dvmrpNeighborTable(vp, name, length, exact, var_len, write_method)
417     struct variable *vp;   /* IN - pointer to variable entry that points here */
418     oid	*name;	    /* IN/OUT - input name requested, output name found */
419     int	*length;    /* IN/OUT - length of input and output oid's */
420     int			exact;	    /* IN - TRUE if an exact match was requested. */
421     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
422     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
423 {
424     vifi_t     vifi;
425     u_long     addr, mask;
426     struct listaddr *neighbor;
427     oid        newname[MAX_NAME_LEN];
428     int        len;
429 
430     /* Copy name OID to new OID */
431     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
432 
433     if (exact) {
434 	    if (*length != vp->namelen + 5)
435 		return NULL;
436 
437       if ((vifi = name[vp->namelen]) >= numvifs)
438       return NULL;
439 
440       if (!get_address(name, *length, &addr, vp->namelen+1))
441 		return NULL;
442 
443       if (!(neighbor = find_neighbor(vifi, addr)))
444 		return NULL;
445 
446        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
447 	 } else {
448        len = *length;
449        if (compare(name, *length, vp->name, vp->namelen) < 0)
450           len = vp->namelen;
451 
452 	    if (len < vp->namelen + 5) { /* get first entry */
453 
454          if (len == vp->namelen) {
455             vifi = addr = 0;
456          } else {
457             vifi = name[vp->namelen];
458             get_address(name, len, &addr, vp->namelen+1);
459          }
460 
461          neighbor = next_neighbor(&vifi,addr);
462          if (!neighbor)
463             return NULL;
464 
465    		newname[vp->namelen] = vifi;
466          put_address(newname, neighbor->al_addr, vp->namelen+1);
467 	    } else {  /* get next entry given previous */
468 		   vifi = name[vp->namelen];
469          get_address(name, *length, &addr, vp->namelen+1);
470 
471          if (!(neighbor = next_neighbor(&vifi,addr+1)))
472             return NULL;
473 
474 		   newname[vp->namelen] = vifi;
475          put_address(newname, neighbor->al_addr, vp->namelen+1);
476 	    }
477     }
478 
479     /* Save new OID */
480     *length = vp->namelen + 5;
481     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
482     *write_method = 0;
483     *var_len = sizeof(long);
484 
485     switch (vp->magic) {
486 
487    case dvmrpNeighborUpTime: {
488        time_t currtime;
489        time(&currtime);
490        long_return = (currtime - neighbor->al_ctime)*100;
491        return (u_char *) &long_return;
492    }
493 
494    case dvmrpNeighborExpiryTime:
495        long_return = (NEIGHBOR_EXPIRE_TIME - neighbor->al_timer
496         + secs_remaining_offset()) * 100;
497        return (u_char *) &long_return;
498 
499    case dvmrpNeighborVersion: {
500        static char buff[15];
501 
502        snprintf(buff, sizeof(buff), "%d.%d", neighbor->al_pv, neighbor->al_mv);
503        *var_len = strlen(buff);
504        return (u_char *)buff;
505    }
506 
507    case dvmrpNeighborGenerationId:
508        long_return = neighbor->al_genid;
509        return (u_char *) &long_return;
510 
511     default:
512        ERROR("");
513     }
514     return NULL;
515 }
516 
517 /* Look up ifIndex given uvifs[ifnum].uv_lcl_addr */
518 struct in_ifaddr *        /* returns: in_ifaddr structure, or null on error */
ipaddr_to_ifindex(ipaddr,ifIndex)519 ipaddr_to_ifindex(ipaddr, ifIndex)
520    u_long ipaddr;
521    int   *ifIndex;
522 {
523     int interface;
524 static struct in_ifaddr in_ifaddr;
525 
526     Interface_Scan_Init();
527     for (;;) {
528        if (Interface_Scan_Next(&interface, (char *)0, NULL, &in_ifaddr) == 0)
529           return NULL;
530 
531        if (((struct sockaddr_in *) &(in_ifaddr.ia_addr))->sin_addr.s_addr
532         == ipaddr) {
533           *ifIndex = interface;
534           return &in_ifaddr;
535        }
536     }
537 }
538 
539 /*
540  * Find if a specific scoped boundary exists on a Vif
541  */
542 struct listaddr *
find_cache(grp,vifi)543 find_cache(grp, vifi)
544    u_long grp;
545    vifi_t vifi;
546 {
547    struct listaddr *n;
548 
549    for (n = uvifs[vifi].uv_groups; n != NULL; n = n->al_next) {
550       if (grp == n->al_addr)
551          return n;
552    }
553    return NULL;
554 }
555 
556 /*
557  * Find the next group cache entry >= (A,V) spec
558  */
559 struct listaddr *
next_cache(addr,vifi)560 next_cache(addr, vifi)
561    u_long  addr;
562    vifi_t *vifi;
563 {
564    struct listaddr *bestn=NULL, *n;
565    int  i, besti;
566 
567    /* Step through all entries looking for the next one */
568    for (i = 0; i < numvifs; i++) {
569       for (n = uvifs[i].uv_groups; n; n=n->al_next) {
570          if ((n->al_addr > addr || (n->al_addr == addr && i >= *vifi))
571           && (!bestn || n->al_addr < bestn->al_addr
572            || (n->al_addr == bestn->al_addr && i < besti))) {
573             bestn = n;
574             besti = i;
575          }
576       }
577    }
578 
579    if (bestn) {
580       *vifi = besti;
581       return bestn;
582    }
583    return NULL;
584 }
585 
586 /*
587  * Implements the IGMP Cache Table portion of the IGMP MIB
588  */
589 u_char *
o_igmpCacheTable(vp,name,length,exact,var_len,write_method)590 o_igmpCacheTable(vp, name, length, exact, var_len, write_method)
591     struct variable *vp;   /* IN - pointer to variable entry that points here */
592     oid	*name;	    /* IN/OUT - input name requested, output name found */
593     int	*length;    /* IN/OUT - length of input and output oid's */
594     int			exact;	    /* IN - TRUE if an exact match was requested. */
595     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
596     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
597 {
598     vifi_t     vifi;
599     u_long     grp;
600     int	      ifIndex;
601     struct listaddr *cache;
602     oid        newname[MAX_NAME_LEN];
603     int        len;
604     struct in_ifaddr *in_ifaddr;
605     struct in_multi   in_multi, *inm;
606 
607     /* Copy name OID to new OID */
608     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
609 
610     if (exact) {
611 	    if (*length != vp->namelen + 5)
612 		return NULL;
613 
614       if ((vifi = name[vp->namelen+4]) >= numvifs)
615       return NULL;
616 
617       if (!get_address(name, *length, &grp, vp->namelen))
618 		return NULL;
619 
620       if (!(cache = find_cache(grp, vifi)))
621 		return NULL;
622 
623        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
624 	 } else {
625        len = *length;
626        if (compare(name, *length, vp->name, vp->namelen) < 0)
627           len = vp->namelen;
628 
629 	    if (len < vp->namelen + 5) { /* get first entry */
630 
631          if (len == vp->namelen) {
632             vifi = grp = 0;
633          } else {
634             get_address(name, len, &grp, vp->namelen);
635             vifi = name[vp->namelen+4];
636          }
637 
638          cache = next_cache(grp,&vifi);
639          if (!cache)
640             return NULL;
641 
642          put_address(newname, cache->al_addr, vp->namelen);
643    		newname[vp->namelen+4] = vifi;
644 	    } else {  /* get next entry given previous */
645          get_address(name, *length, &grp, vp->namelen);
646 		   vifi = name[vp->namelen+4]+1;
647 
648          if (!(cache = next_cache(grp,&vifi)))
649             return NULL;
650 
651          put_address(newname, cache->al_addr, vp->namelen);
652 		   newname[vp->namelen+4] = vifi;
653 	    }
654     }
655 
656     /* Save new OID */
657     *length = vp->namelen + 5;
658     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
659     *write_method = 0;
660     *var_len = sizeof(long);
661 
662     /* Look up ifIndex given uvifs[vifi].uv_lcl_addr */
663     in_ifaddr = ipaddr_to_ifindex(uvifs[vifi].uv_lcl_addr, &ifIndex);
664 
665     switch (vp->magic) {
666 
667    case igmpCacheSelf:
668        inm = in_ifaddr->ia_multiaddrs;
669        while (inm) {
670           klookup( (int)inm, (char *)&in_multi, sizeof(in_multi));
671 
672           if (in_multi.inm_addr.s_addr == cache->al_addr) {
673              long_return = 1; /* true */
674              return (u_char *) &long_return;
675           }
676 
677           inm = in_multi.inm_next;
678        }
679        long_return = 2; /* false */
680        return (u_char *) &long_return;
681 
682    case igmpCacheLastReporter:
683        return (u_char *) &cache->al_genid;
684 
685    case igmpCacheUpTime: {
686       time_t currtime;
687       time(&currtime);
688       long_return = (currtime - cache->al_ctime)*100;
689       return (u_char *) &long_return;
690    }
691 
692    case igmpCacheExpiryTime:
693        long_return = secs_remaining(cache->al_timerid)*100;
694        return (u_char *) &long_return;
695 
696    case igmpCacheStatus:
697        long_return = 1;
698        return (u_char *) &long_return;
699 
700     default:
701        ERROR("");
702     }
703     return NULL;
704 }
705 
706 /*
707  * Implements the IGMP Interface Table portion of the IGMP MIB
708  */
709 u_char *
o_igmpInterfaceTable(vp,name,length,exact,var_len,write_method)710 o_igmpInterfaceTable(vp, name, length, exact, var_len, write_method)
711     struct variable *vp;   /* IN - pointer to variable entry that points here */
712     oid	*name;	    /* IN/OUT - input name requested, output name found */
713     int	*length;    /* IN/OUT - length of input and output oid's */
714     int			exact;	    /* IN - TRUE if an exact match was requested. */
715     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
716     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
717 {
718     oid			newname[MAX_NAME_LEN];
719     int	ifnum;
720     int result;
721 static struct sioc_vif_req v_req;
722 
723     /* Copy name OID to new OID */
724     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
725 
726     /* find "next" interface */
727     for(ifnum = 0; ifnum < numvifs; ifnum++){
728        if (!(uvifs[ifnum].uv_flags & VIFF_QUERIER))
729            continue;
730        newname[vp->namelen] = (oid)ifnum;
731        result = compare(name, *length, newname, (int)vp->namelen + 1);
732        if ((exact && (result == 0)) || (!exact && (result < 0)))
733           break;
734     }
735     if (ifnum >= numvifs)
736        return NULL;
737 
738     /* Save new OID */
739     bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid));
740     *length = vp->namelen + 1;
741     *write_method = 0;
742     *var_len = sizeof(long);
743 
744     switch (vp->magic){
745 
746 	case igmpInterfaceQueryInterval:
747 		long_return = GROUP_QUERY_INTERVAL;
748       return (u_char *) &long_return;
749 
750 	case igmpInterfaceStatus:
751 		long_return = 1; /* active */
752       return (u_char *) &long_return;
753 
754 	default:
755 	    ERROR("");
756     }
757     return NULL;
758 }
759 
760 /*
761  * Given a virtual interface number, make sure we have the current
762  * kernel information for that Vif.
763  */
764 refresh_vif(v_req, ifnum)
765    struct sioc_vif_req *v_req;
766    int ifnum;
767 {
768    static   int lastq = -1;
769 
770    if (quantum!=lastq || v_req->vifi != ifnum) {
771        lastq = quantum;
772        v_req->vifi = ifnum;
773        if (ioctl(igmp_socket, SIOCGETVIFCNT, (char *)v_req) < 0)
774           v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0;
775    }
776 }
777 
778 /*
779  * Implements the Multicast Routing Interface Table portion of the Multicast MIB
780  */
781 u_char *
o_ipMRouteInterfaceTable(vp,name,length,exact,var_len,write_method)782 o_ipMRouteInterfaceTable(vp, name, length, exact, var_len, write_method)
783     struct variable *vp;   /* IN - pointer to variable entry that points here */
784     oid	*name;	    /* IN/OUT - input name requested, output name found */
785     int	*length;    /* IN/OUT - length of input and output oid's */
786     int			exact;	    /* IN - TRUE if an exact match was requested. */
787     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
788     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
789 {
790     oid			newname[MAX_NAME_LEN];
791     int	ifnum;
792     int result;
793 static struct sioc_vif_req v_req;
794 
795     /* Copy name OID to new OID */
796     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
797 
798     /* find "next" interface */
799     for(ifnum = 0; ifnum < numvifs; ifnum++){
800 	newname[vp->namelen] = (oid)ifnum;
801 	result = compare(name, *length, newname, (int)vp->namelen + 1);
802 	if ((exact && (result == 0)) || (!exact && (result < 0)))
803 	    break;
804     }
805     if (ifnum >= numvifs)
806 	return NULL;
807 
808     /* Save new OID */
809     bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid));
810     *length = vp->namelen + 1;
811     *write_method = 0;
812     *var_len = sizeof(long);
813 
814     switch (vp->magic){
815 
816    case ipMRouteInterfaceTtl:
817        long_return = uvifs[ifnum].uv_threshold;
818        return (u_char *) &long_return;
819 
820    case dvmrpVInterfaceType:
821       if (uvifs[ifnum].uv_flags & VIFF_SRCRT)
822          long_return = 2;
823       else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL)
824          long_return = 1;
825       else if (uvifs[ifnum].uv_flags & VIFF_QUERIER)
826          long_return = 3;
827       else                               /* SUBNET */
828          long_return = 4;
829       return (u_char *) &long_return;
830 
831    case dvmrpVInterfaceState:
832       if (uvifs[ifnum].uv_flags & VIFF_DISABLED)
833          long_return = 3;
834       else if ((uvifs[ifnum].uv_flags & VIFF_DOWN)
835        || ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) && (uvifs[ifnum].uv_neighbors==NULL)))
836          long_return = 2;
837       else /* UP */
838          long_return = 1;
839       return (u_char *) &long_return;
840 
841    case dvmrpVInterfaceLocalAddress:
842       return (u_char *) &uvifs[ifnum].uv_lcl_addr;
843 
844    case dvmrpVInterfaceRemoteAddress:
845       return (u_char *) ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) ?
846          &uvifs[ifnum].uv_rmt_addr :
847          &uvifs[ifnum].uv_subnet);
848 
849    case dvmrpVInterfaceRemoteSubnetMask:
850       return (u_char *) &uvifs[ifnum].uv_subnetmask;
851 
852    case dvmrpVInterfaceMetric:
853        long_return = uvifs[ifnum].uv_metric;
854        return (u_char *) &long_return;
855 
856    case dvmrpVInterfaceRateLimit:
857        long_return = uvifs[ifnum].uv_rate_limit;
858        return (u_char *) &long_return;
859 
860    case dvmrpVInterfaceInPkts:
861        refresh_vif(&v_req, ifnum);
862        long_return = v_req.icount;
863        return (u_char *) &long_return;
864 
865    case dvmrpVInterfaceOutPkts:
866        refresh_vif(&v_req, ifnum);
867        long_return = v_req.ocount;
868        return (u_char *) &long_return;
869 
870    case dvmrpVInterfaceInOctets:
871        refresh_vif(&v_req, ifnum);
872        long_return = v_req.ibytes;
873        return (u_char *) &long_return;
874 
875    case dvmrpVInterfaceOutOctets:
876        refresh_vif(&v_req, ifnum);
877        long_return = v_req.obytes;
878        return (u_char *) &long_return;
879 
880 	default:
881 	    ERROR("");
882     }
883     return NULL;
884 }
885 
886 /*
887  * Implements the DVMRP Route Table portion of the DVMRP MIB
888  */
889 u_char *
o_dvmrpRouteTable(vp,name,length,exact,var_len,write_method)890 o_dvmrpRouteTable(vp, name, length, exact, var_len, write_method)
891     struct variable *vp;   /* IN - pointer to variable entry that points here */
892     oid	*name;	    /* IN/OUT - input name requested, output name found */
893     int	*length;    /* IN/OUT - length of input and output oid's */
894     int			exact;	    /* IN - TRUE if an exact match was requested. */
895     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
896     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
897 {
898     u_long src, mask;
899     oid        newname[MAX_NAME_LEN];
900     int        len;
901     struct rtentry *rt = NULL;
902 
903     /* Copy name OID to new OID */
904     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
905 
906     if (exact) {
907 	    if (*length != vp->namelen + 8)
908 		return NULL;
909 
910       if (!get_address(name, *length, &src, vp->namelen)
911        || !get_address(name, *length, &mask, vp->namelen+4))
912 		return NULL;
913 
914       if (!(rt = snmp_find_route(src, mask)))
915 		return NULL;
916 
917        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
918 	 } else {
919        len = *length;
920        if (compare(name, *length, vp->name, vp->namelen) < 0)
921           len = vp->namelen;
922 
923 	    if (len < vp->namelen + 8) { /* get first entry */
924 
925          if (len == vp->namelen) {
926             src = mask = 0;
927          } else {
928             get_address(name, len, &src, vp->namelen);
929             get_address(name, len, &mask, vp->namelen+4);
930          }
931 
932          if (!next_route(&rt,src,mask)) /* Get first entry */
933             return NULL;
934 
935          put_address(newname, rt->rt_origin    , vp->namelen);
936          put_address(newname, rt->rt_originmask, vp->namelen+4);
937 	    } else {  /* get next entry given previous */
938          get_address(name, *length, &src,  vp->namelen);
939          get_address(name, *length, &mask, vp->namelen+4);
940 
941          if (!next_route(&rt, src,mask))
942             return NULL;
943 
944          put_address(newname, rt->rt_origin,     vp->namelen);
945          put_address(newname, rt->rt_originmask, vp->namelen+4);
946 	    }
947     }
948 
949     /* Save new OID */
950     *length = vp->namelen + 8;
951     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
952     *write_method = 0;
953     *var_len = sizeof(long);
954 
955     switch (vp->magic) {
956 
957       case dvmrpRouteUpstreamNeighbor:
958          return (u_char *) &rt->rt_gateway;
959 
960       case dvmrpRouteInVifIndex:
961          long_return = rt->rt_parent;
962          return (u_char *) &long_return;
963 
964       case dvmrpRouteMetric:
965          long_return = rt->rt_metric;
966          return (u_char *) &long_return;
967 
968       case dvmrpRouteExpiryTime:
969          long_return = (ROUTE_EXPIRE_TIME - rt->rt_timer
970           + secs_remaining_offset()) * 100;
971          return (u_char *) &long_return;
972 
973     default:
974        ERROR("");
975     }
976     return NULL;
977 }
978 
979 /*
980  * Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB
981  */
982 u_char *
o_dvmrpRouteNextHopTable(vp,name,length,exact,var_len,write_method)983 o_dvmrpRouteNextHopTable(vp, name, length, exact, var_len, write_method)
984     struct variable *vp;   /* IN - pointer to variable entry that points here */
985     oid	*name;	    /* IN/OUT - input name requested, output name found */
986     int	*length;    /* IN/OUT - length of input and output oid's */
987     int			exact;	    /* IN - TRUE if an exact match was requested. */
988     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
989     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
990 {
991     u_long     src, mask;
992     vifi_t     vifi;
993     struct rtentry *rt = NULL;
994     oid        newname[MAX_NAME_LEN];
995     int        len;
996 
997     /* Copy name OID to new OID */
998     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
999 
1000     if (exact) {
1001 	    if (*length != vp->namelen + 9)
1002 		return NULL;
1003 
1004       if (!get_address(name, *length, &src, vp->namelen)
1005        || !get_address(name, *length, &mask, vp->namelen+4)
1006        || (!(rt=snmp_find_route(src,mask))))
1007 		return NULL;
1008 
1009       vifi = name[vp->namelen+8];
1010       if (!(VIFM_ISSET(vifi, rt->rt_children)))
1011       return NULL;
1012 
1013        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
1014 	 } else {
1015        len = *length;
1016        if (compare(name, *length, vp->name, vp->namelen) < 0)
1017           len = vp->namelen;
1018 
1019 	    if (len < vp->namelen + 9) { /* get first entry */
1020 
1021          get_address(name, len, &src,  vp->namelen);
1022          get_address(name, len, &mask, vp->namelen+4);
1023 
1024          /* Find first child vif */
1025          vifi=0;
1026          if (!next_route_child(&rt, src, mask, &vifi))
1027             return NULL;
1028 
1029          put_address(newname, rt->rt_origin,     vp->namelen);
1030          put_address(newname, rt->rt_originmask, vp->namelen+4);
1031    		newname[vp->namelen+8] = vifi;
1032 	    } else {  /* get next entry given previous */
1033 		   vifi = name[vp->namelen+8] + 1;
1034          if (!get_address(name, *length, &src,  vp->namelen)
1035           || !get_address(name, *length, &mask, vp->namelen+4)
1036           || !next_route_child(&rt, src, mask, &vifi))
1037             return NULL;
1038 
1039          put_address(newname, rt->rt_origin,     vp->namelen);
1040          put_address(newname, rt->rt_originmask, vp->namelen+4);
1041 		   newname[vp->namelen+8] = vifi;
1042 	    }
1043     }
1044 
1045     /* Save new OID */
1046     *length = vp->namelen + 9;
1047     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
1048     *write_method = 0;
1049     *var_len = sizeof(long);
1050 
1051     switch (vp->magic) {
1052 
1053     case dvmrpRouteNextHopType:
1054        long_return = (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2;
1055        return (u_char *) &long_return;
1056 
1057     default:
1058        ERROR("");
1059     }
1060     return NULL;
1061 }
1062 
1063 /*
1064  * Implements the IP Multicast Route Table portion of the Multicast MIB
1065  */
1066 u_char *
o_ipMRouteTable(vp,name,length,exact,var_len,write_method)1067 o_ipMRouteTable(vp, name, length, exact, var_len, write_method)
1068     struct variable *vp;   /* IN - pointer to variable entry that points here */
1069     oid	*name;	    /* IN/OUT - input name requested, output name found */
1070     int	*length;    /* IN/OUT - length of input and output oid's */
1071     int			exact;	    /* IN - TRUE if an exact match was requested. */
1072     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
1073     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
1074 {
1075     u_long src, grp, mask;
1076     struct gtable *gt = NULL;
1077     struct stable *st = NULL;
1078 static struct sioc_sg_req sg_req;
1079     oid        newname[MAX_NAME_LEN];
1080     int        len;
1081 
1082     /* Copy name OID to new OID */
1083     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
1084 
1085     if (exact) {
1086 	    if (*length != vp->namelen + 12)
1087 		return NULL;
1088 
1089       if (!get_address(name, *length, &grp,  vp->namelen)
1090        || !get_address(name, *length, &src,  vp->namelen+4)
1091        || !get_address(name, *length, &mask, vp->namelen+8)
1092        || (mask != 0xFFFFFFFF) /* we keep sources now, not subnets */
1093        || !(gt = find_grp(grp))
1094        || !(st = find_grp_src(gt,src)))
1095 		return NULL;
1096 
1097        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
1098 	 } else {
1099        len = *length;
1100        if (compare(name, *length, vp->name, vp->namelen) < 0)
1101           len = vp->namelen;
1102 
1103 	    if (len < vp->namelen + 12) { /* get first entry */
1104 
1105          get_address(name, len, &grp,  vp->namelen);
1106          get_address(name, len, &src,  vp->namelen+4);
1107          get_address(name, len, &mask, vp->namelen+8);
1108 
1109          if (!next_grp_src_mask(&gt,&st,grp,src,mask)) /* Get first entry */
1110             return NULL;
1111 
1112          put_address(newname, gt->gt_mcastgrp, vp->namelen);
1113          put_address(newname, st->st_origin,   vp->namelen+4);
1114          put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
1115 	    } else {  /* get next entry given previous */
1116          get_address(name, *length, &grp , vp->namelen);
1117          get_address(name, *length, &src , vp->namelen+4);
1118          get_address(name, *length, &mask, vp->namelen+8);
1119 
1120          if (!next_grp_src_mask(&gt, &st, grp,src,mask))
1121             return NULL;
1122 
1123          put_address(newname, gt->gt_mcastgrp, vp->namelen);
1124          put_address(newname, st->st_origin,   vp->namelen+4);
1125          put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
1126 	    }
1127     }
1128 
1129     /* Save new OID */
1130     *length = vp->namelen + 12;
1131     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
1132     *write_method = 0;
1133     *var_len = sizeof(long);
1134 
1135     switch (vp->magic) {
1136 
1137       case ipMRouteUpstreamNeighbor:
1138          return (u_char *) &gt->gt_route->rt_gateway;
1139 
1140       case ipMRouteInIfIndex:
1141          long_return = gt->gt_route->rt_parent;
1142          return (u_char *) &long_return;
1143 
1144       case ipMRouteUpTime: {
1145          time_t currtime;
1146          time(&currtime);
1147          long_return = (currtime - gt->gt_ctime)*100;
1148          return (u_char *) &long_return;
1149       }
1150 
1151       case ipMRouteExpiryTime:
1152          long_return = 5*((gt->gt_timer+4)/5); /* round up to nearest 5 */
1153          long_return = (long_return + secs_remaining_offset()) * 100;
1154          return (u_char *) &long_return;
1155 
1156       case ipMRoutePkts:
1157          refresh_sg(&sg_req, gt, st);
1158          long_return = sg_req.pktcnt;
1159          return (u_char *) &long_return;
1160 
1161       case ipMRouteOctets:
1162          refresh_sg(&sg_req, gt, st);
1163          long_return = sg_req.bytecnt;
1164          return (u_char *) &long_return;
1165 
1166       case ipMRouteDifferentInIfIndexes:
1167          refresh_sg(&sg_req, gt, st);
1168          long_return = sg_req.wrong_if;
1169          return (u_char *) &long_return;
1170 
1171       case ipMRouteProtocol:
1172          long_return = 4;
1173          return (u_char *) &long_return;
1174 
1175     default:
1176        ERROR("");
1177     }
1178     return NULL;
1179 }
1180 
1181 /*
1182  * Implements the IP Multicast Routing Next Hop Table portion of the Multicast
1183  * MIB
1184  */
1185 u_char *
o_ipMRouteNextHopTable(vp,name,length,exact,var_len,write_method)1186 o_ipMRouteNextHopTable(vp, name, length, exact, var_len, write_method)
1187     struct variable *vp;   /* IN - pointer to variable entry that points here */
1188     oid	*name;	    /* IN/OUT - input name requested, output name found */
1189     int	*length;    /* IN/OUT - length of input and output oid's */
1190     int			exact;	    /* IN - TRUE if an exact match was requested. */
1191     int			*var_len;   /* OUT - length of variable or 0 if function returned. */
1192     int			(**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
1193 {
1194     u_long src, grp, mask, addr;
1195     vifi_t   vifi;
1196     struct gtable *gt;
1197     struct stable *st;
1198     oid        newname[MAX_NAME_LEN];
1199     int        len;
1200 
1201     /* Copy name OID to new OID */
1202     bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
1203 
1204     if (exact) {
1205 	    if (*length != vp->namelen + 17)
1206 		return NULL;
1207 
1208       if (!get_address(name, *length, &grp, vp->namelen)
1209        || !get_address(name, *length, &src, vp->namelen+4)
1210        || !get_address(name, *length, &mask, vp->namelen+8)
1211        || !get_address(name, *length, &addr, vp->namelen+13)
1212        || grp!=addr
1213        || mask!=0xFFFFFFFF
1214        || (!(gt=find_grp(grp)))
1215        || (!(st=find_grp_src(gt,src))))
1216 		return NULL;
1217 
1218       vifi = name[vp->namelen+12];
1219       if (!(VIFM_ISSET(vifi, gt->gt_route->rt_children)))
1220       return NULL;
1221 
1222        bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
1223 	 } else {
1224        len = *length;
1225        if (compare(name, *length, vp->name, vp->namelen) < 0)
1226           len = vp->namelen;
1227 
1228 	    if (len < vp->namelen + 17) { /* get first entry */
1229 
1230          get_address(name, len, &grp, vp->namelen);
1231          get_address(name, len, &src, vp->namelen+4);
1232          get_address(name, len, &mask, vp->namelen+8);
1233 
1234          /* Find first child vif */
1235          vifi=0;
1236          if (!next_child(&gt, &st, grp, src, mask, &vifi))
1237             return NULL;
1238 
1239          put_address(newname, gt->gt_mcastgrp, vp->namelen);
1240          put_address(newname, st->st_origin,   vp->namelen+4);
1241          put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
1242    		newname[vp->namelen+12] = vifi;
1243          put_address(newname, gt->gt_mcastgrp, vp->namelen+13);
1244 
1245 	    } else {  /* get next entry given previous */
1246 		   vifi = name[vp->namelen+12]+1;
1247          if (!get_address(name, *length, &grp,  vp->namelen)
1248           || !get_address(name, *length, &src,  vp->namelen+4)
1249           || !get_address(name, *length, &mask, vp->namelen+8)
1250           || !next_child(&gt, &st, grp, src, mask, &vifi))
1251             return NULL;
1252 
1253          put_address(newname, gt->gt_mcastgrp, vp->namelen);
1254          put_address(newname, st->st_origin,   vp->namelen+4);
1255          put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
1256 		   newname[vp->namelen+12] = vifi;
1257          put_address(newname, gt->gt_mcastgrp, vp->namelen+13);
1258 	    }
1259     }
1260 
1261     /* Save new OID */
1262     *length = vp->namelen + 17;
1263     bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
1264     *write_method = 0;
1265     *var_len = sizeof(long);
1266 
1267     switch (vp->magic) {
1268 
1269       case ipMRouteNextHopState:
1270          long_return = (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1;
1271          return (u_char *) &long_return;
1272 
1273       /* Currently equal to ipMRouteUpTime */
1274       case ipMRouteNextHopUpTime: {
1275          time_t currtime;
1276          time(&currtime);
1277          long_return = (currtime - gt->gt_ctime)*100;
1278          return (u_char *) &long_return;
1279       }
1280 
1281       case ipMRouteNextHopExpiryTime:
1282          long_return = 5*((gt->gt_prsent_timer+4)/5); /* round up to nearest 5*/
1283          long_return = (long_return + secs_remaining_offset()) * 100;
1284          return (u_char *) &long_return;
1285 
1286       case ipMRouteNextHopClosestMemberHops:
1287          long_return = 0;
1288          return (u_char *) &long_return;
1289 
1290       case ipMRouteNextHopProtocol:
1291          long_return = 4;
1292          return (u_char *) &long_return;
1293 
1294     default:
1295        ERROR("");
1296     }
1297     return NULL;
1298 }
1299 
1300 /* sync_timer is called by timer() every TIMER_INTERVAL seconds.
1301  * Its job is to record this time so that we can compute on demand
1302  * the approx # seconds remaining until the next timer() call
1303  */
1304 static time_t lasttimer;
1305 
1306 void
sync_timer()1307 sync_timer()
1308 {
1309     time(&lasttimer);
1310 }
1311 
1312 int /* in range [-TIMER_INTERVAL..0] */
secs_remaining_offset()1313 secs_remaining_offset()
1314 {
1315    time_t tm;
1316 
1317    time(&tm);
1318    return lasttimer-tm;
1319 }
1320