/* $NetBSD: snmp.c,v 1.3 1995/12/10 10:07:16 mycroft Exp $ */ /* * Copyright (c) 1992, 2001 Xerox Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither name of the Xerox, PARC, nor the names of its contributors may be used * to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE XEROX CORPORATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "defs.h" #include #include "snmp.h" #include "snmplib/asn1.h" #include "snmplib/party.h" #include "snmplib/snmp_impl.h" #define MROUTED #include "snmpd/snmp_vars.h" in_port_t dest_port = 0; int sdlen = 0; struct addrCache { u_long addr; int status; #define UNUSED 0 #define USED 1 #define OLD 2 }; static struct addrCache addrCache[10]; /* * Initialize the SNMP part of mrouted */ int /* returns: 0 on success, true on error */ snmp_init(dest_port) in_port_t dest_port; { u_long myaddr; int ret; struct partyEntry *pp; struct sockaddr_in me; int index, sd, portlist[32]; init_snmp(); /* init_mib(); why was this here? */ if (read_party_database("/etc/party.conf") > 0){ fprintf(stderr, "Couldn't read party database from /etc/party.conf\n"); exit(0); } if (read_context_database("/etc/context.conf") > 0){ fprintf(stderr, "Couldn't read context database from /etc/context.conf\n"); exit(0); } if (read_acl_database("/etc/acl.conf") > 0){ fprintf(stderr, "Couldn't read acl database from /etc/acl.conf\n"); exit(0); } if (read_view_database("/etc/view.conf") > 0){ fprintf(stderr, "Couldn't read view database from /etc/view.conf\n"); exit(0); } myaddr = get_myaddr(); if (ret = agent_party_init(myaddr, ".1.3.6.1")){ if (ret == 1){ fprintf(stderr, "Conflict found with initial noAuth/noPriv parties... continuing\n"); } else if (ret == -1){ fprintf(stderr, "Error installing initial noAuth/noPriv parties, exiting\n"); exit(1); } else { fprintf(stderr, "Unknown error, exiting\n"); exit(2); } } printf("Opening port(s): "); fflush(stdout); party_scanInit(); for(pp = party_scanNext(); pp; pp = party_scanNext()){ if ((pp->partyTDomain != DOMAINSNMPUDP) || bcmp((char *)&myaddr, pp->partyTAddress, 4)) continue; /* don't listen for non-local parties */ dest_port = 0; bcopy(pp->partyTAddress + 4, &dest_port, 2); for(index = 0; index < sdlen; index++) if (dest_port == portlist[index]) break; if (index < sdlen) /* found a hit before the end of the list */ continue; printf("%u ", dest_port); fflush(stdout); /* Set up connections */ sd = socket(AF_INET, SOCK_DGRAM, 0); if (sd < 0){ perror("socket"); return 1; } memset(&me, 0, sizeof me); me.sin_family = AF_INET; me.sin_addr.s_addr = INADDR_ANY; /* already in network byte order (I think) */ me.sin_port = dest_port; if (bind(sd, (struct sockaddr *)&me, sizeof(me)) != 0){ perror("bind"); return 2; } register_input_handler(sd, snmp_read_packet); portlist[sdlen] = dest_port; if (++sdlen == 32){ printf("No more sockets... ignoring rest of file\n"); break; } } printf("\n"); bzero((char *)addrCache, sizeof(addrCache)); } /* * Place an IP address into an OID starting at element n */ void put_address(name, addr, n) oid *name; u_long addr; int n; { int i; for (i=n+3; i>=n+0; i--) { name[i] = addr & 0xFF; addr >>= 8; } } /* Get an IP address from an OID starting at element n */ int get_address(name, length, addr, n) oid *name; int length; u_long *addr; int n; { int i; int ok = 1; (*addr) = 0; if (length < n+4) return 0; for (i=n; i= length) ok = 0; else (*addr) |= name[i]; } return ok; } /* * Implements scalar objects from DVMRP and Multicast MIBs */ u_char * o_scalar(vp, name, length, exact, var_len, write_method) register struct variable *vp; /* IN - pointer to variable entry that points here */ register oid *name; /* IN/OUT - input name requested, output name found */ register int *length; /* IN/OUT - length of input and output oid's */ int exact; /* IN - TRUE if an exact match was requested. */ int *var_len; /* OUT - length of variable or 0 if function returned. */ int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ { int result; *write_method = 0; result = compare(name, *length, vp->name, (int)vp->namelen); if ((exact && (result != 0)) || (!exact && (result >= 0))) return NULL; bcopy((char *)vp->name, (char *)name, (int)vp->namelen * sizeof(oid)); *length = vp->namelen; *var_len = sizeof(long); switch (vp->magic) { case ipMRouteEnable: long_return = 1; return (u_char *) &long_return; case dvmrpVersion: { static char buff[15]; snprintf(buff, sizeof buff, "mrouted%d.%d", PROTOCOL_VERSION, MROUTED_VERSION); *var_len = strlen(buff); return (u_char *)buff; } case dvmrpGenerationId: long_return = dvmrp_genid; return (u_char *) &long_return; default: ERROR(""); } return NULL; } /* * Find if a specific scoped boundary exists on a Vif */ struct vif_acl * find_boundary(vifi, addr, mask) vifi_t vifi; u_long addr; u_long mask; { struct vif_acl *n; for (n = uvifs[vifi].uv_acl; n != NULL; n = n->acl_next) { if (addr == n->acl_addr && mask==n->acl_mask) return n; } return NULL; } /* * Find the lowest boundary >= (V,A,M) spec */ struct vif_acl * next_boundary(vifi, addr, mask) vifi_t *vifi; u_long addr; u_long mask; { struct vif_acl *bestn, *n; int i; for (i = *vifi; i < numvifs; i++) { bestn = NULL; for (n = uvifs[i].uv_acl; n; n=n->acl_next) { if ((i > *vifi || n->acl_addr > addr || (n->acl_addr == addr && n->acl_mask >= mask)) && (!bestn || n->acl_addr < bestn->acl_addr || (n->acl_addr==bestn->acl_addr && n->acl_maskacl_mask))) bestn = n; } if (bestn) { *vifi = i; return bestn; } } return NULL; } /* * Implements the Boundary Table portion of the DVMRP MIB */ u_char * o_dvmrpBoundaryTable(vp, name, length, exact, var_len, write_method) register struct variable *vp; /* IN - pointer to variable entry that points here */ register oid *name; /* IN/OUT - input name requested, output name found */ register int *length; /* IN/OUT - length of input and output oid's */ int exact; /* IN - TRUE if an exact match was requested. */ int *var_len; /* OUT - length of variable or 0 if function returned. */ int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ { vifi_t vifi; u_long addr, mask; struct vif_acl *bound; oid newname[MAX_NAME_LEN]; int len; /* Copy name OID to new OID */ bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); if (exact) { if (*length != vp->namelen + 9) return NULL; if ((vifi = name[vp->namelen]) >= numvifs) return NULL; if (!get_address(name, *length, &addr, vp->namelen+1) || !get_address(name, *length, &mask, vp->namelen+5)) return NULL; if (!(bound = find_boundary(vifi, addr, mask))) return NULL; bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); } else { len = *length; if (compare(name, *length, vp->name, vp->namelen) < 0) len = vp->namelen; if (len < vp->namelen + 9) { /* get first entry */ if (len == vp->namelen) { vifi = addr = mask = 0; } else { vifi = name[vp->namelen]; get_address(name, len, &addr, vp->namelen+1); get_address(name, len, &mask, vp->namelen+5); } bound = next_boundary(&vifi,addr,mask); if (!bound) return NULL; newname[vp->namelen] = vifi; put_address(newname, bound->acl_addr, vp->namelen+1); put_address(newname, bound->acl_mask, vp->namelen+5); } else { /* get next entry given previous */ vifi = name[vp->namelen]; get_address(name, *length, &addr, vp->namelen+1); get_address(name, *length, &mask, vp->namelen+5); if (!(bound = next_boundary(&vifi,addr,mask+1))) return NULL; newname[vp->namelen] = vifi; put_address(newname, bound->acl_addr, vp->namelen+1); put_address(newname, bound->acl_mask, vp->namelen+5); } } /* Save new OID */ *length = vp->namelen + 9; bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); *write_method = 0; *var_len = sizeof(long); switch (vp->magic) { case dvmrpBoundaryVifIndex: long_return = vifi; return (u_char *) &long_return; default: ERROR(""); } return NULL; } /* * Find the lowest neighbor >= (V,A) spec */ struct listaddr * next_neighbor(vifi, addr) vifi_t *vifi; u_long addr; { struct listaddr *bestn, *n; int i; for (i = *vifi; i < numvifs; i++) { bestn = NULL; for (n = uvifs[i].uv_neighbors; n; n=n->al_next) { if ((i > *vifi || n->al_addr >= addr) && (!bestn || n->al_addr < bestn->al_addr)) bestn = n; } if (bestn) { *vifi = i; return bestn; } } return NULL; } /* * Find a neighbor, if it exists off a given Vif */ struct listaddr * find_neighbor(vifi, addr) vifi_t vifi; u_long addr; { struct listaddr *n; for (n = uvifs[vifi].uv_neighbors; n != NULL; n = n->al_next) { if (addr == n->al_addr) return n; } return NULL; } u_char * o_dvmrpNeighborTable(vp, name, length, exact, var_len, write_method) register struct variable *vp; /* IN - pointer to variable entry that points here */ register oid *name; /* IN/OUT - input name requested, output name found */ register int *length; /* IN/OUT - length of input and output oid's */ int exact; /* IN - TRUE if an exact match was requested. */ int *var_len; /* OUT - length of variable or 0 if function returned. */ int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ { vifi_t vifi; u_long addr, mask; struct listaddr *neighbor; oid newname[MAX_NAME_LEN]; int len; /* Copy name OID to new OID */ bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); if (exact) { if (*length != vp->namelen + 5) return NULL; if ((vifi = name[vp->namelen]) >= numvifs) return NULL; if (!get_address(name, *length, &addr, vp->namelen+1)) return NULL; if (!(neighbor = find_neighbor(vifi, addr))) return NULL; bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); } else { len = *length; if (compare(name, *length, vp->name, vp->namelen) < 0) len = vp->namelen; if (len < vp->namelen + 5) { /* get first entry */ if (len == vp->namelen) { vifi = addr = 0; } else { vifi = name[vp->namelen]; get_address(name, len, &addr, vp->namelen+1); } neighbor = next_neighbor(&vifi,addr); if (!neighbor) return NULL; newname[vp->namelen] = vifi; put_address(newname, neighbor->al_addr, vp->namelen+1); } else { /* get next entry given previous */ vifi = name[vp->namelen]; get_address(name, *length, &addr, vp->namelen+1); if (!(neighbor = next_neighbor(&vifi,addr+1))) return NULL; newname[vp->namelen] = vifi; put_address(newname, neighbor->al_addr, vp->namelen+1); } } /* Save new OID */ *length = vp->namelen + 5; bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); *write_method = 0; *var_len = sizeof(long); switch (vp->magic) { case dvmrpNeighborUpTime: { time_t currtime; time(&currtime); long_return = (currtime - neighbor->al_ctime)*100; return (u_char *) &long_return; } case dvmrpNeighborExpiryTime: long_return = (NEIGHBOR_EXPIRE_TIME - neighbor->al_timer + secs_remaining_offset()) * 100; return (u_char *) &long_return; case dvmrpNeighborVersion: { static char buff[15]; snprintf(buff, sizeof buff, "%d.%d", neighbor->al_pv, neighbor->al_mv); *var_len = strlen(buff); return (u_char *)buff; } case dvmrpNeighborGenerationId: long_return = neighbor->al_genid; return (u_char *) &long_return; default: ERROR(""); } return NULL; } /* Look up ifIndex given uvifs[ifnum].uv_lcl_addr */ struct in_ifaddr * /* returns: in_ifaddr structure, or null on error */ ipaddr_to_ifindex(ipaddr, ifIndex) u_long ipaddr; int *ifIndex; { int interface; static struct in_ifaddr in_ifaddr; Interface_Scan_Init(); for (;;) { if (Interface_Scan_Next(&interface, (char *)0, NULL, &in_ifaddr) == 0) return NULL; if (((struct sockaddr_in *) &(in_ifaddr.ia_addr))->sin_addr.s_addr == ipaddr) { *ifIndex = interface; return &in_ifaddr; } } } /* * Find if a specific scoped boundary exists on a Vif */ struct listaddr * find_cache(grp, vifi) u_long grp; vifi_t vifi; { struct listaddr *n; for (n = uvifs[vifi].uv_groups; n != NULL; n = n->al_next) { if (grp == n->al_addr) return n; } return NULL; } /* * Find the next group cache entry >= (A,V) spec */ struct listaddr * next_cache(addr, vifi) u_long addr; vifi_t *vifi; { struct listaddr *bestn=NULL, *n; int i, besti; /* Step through all entries looking for the next one */ for (i = 0; i < numvifs; i++) { for (n = uvifs[i].uv_groups; n; n=n->al_next) { if ((n->al_addr > addr || (n->al_addr == addr && i >= *vifi)) && (!bestn || n->al_addr < bestn->al_addr || (n->al_addr == bestn->al_addr && i < besti))) { bestn = n; besti = i; } } } if (bestn) { *vifi = besti; return bestn; } return NULL; } /* * Implements the IGMP Cache Table portion of the IGMP MIB */ u_char * o_igmpCacheTable(vp, name, length, exact, var_len, write_method) register struct variable *vp; /* IN - pointer to variable entry that points here */ register oid *name; /* IN/OUT - input name requested, output name found */ register int *length; /* IN/OUT - length of input and output oid's */ int exact; /* IN - TRUE if an exact match was requested. */ int *var_len; /* OUT - length of variable or 0 if function returned. */ int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ { vifi_t vifi; u_long grp; int ifIndex; struct listaddr *cache; oid newname[MAX_NAME_LEN]; int len; struct in_ifaddr *in_ifaddr; struct in_multi in_multi, *inm; /* Copy name OID to new OID */ bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); if (exact) { if (*length != vp->namelen + 5) return NULL; if ((vifi = name[vp->namelen+4]) >= numvifs) return NULL; if (!get_address(name, *length, &grp, vp->namelen)) return NULL; if (!(cache = find_cache(grp, vifi))) return NULL; bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); } else { len = *length; if (compare(name, *length, vp->name, vp->namelen) < 0) len = vp->namelen; if (len < vp->namelen + 5) { /* get first entry */ if (len == vp->namelen) { vifi = grp = 0; } else { get_address(name, len, &grp, vp->namelen); vifi = name[vp->namelen+4]; } cache = next_cache(grp,&vifi); if (!cache) return NULL; put_address(newname, cache->al_addr, vp->namelen); newname[vp->namelen+4] = vifi; } else { /* get next entry given previous */ get_address(name, *length, &grp, vp->namelen); vifi = name[vp->namelen+4]+1; if (!(cache = next_cache(grp,&vifi))) return NULL; put_address(newname, cache->al_addr, vp->namelen); newname[vp->namelen+4] = vifi; } } /* Save new OID */ *length = vp->namelen + 5; bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); *write_method = 0; *var_len = sizeof(long); /* Look up ifIndex given uvifs[vifi].uv_lcl_addr */ in_ifaddr = ipaddr_to_ifindex(uvifs[vifi].uv_lcl_addr, &ifIndex); switch (vp->magic) { case igmpCacheSelf: inm = in_ifaddr->ia_multiaddrs; while (inm) { klookup( (int)inm, (char *)&in_multi, sizeof(in_multi)); if (in_multi.inm_addr.s_addr == cache->al_addr) { long_return = 1; /* true */ return (u_char *) &long_return; } inm = in_multi.inm_next; } long_return = 2; /* false */ return (u_char *) &long_return; case igmpCacheLastReporter: return (u_char *) &cache->al_genid; case igmpCacheUpTime: { time_t currtime; time(&currtime); long_return = (currtime - cache->al_ctime)*100; return (u_char *) &long_return; } case igmpCacheExpiryTime: long_return = secs_remaining(cache->al_timerid)*100; return (u_char *) &long_return; case igmpCacheStatus: long_return = 1; return (u_char *) &long_return; default: ERROR(""); } return NULL; } /* * Implements the IGMP Interface Table portion of the IGMP MIB */ u_char * o_igmpInterfaceTable(vp, name, length, exact, var_len, write_method) register struct variable *vp; /* IN - pointer to variable entry that points here */ register oid *name; /* IN/OUT - input name requested, output name found */ register int *length; /* IN/OUT - length of input and output oid's */ int exact; /* IN - TRUE if an exact match was requested. */ int *var_len; /* OUT - length of variable or 0 if function returned. */ int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ { oid newname[MAX_NAME_LEN]; register int ifnum; int result; static struct sioc_vif_req v_req; /* Copy name OID to new OID */ bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); /* find "next" interface */ for(ifnum = 0; ifnum < numvifs; ifnum++){ if (!(uvifs[ifnum].uv_flags & VIFF_QUERIER)) continue; newname[vp->namelen] = (oid)ifnum; result = compare(name, *length, newname, (int)vp->namelen + 1); if ((exact && (result == 0)) || (!exact && (result < 0))) break; } if (ifnum >= numvifs) return NULL; /* Save new OID */ bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid)); *length = vp->namelen + 1; *write_method = 0; *var_len = sizeof(long); switch (vp->magic){ case igmpInterfaceQueryInterval: long_return = GROUP_QUERY_INTERVAL; return (u_char *) &long_return; case igmpInterfaceStatus: long_return = 1; /* active */ return (u_char *) &long_return; default: ERROR(""); } return NULL; } /* * Given a virtual interface number, make sure we have the current * kernel information for that Vif. */ refresh_vif(v_req, ifnum) struct sioc_vif_req *v_req; int ifnum; { static int lastq = -1; if (quantum!=lastq || v_req->vifi != ifnum) { lastq = quantum; v_req->vifi = ifnum; if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)v_req) < 0) v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0; } } /* * Implements the Multicast Routing Interface Table portion of the Multicast MIB */ u_char * o_ipMRouteInterfaceTable(vp, name, length, exact, var_len, write_method) register struct variable *vp; /* IN - pointer to variable entry that points here */ register oid *name; /* IN/OUT - input name requested, output name found */ register int *length; /* IN/OUT - length of input and output oid's */ int exact; /* IN - TRUE if an exact match was requested. */ int *var_len; /* OUT - length of variable or 0 if function returned. */ int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ { oid newname[MAX_NAME_LEN]; register int ifnum; int result; static struct sioc_vif_req v_req; /* Copy name OID to new OID */ bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); /* find "next" interface */ for(ifnum = 0; ifnum < numvifs; ifnum++){ newname[vp->namelen] = (oid)ifnum; result = compare(name, *length, newname, (int)vp->namelen + 1); if ((exact && (result == 0)) || (!exact && (result < 0))) break; } if (ifnum >= numvifs) return NULL; /* Save new OID */ bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid)); *length = vp->namelen + 1; *write_method = 0; *var_len = sizeof(long); switch (vp->magic){ case ipMRouteInterfaceTtl: long_return = uvifs[ifnum].uv_threshold; return (u_char *) &long_return; case dvmrpVInterfaceType: if (uvifs[ifnum].uv_flags & VIFF_SRCRT) long_return = 2; else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL) long_return = 1; else if (uvifs[ifnum].uv_flags & VIFF_QUERIER) long_return = 3; else /* SUBNET */ long_return = 4; return (u_char *) &long_return; case dvmrpVInterfaceState: if (uvifs[ifnum].uv_flags & VIFF_DISABLED) long_return = 3; else if ((uvifs[ifnum].uv_flags & VIFF_DOWN) || ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) && (uvifs[ifnum].uv_neighbors==NULL))) long_return = 2; else /* UP */ long_return = 1; return (u_char *) &long_return; case dvmrpVInterfaceLocalAddress: return (u_char *) &uvifs[ifnum].uv_lcl_addr; case dvmrpVInterfaceRemoteAddress: return (u_char *) ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) ? &uvifs[ifnum].uv_rmt_addr : &uvifs[ifnum].uv_subnet); case dvmrpVInterfaceRemoteSubnetMask: return (u_char *) &uvifs[ifnum].uv_subnetmask; case dvmrpVInterfaceMetric: long_return = uvifs[ifnum].uv_metric; return (u_char *) &long_return; case dvmrpVInterfaceRateLimit: long_return = uvifs[ifnum].uv_rate_limit; return (u_char *) &long_return; case dvmrpVInterfaceInPkts: refresh_vif(&v_req, ifnum); long_return = v_req.icount; return (u_char *) &long_return; case dvmrpVInterfaceOutPkts: refresh_vif(&v_req, ifnum); long_return = v_req.ocount; return (u_char *) &long_return; case dvmrpVInterfaceInOctets: refresh_vif(&v_req, ifnum); long_return = v_req.ibytes; return (u_char *) &long_return; case dvmrpVInterfaceOutOctets: refresh_vif(&v_req, ifnum); long_return = v_req.obytes; return (u_char *) &long_return; default: ERROR(""); } return NULL; } /* * Implements the DVMRP Route Table portion of the DVMRP MIB */ u_char * o_dvmrpRouteTable(vp, name, length, exact, var_len, write_method) register struct variable *vp; /* IN - pointer to variable entry that points here */ register oid *name; /* IN/OUT - input name requested, output name found */ register int *length; /* IN/OUT - length of input and output oid's */ int exact; /* IN - TRUE if an exact match was requested. */ int *var_len; /* OUT - length of variable or 0 if function returned. */ int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ { u_long src, mask; oid newname[MAX_NAME_LEN]; int len; struct rtentry *rt = NULL; /* Copy name OID to new OID */ bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); if (exact) { if (*length != vp->namelen + 8) return NULL; if (!get_address(name, *length, &src, vp->namelen) || !get_address(name, *length, &mask, vp->namelen+4)) return NULL; if (!(rt = snmp_find_route(src, mask))) return NULL; bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); } else { len = *length; if (compare(name, *length, vp->name, vp->namelen) < 0) len = vp->namelen; if (len < vp->namelen + 8) { /* get first entry */ if (len == vp->namelen) { src = mask = 0; } else { get_address(name, len, &src, vp->namelen); get_address(name, len, &mask, vp->namelen+4); } if (!next_route(&rt,src,mask)) /* Get first entry */ return NULL; put_address(newname, rt->rt_origin , vp->namelen); put_address(newname, rt->rt_originmask, vp->namelen+4); } else { /* get next entry given previous */ get_address(name, *length, &src, vp->namelen); get_address(name, *length, &mask, vp->namelen+4); if (!next_route(&rt, src,mask)) return NULL; put_address(newname, rt->rt_origin, vp->namelen); put_address(newname, rt->rt_originmask, vp->namelen+4); } } /* Save new OID */ *length = vp->namelen + 8; bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); *write_method = 0; *var_len = sizeof(long); switch (vp->magic) { case dvmrpRouteUpstreamNeighbor: return (u_char *) &rt->rt_gateway; case dvmrpRouteInVifIndex: long_return = rt->rt_parent; return (u_char *) &long_return; case dvmrpRouteMetric: long_return = rt->rt_metric; return (u_char *) &long_return; case dvmrpRouteExpiryTime: long_return = (ROUTE_EXPIRE_TIME - rt->rt_timer + secs_remaining_offset()) * 100; return (u_char *) &long_return; default: ERROR(""); } return NULL; } /* * Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB */ u_char * o_dvmrpRouteNextHopTable(vp, name, length, exact, var_len, write_method) register struct variable *vp; /* IN - pointer to variable entry that points here */ register oid *name; /* IN/OUT - input name requested, output name found */ register int *length; /* IN/OUT - length of input and output oid's */ int exact; /* IN - TRUE if an exact match was requested. */ int *var_len; /* OUT - length of variable or 0 if function returned. */ int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ { u_long src, mask; vifi_t vifi; struct rtentry *rt = NULL; oid newname[MAX_NAME_LEN]; int len; /* Copy name OID to new OID */ bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); if (exact) { if (*length != vp->namelen + 9) return NULL; if (!get_address(name, *length, &src, vp->namelen) || !get_address(name, *length, &mask, vp->namelen+4) || (!(rt=snmp_find_route(src,mask)))) return NULL; vifi = name[vp->namelen+8]; if (!(VIFM_ISSET(vifi, rt->rt_children))) return NULL; bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); } else { len = *length; if (compare(name, *length, vp->name, vp->namelen) < 0) len = vp->namelen; if (len < vp->namelen + 9) { /* get first entry */ get_address(name, len, &src, vp->namelen); get_address(name, len, &mask, vp->namelen+4); /* Find first child vif */ vifi=0; if (!next_route_child(&rt, src, mask, &vifi)) return NULL; put_address(newname, rt->rt_origin, vp->namelen); put_address(newname, rt->rt_originmask, vp->namelen+4); newname[vp->namelen+8] = vifi; } else { /* get next entry given previous */ vifi = name[vp->namelen+8] + 1; if (!get_address(name, *length, &src, vp->namelen) || !get_address(name, *length, &mask, vp->namelen+4) || !next_route_child(&rt, src, mask, &vifi)) return NULL; put_address(newname, rt->rt_origin, vp->namelen); put_address(newname, rt->rt_originmask, vp->namelen+4); newname[vp->namelen+8] = vifi; } } /* Save new OID */ *length = vp->namelen + 9; bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); *write_method = 0; *var_len = sizeof(long); switch (vp->magic) { case dvmrpRouteNextHopType: long_return = (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2; return (u_char *) &long_return; default: ERROR(""); } return NULL; } /* * Implements the IP Multicast Route Table portion of the Multicast MIB */ u_char * o_ipMRouteTable(vp, name, length, exact, var_len, write_method) register struct variable *vp; /* IN - pointer to variable entry that points here */ register oid *name; /* IN/OUT - input name requested, output name found */ register int *length; /* IN/OUT - length of input and output oid's */ int exact; /* IN - TRUE if an exact match was requested. */ int *var_len; /* OUT - length of variable or 0 if function returned. */ int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ { u_long src, grp, mask; struct gtable *gt = NULL; struct stable *st = NULL; static struct sioc_sg_req sg_req; oid newname[MAX_NAME_LEN]; int len; /* Copy name OID to new OID */ bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); if (exact) { if (*length != vp->namelen + 12) return NULL; if (!get_address(name, *length, &grp, vp->namelen) || !get_address(name, *length, &src, vp->namelen+4) || !get_address(name, *length, &mask, vp->namelen+8) || (mask != 0xFFFFFFFF) /* we keep sources now, not subnets */ || !(gt = find_grp(grp)) || !(st = find_grp_src(gt,src))) return NULL; bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); } else { len = *length; if (compare(name, *length, vp->name, vp->namelen) < 0) len = vp->namelen; if (len < vp->namelen + 12) { /* get first entry */ get_address(name, len, &grp, vp->namelen); get_address(name, len, &src, vp->namelen+4); get_address(name, len, &mask, vp->namelen+8); if (!next_grp_src_mask(>,&st,grp,src,mask)) /* Get first entry */ return NULL; put_address(newname, gt->gt_mcastgrp, vp->namelen); put_address(newname, st->st_origin, vp->namelen+4); put_address(newname, 0xFFFFFFFF, vp->namelen+8); } else { /* get next entry given previous */ get_address(name, *length, &grp , vp->namelen); get_address(name, *length, &src , vp->namelen+4); get_address(name, *length, &mask, vp->namelen+8); if (!next_grp_src_mask(>, &st, grp,src,mask)) return NULL; put_address(newname, gt->gt_mcastgrp, vp->namelen); put_address(newname, st->st_origin, vp->namelen+4); put_address(newname, 0xFFFFFFFF, vp->namelen+8); } } /* Save new OID */ *length = vp->namelen + 12; bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); *write_method = 0; *var_len = sizeof(long); switch (vp->magic) { case ipMRouteUpstreamNeighbor: return (u_char *) >->gt_route->rt_gateway; case ipMRouteInIfIndex: long_return = gt->gt_route->rt_parent; return (u_char *) &long_return; case ipMRouteUpTime: { time_t currtime; time(&currtime); long_return = (currtime - gt->gt_ctime)*100; return (u_char *) &long_return; } case ipMRouteExpiryTime: long_return = 5*((gt->gt_timer+4)/5); /* round up to nearest 5 */ long_return = (long_return + secs_remaining_offset()) * 100; return (u_char *) &long_return; case ipMRoutePkts: refresh_sg(&sg_req, gt, st); long_return = sg_req.pktcnt; return (u_char *) &long_return; case ipMRouteOctets: refresh_sg(&sg_req, gt, st); long_return = sg_req.bytecnt; return (u_char *) &long_return; case ipMRouteDifferentInIfIndexes: refresh_sg(&sg_req, gt, st); long_return = sg_req.wrong_if; return (u_char *) &long_return; case ipMRouteProtocol: long_return = 4; return (u_char *) &long_return; default: ERROR(""); } return NULL; } /* * Implements the IP Multicast Routing Next Hop Table portion of the Multicast * MIB */ u_char * o_ipMRouteNextHopTable(vp, name, length, exact, var_len, write_method) register struct variable *vp; /* IN - pointer to variable entry that points here */ register oid *name; /* IN/OUT - input name requested, output name found */ register int *length; /* IN/OUT - length of input and output oid's */ int exact; /* IN - TRUE if an exact match was requested. */ int *var_len; /* OUT - length of variable or 0 if function returned. */ int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ { u_long src, grp, mask, addr; vifi_t vifi; struct gtable *gt; struct stable *st; oid newname[MAX_NAME_LEN]; int len; /* Copy name OID to new OID */ bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); if (exact) { if (*length != vp->namelen + 17) return NULL; if (!get_address(name, *length, &grp, vp->namelen) || !get_address(name, *length, &src, vp->namelen+4) || !get_address(name, *length, &mask, vp->namelen+8) || !get_address(name, *length, &addr, vp->namelen+13) || grp!=addr || mask!=0xFFFFFFFF || (!(gt=find_grp(grp))) || (!(st=find_grp_src(gt,src)))) return NULL; vifi = name[vp->namelen+12]; if (!(VIFM_ISSET(vifi, gt->gt_route->rt_children))) return NULL; bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); } else { len = *length; if (compare(name, *length, vp->name, vp->namelen) < 0) len = vp->namelen; if (len < vp->namelen + 17) { /* get first entry */ get_address(name, len, &grp, vp->namelen); get_address(name, len, &src, vp->namelen+4); get_address(name, len, &mask, vp->namelen+8); /* Find first child vif */ vifi=0; if (!next_child(>, &st, grp, src, mask, &vifi)) return NULL; put_address(newname, gt->gt_mcastgrp, vp->namelen); put_address(newname, st->st_origin, vp->namelen+4); put_address(newname, 0xFFFFFFFF, vp->namelen+8); newname[vp->namelen+12] = vifi; put_address(newname, gt->gt_mcastgrp, vp->namelen+13); } else { /* get next entry given previous */ vifi = name[vp->namelen+12]+1; if (!get_address(name, *length, &grp, vp->namelen) || !get_address(name, *length, &src, vp->namelen+4) || !get_address(name, *length, &mask, vp->namelen+8) || !next_child(>, &st, grp, src, mask, &vifi)) return NULL; put_address(newname, gt->gt_mcastgrp, vp->namelen); put_address(newname, st->st_origin, vp->namelen+4); put_address(newname, 0xFFFFFFFF, vp->namelen+8); newname[vp->namelen+12] = vifi; put_address(newname, gt->gt_mcastgrp, vp->namelen+13); } } /* Save new OID */ *length = vp->namelen + 17; bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); *write_method = 0; *var_len = sizeof(long); switch (vp->magic) { case ipMRouteNextHopState: long_return = (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1; return (u_char *) &long_return; /* Currently equal to ipMRouteUpTime */ case ipMRouteNextHopUpTime: { time_t currtime; time(&currtime); long_return = (currtime - gt->gt_ctime)*100; return (u_char *) &long_return; } case ipMRouteNextHopExpiryTime: long_return = 5*((gt->gt_prsent_timer+4)/5); /* round up to nearest 5*/ long_return = (long_return + secs_remaining_offset()) * 100; return (u_char *) &long_return; case ipMRouteNextHopClosestMemberHops: long_return = 0; return (u_char *) &long_return; case ipMRouteNextHopProtocol: long_return = 4; return (u_char *) &long_return; default: ERROR(""); } return NULL; } /* sync_timer is called by timer() every TIMER_INTERVAL seconds. * Its job is to record this time so that we can compute on demand * the approx # seconds remaining until the next timer() call */ static time_t lasttimer; void sync_timer() { time(&lasttimer); } int /* in range [-TIMER_INTERVAL..0] */ secs_remaining_offset() { time_t tm; time(&tm); return lasttimer-tm; }