1 /* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> 7 * 8 * Redistribution of this software and documentation and use in source and 9 * binary forms, with or without modification, are permitted provided that 10 * the following conditions are met: 11 * 12 * 1. Redistributions of source code or documentation must retain the above 13 * copyright notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 22 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 24 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25 * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 28 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $Begemot: bsnmp/snmp_mibII/mibII_route.c,v 1.4 2003/12/03 10:01:19 hbb Exp $ 34 * 35 * Routing table 36 */ 37 #include "mibII.h" 38 #include "mibII_oid.h" 39 40 struct sroute { 41 TAILQ_ENTRY(sroute) link; 42 struct asn_oid index; 43 u_int ifindex; 44 u_int type; 45 u_int proto; 46 }; 47 static TAILQ_HEAD(, sroute) sroute_list = TAILQ_HEAD_INITIALIZER(sroute_list); 48 49 static u_int32_t route_tick; 50 static u_int route_total; 51 52 static int 53 fetch_route(void) 54 { 55 u_char *rtab, *next; 56 size_t len; 57 struct sroute *r; 58 struct rt_msghdr *rtm; 59 struct sockaddr *addrs[RTAX_MAX]; 60 struct sockaddr_in *sa, *gw; 61 struct in_addr mask, nhop; 62 in_addr_t ha; 63 struct mibif *ifp; 64 65 while ((r = TAILQ_FIRST(&sroute_list)) != NULL) { 66 TAILQ_REMOVE(&sroute_list, r, link); 67 free(r); 68 } 69 route_total = 0; 70 71 if ((rtab = mib_fetch_rtab(AF_INET, NET_RT_DUMP, 0, &len)) == NULL) 72 return (-1); 73 74 next = rtab; 75 for (next = rtab; next < rtab + len; next += rtm->rtm_msglen) { 76 rtm = (struct rt_msghdr *)(void *)next; 77 if (rtm->rtm_type != RTM_GET || 78 !(rtm->rtm_flags & RTF_UP)) 79 continue; 80 mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); 81 82 if (addrs[RTAX_DST] == NULL || addrs[RTAX_GATEWAY] == NULL || 83 addrs[RTAX_DST]->sa_family != AF_INET) 84 continue; 85 86 sa = (struct sockaddr_in *)(void *)addrs[RTAX_DST]; 87 88 if (rtm->rtm_flags & RTF_HOST) { 89 mask.s_addr = 0xffffffff; 90 } else { 91 if (addrs[RTAX_NETMASK] == NULL || 92 addrs[RTAX_NETMASK]->sa_len == 0) 93 mask.s_addr = 0; 94 else 95 mask = ((struct sockaddr_in *)(void *) 96 addrs[RTAX_NETMASK])->sin_addr; 97 } 98 if (addrs[RTAX_GATEWAY] == NULL) { 99 nhop.s_addr = 0; 100 } else if (rtm->rtm_flags & RTF_LLINFO) { 101 nhop = sa->sin_addr; 102 } else { 103 gw = (struct sockaddr_in *)(void *)addrs[RTAX_GATEWAY]; 104 if (gw->sin_family != AF_INET) 105 continue; 106 nhop = gw->sin_addr; 107 } 108 if ((ifp = mib_find_if_sys(rtm->rtm_index)) == NULL) { 109 mib_iflist_bad = 1; 110 continue; 111 } 112 113 if ((r = malloc(sizeof(*r))) == NULL) { 114 syslog(LOG_ERR, "%m"); 115 continue; 116 } 117 118 route_total++; 119 120 r->index.len = 13; 121 ha = ntohl(sa->sin_addr.s_addr); 122 r->index.subs[0] = (ha >> 24) & 0xff; 123 r->index.subs[1] = (ha >> 16) & 0xff; 124 r->index.subs[2] = (ha >> 8) & 0xff; 125 r->index.subs[3] = (ha >> 0) & 0xff; 126 ha = ntohl(mask.s_addr); 127 r->index.subs[4] = (ha >> 24) & 0xff; 128 r->index.subs[5] = (ha >> 16) & 0xff; 129 r->index.subs[6] = (ha >> 8) & 0xff; 130 r->index.subs[7] = (ha >> 0) & 0xff; 131 132 r->index.subs[8] = 0; 133 134 ha = ntohl(nhop.s_addr); 135 r->index.subs[9] = (ha >> 24) & 0xff; 136 r->index.subs[10] = (ha >> 16) & 0xff; 137 r->index.subs[11] = (ha >> 8) & 0xff; 138 r->index.subs[12] = (ha >> 0) & 0xff; 139 140 r->ifindex = ifp->index; 141 142 r->type = (rtm->rtm_flags & RTF_LLINFO) ? 3 : 143 (rtm->rtm_flags & RTF_REJECT) ? 2 : 4; 144 145 /* cannot really know, what protocol it runs */ 146 r->proto = (rtm->rtm_flags & RTF_LOCAL) ? 2 : 147 (rtm->rtm_flags & RTF_STATIC) ? 3 : 148 (rtm->rtm_flags & RTF_DYNAMIC) ? 4 : 10; 149 150 INSERT_OBJECT_OID(r, &sroute_list); 151 } 152 153 free(rtab); 154 route_tick = get_ticks(); 155 156 return (0); 157 } 158 159 /* 160 * Table 161 */ 162 int 163 op_route_table(struct snmp_context *ctx __unused, struct snmp_value *value, 164 u_int sub, u_int iidx __unused, enum snmp_op op) 165 { 166 static struct sroute *r; 167 168 if (route_tick < this_tick) 169 if (fetch_route() == -1) 170 return (SNMP_ERR_GENERR); 171 172 switch (op) { 173 174 case SNMP_OP_GETNEXT: 175 if ((r = NEXT_OBJECT_OID(&sroute_list, &value->var, sub)) == NULL) 176 return (SNMP_ERR_NOSUCHNAME); 177 index_append(&value->var, sub, &r->index); 178 break; 179 180 case SNMP_OP_GET: 181 if ((r = FIND_OBJECT_OID(&sroute_list, &value->var, sub)) == NULL) 182 return (SNMP_ERR_NOSUCHNAME); 183 break; 184 185 case SNMP_OP_SET: 186 if ((r = FIND_OBJECT_OID(&sroute_list, &value->var, sub)) == NULL) 187 return (SNMP_ERR_NO_CREATION); 188 return (SNMP_ERR_NOT_WRITEABLE); 189 190 case SNMP_OP_ROLLBACK: 191 case SNMP_OP_COMMIT: 192 abort(); 193 194 default: 195 abort(); 196 } 197 198 switch (value->var.subs[sub - 1]) { 199 200 case LEAF_ipCidrRouteDest: 201 value->v.ipaddress[0] = r->index.subs[0]; 202 value->v.ipaddress[1] = r->index.subs[1]; 203 value->v.ipaddress[2] = r->index.subs[2]; 204 value->v.ipaddress[3] = r->index.subs[3]; 205 break; 206 207 case LEAF_ipCidrRouteMask: 208 value->v.ipaddress[0] = r->index.subs[4]; 209 value->v.ipaddress[1] = r->index.subs[5]; 210 value->v.ipaddress[2] = r->index.subs[6]; 211 value->v.ipaddress[3] = r->index.subs[7]; 212 break; 213 214 case LEAF_ipCidrRouteTos: 215 value->v.integer = r->index.subs[8]; 216 break; 217 218 case LEAF_ipCidrRouteNextHop: 219 value->v.ipaddress[0] = r->index.subs[9]; 220 value->v.ipaddress[1] = r->index.subs[10]; 221 value->v.ipaddress[2] = r->index.subs[11]; 222 value->v.ipaddress[3] = r->index.subs[12]; 223 break; 224 225 case LEAF_ipCidrRouteIfIndex: 226 value->v.integer = r->ifindex; 227 break; 228 229 case LEAF_ipCidrRouteType: 230 value->v.integer = r->type; 231 break; 232 233 case LEAF_ipCidrRouteProto: 234 value->v.integer = r->proto; 235 break; 236 237 case LEAF_ipCidrRouteAge: 238 value->v.integer = 0; 239 break; 240 241 case LEAF_ipCidrRouteInfo: 242 value->v.oid = oid_zeroDotZero; 243 break; 244 245 case LEAF_ipCidrRouteNextHopAS: 246 value->v.integer = 0; 247 break; 248 249 case LEAF_ipCidrRouteMetric1: 250 case LEAF_ipCidrRouteMetric2: 251 case LEAF_ipCidrRouteMetric3: 252 case LEAF_ipCidrRouteMetric4: 253 case LEAF_ipCidrRouteMetric5: 254 value->v.integer = -1; 255 break; 256 257 case LEAF_ipCidrRouteStatus: 258 value->v.integer = 1; 259 break; 260 } 261 return (SNMP_ERR_NOERROR); 262 } 263 264 /* 265 * scalars 266 */ 267 int 268 op_route(struct snmp_context *ctx __unused, struct snmp_value *value, 269 u_int sub, u_int iidx __unused, enum snmp_op op) 270 { 271 switch (op) { 272 273 case SNMP_OP_GETNEXT: 274 abort(); 275 276 case SNMP_OP_GET: 277 break; 278 279 case SNMP_OP_SET: 280 return (SNMP_ERR_NOT_WRITEABLE); 281 282 case SNMP_OP_ROLLBACK: 283 case SNMP_OP_COMMIT: 284 abort(); 285 } 286 287 if (route_tick < this_tick) 288 if (fetch_route() == -1) 289 return (SNMP_ERR_GENERR); 290 291 switch (value->var.subs[sub - 1]) { 292 293 case LEAF_ipCidrRouteNumber: 294 value->v.uint32 = route_total; 295 break; 296 297 } 298 return (SNMP_ERR_NOERROR); 299 } 300