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