Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bsnmp/snmp_mibII/mibII_route.c
39478 views
1
/*
2
* Copyright (c) 2001-2003
3
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4
* All rights reserved.
5
*
6
* Author: Harti Brandt <[email protected]>
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
* 1. Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*
29
* $Begemot: bsnmp/snmp_mibII/mibII_route.c,v 1.9 2005/10/06 07:15:00 brandt_h Exp $
30
*
31
* Routing table
32
*/
33
34
#ifdef HAVE_SYS_TREE_H
35
#include <sys/tree.h>
36
#else
37
#include "tree.h"
38
#endif
39
40
#include "mibII.h"
41
#include "mibII_oid.h"
42
43
struct sroute {
44
RB_ENTRY(sroute) link;
45
uint32_t ifindex;
46
uint8_t index[13];
47
uint8_t type;
48
uint8_t proto;
49
};
50
static RB_HEAD(sroutes, sroute) sroutes = RB_INITIALIZER(&sroutes);
51
52
RB_PROTOTYPE(sroutes, sroute, link, sroute_compare);
53
54
#define ROUTE_UPDATE_INTERVAL (100 * 60 * 10) /* 10 min */
55
static uint64_t route_tick;
56
static u_int route_total;
57
58
/*
59
* Compare two routes
60
*/
61
static int
62
sroute_compare(struct sroute *s1, struct sroute *s2)
63
{
64
65
return (memcmp(s1->index, s2->index, 13));
66
}
67
68
static void
69
sroute_index_append(struct asn_oid *oid, u_int sub, const struct sroute *s)
70
{
71
int i;
72
73
oid->len = sub + 13;
74
for (i = 0; i < 13; i++)
75
oid->subs[sub + i] = s->index[i];
76
}
77
78
#if 0
79
static void
80
sroute_print(const struct sroute *r)
81
{
82
u_int i;
83
84
for (i = 0; i < 13 - 1; i++)
85
printf("%u.", r->index[i]);
86
printf("%u proto=%u type=%u", r->index[i], r->proto, r->type);
87
}
88
#endif
89
90
/*
91
* process routing message
92
*/
93
void
94
mib_sroute_process(struct rt_msghdr *rtm, struct sockaddr *gw,
95
struct sockaddr *dst, struct sockaddr *mask)
96
{
97
struct sockaddr_in *in_dst, *in_gw;
98
struct in_addr in_mask;
99
struct mibif *ifp;
100
struct sroute key;
101
struct sroute *r, *r1;
102
in_addr_t ha;
103
104
if (dst == NULL || gw == NULL || dst->sa_family != AF_INET ||
105
gw->sa_family != AF_INET)
106
return;
107
108
in_dst = (struct sockaddr_in *)(void *)dst;
109
in_gw = (struct sockaddr_in *)(void *)gw;
110
111
if (rtm->rtm_flags & RTF_HOST)
112
in_mask.s_addr = 0xffffffff;
113
else if (mask == NULL || mask->sa_len == 0)
114
in_mask.s_addr = 0;
115
else
116
in_mask = ((struct sockaddr_in *)(void *)mask)->sin_addr;
117
118
/* build the index */
119
ha = ntohl(in_dst->sin_addr.s_addr);
120
key.index[0] = (ha >> 24) & 0xff;
121
key.index[1] = (ha >> 16) & 0xff;
122
key.index[2] = (ha >> 8) & 0xff;
123
key.index[3] = (ha >> 0) & 0xff;
124
125
ha = ntohl(in_mask.s_addr);
126
key.index[4] = (ha >> 24) & 0xff;
127
key.index[5] = (ha >> 16) & 0xff;
128
key.index[6] = (ha >> 8) & 0xff;
129
key.index[7] = (ha >> 0) & 0xff;
130
131
/* ToS */
132
key.index[8] = 0;
133
134
ha = ntohl(in_gw->sin_addr.s_addr);
135
key.index[9] = (ha >> 24) & 0xff;
136
key.index[10] = (ha >> 16) & 0xff;
137
key.index[11] = (ha >> 8) & 0xff;
138
key.index[12] = (ha >> 0) & 0xff;
139
140
if (rtm->rtm_type == RTM_DELETE) {
141
r = RB_FIND(sroutes, &sroutes, &key);
142
if (r == 0) {
143
#ifdef DEBUG_ROUTE
144
syslog(LOG_WARNING, "%s: DELETE: %u.%u.%u.%u "
145
"%u.%u.%u.%u %u %u.%u.%u.%u not found", __func__,
146
key.index[0], key.index[1], key.index[2],
147
key.index[3], key.index[4], key.index[5],
148
key.index[6], key.index[7], key.index[8],
149
key.index[9], key.index[10], key.index[11],
150
key.index[12]);
151
#endif
152
return;
153
}
154
RB_REMOVE(sroutes, &sroutes, r);
155
free(r);
156
route_total--;
157
#ifdef DEBUG_ROUTE
158
printf("%s: DELETE: %u.%u.%u.%u "
159
"%u.%u.%u.%u %u %u.%u.%u.%u\n", __func__,
160
key.index[0], key.index[1], key.index[2],
161
key.index[3], key.index[4], key.index[5],
162
key.index[6], key.index[7], key.index[8],
163
key.index[9], key.index[10], key.index[11],
164
key.index[12]);
165
#endif
166
return;
167
}
168
169
/* GET or ADD */
170
ifp = NULL;
171
if ((ifp = mib_find_if_sys(rtm->rtm_index)) == NULL) {
172
if (rtm->rtm_type == RTM_ADD) {
173
/* make it a get so the kernel fills the index */
174
mib_send_rtmsg(rtm, gw, dst, mask);
175
return;
176
}
177
mib_iflist_bad = 1;
178
}
179
180
if ((r = malloc(sizeof(*r))) == NULL) {
181
syslog(LOG_ERR, "%m");
182
return;
183
}
184
185
memcpy(r->index, key.index, sizeof(r->index));
186
r->ifindex = (ifp == NULL) ? 0 : ifp->index;
187
188
r->type = (rtm->rtm_flags & RTF_REJECT) ? 2 : 4;
189
190
/* cannot really know, what protocol it runs */
191
r->proto = (rtm->rtm_flags & RTF_LOCAL) ? 2 :
192
(rtm->rtm_flags & RTF_STATIC) ? 3 :
193
(rtm->rtm_flags & RTF_DYNAMIC) ? 4 : 10;
194
195
r1 = RB_INSERT(sroutes, &sroutes, r);
196
if (r1 != NULL) {
197
#ifdef DEBUG_ROUTE
198
syslog(LOG_WARNING, "%s: %u.%u.%u.%u "
199
"%u.%u.%u.%u %u %u.%u.%u.%u duplicate route", __func__,
200
key.index[0], key.index[1], key.index[2],
201
key.index[3], key.index[4], key.index[5],
202
key.index[6], key.index[7], key.index[8],
203
key.index[9], key.index[10], key.index[11],
204
key.index[12]);
205
#endif
206
r1->ifindex = r->ifindex;
207
r1->type = r->type;
208
r1->proto = r->proto;
209
free(r);
210
return;
211
}
212
213
route_total++;
214
#ifdef DEBUG_ROUTE
215
printf("%s: ADD/GET: %u.%u.%u.%u "
216
"%u.%u.%u.%u %u %u.%u.%u.%u\n", __func__,
217
key.index[0], key.index[1], key.index[2],
218
key.index[3], key.index[4], key.index[5],
219
key.index[6], key.index[7], key.index[8],
220
key.index[9], key.index[10], key.index[11],
221
key.index[12]);
222
#endif
223
}
224
225
int
226
mib_fetch_route(void)
227
{
228
u_char *rtab, *next;
229
size_t len;
230
struct sroute *r, *r1;
231
struct rt_msghdr *rtm;
232
struct sockaddr *addrs[RTAX_MAX];
233
234
if (route_tick != 0 && route_tick + ROUTE_UPDATE_INTERVAL > this_tick)
235
return (0);
236
237
/*
238
* Remove all routes
239
*/
240
r = RB_MIN(sroutes, &sroutes);
241
while (r != NULL) {
242
r1 = RB_NEXT(sroutes, &sroutes, r);
243
RB_REMOVE(sroutes, &sroutes, r);
244
free(r);
245
r = r1;
246
}
247
route_total = 0;
248
249
if ((rtab = mib_fetch_rtab(AF_INET, NET_RT_DUMP, 0, &len)) == NULL)
250
return (-1);
251
252
next = rtab;
253
for (next = rtab; next < rtab + len; next += rtm->rtm_msglen) {
254
rtm = (struct rt_msghdr *)(void *)next;
255
if (rtm->rtm_type != RTM_GET ||
256
!(rtm->rtm_flags & RTF_UP))
257
continue;
258
mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs);
259
260
261
mib_sroute_process(rtm, addrs[RTAX_GATEWAY], addrs[RTAX_DST],
262
addrs[RTAX_NETMASK]);
263
}
264
265
#if 0
266
u_int n = 0;
267
r = RB_MIN(sroutes, &sroutes);
268
while (r != NULL) {
269
printf("%u: ", n++);
270
sroute_print(r);
271
printf("\n");
272
r = RB_NEXT(sroutes, &sroutes, r);
273
}
274
#endif
275
free(rtab);
276
route_tick = get_ticks();
277
278
return (0);
279
}
280
281
/**
282
* Find a route in the table.
283
*/
284
static struct sroute *
285
sroute_get(const struct asn_oid *oid, u_int sub)
286
{
287
struct sroute key;
288
int i;
289
290
if (oid->len - sub != 13)
291
return (NULL);
292
for (i = 0; i < 13; i++)
293
key.index[i] = oid->subs[sub + i];
294
return (RB_FIND(sroutes, &sroutes, &key));
295
}
296
297
/**
298
* Find next route in the table. There is no such RB_ macro, so must
299
* dig into the innards of the RB stuff.
300
*/
301
static struct sroute *
302
sroute_getnext(struct asn_oid *oid, u_int sub)
303
{
304
u_int i;
305
int comp;
306
struct sroute key;
307
struct sroute *best;
308
struct sroute *s;
309
310
/*
311
* We now, that the OID is at least the tableEntry OID. If it is,
312
* the user wants the first route.
313
*/
314
if (oid->len == sub)
315
return (RB_MIN(sroutes, &sroutes));
316
317
/*
318
* This is also true for any index that consists of zeros and is
319
* shorter than the full index.
320
*/
321
if (oid->len < sub + 13) {
322
for (i = sub; i < oid->len; i++)
323
if (oid->subs[i] != 0)
324
break;
325
if (i == oid->len)
326
return (RB_MIN(sroutes, &sroutes));
327
328
/*
329
* Now if the index is too short, we fill it with zeros and then
330
* subtract one from the index. We can do this, because we now,
331
* that there is at least one index element that is not zero.
332
*/
333
for (i = oid->len; i < sub + 13; i++)
334
oid->subs[i] = 0;
335
336
for (i = sub + 13 - 1; i >= sub; i--) {
337
if (oid->subs[i] != 0) {
338
oid->subs[i]--;
339
break;
340
}
341
oid->subs[i] = ASN_MAXID;
342
}
343
oid->len = sub + 13;
344
}
345
346
/* build the index */
347
for (i = sub; i < sub + 13; i++)
348
key.index[i - sub] = oid->subs[i];
349
350
/* now find the element */
351
best = NULL;
352
s = RB_ROOT(&sroutes);
353
354
while (s != NULL) {
355
comp = sroute_compare(&key, s);
356
if (comp >= 0) {
357
/* The current element is smaller than what we search.
358
* Forget about it and move to the right subtree. */
359
s = RB_RIGHT(s, link);
360
continue;
361
}
362
/* the current element is larger than what we search.
363
* forget about the right subtree (its even larger), but
364
* the current element may be what we need. */
365
if (best == NULL || sroute_compare(s, best) < 0)
366
/* this one's better */
367
best = s;
368
369
s = RB_LEFT(s, link);
370
}
371
return (best);
372
}
373
374
/*
375
* Table
376
*/
377
int
378
op_route_table(struct snmp_context *ctx __unused, struct snmp_value *value,
379
u_int sub, u_int iidx __unused, enum snmp_op op)
380
{
381
struct sroute *r;
382
383
if (mib_fetch_route() == -1)
384
return (SNMP_ERR_GENERR);
385
386
switch (op) {
387
388
case SNMP_OP_GETNEXT:
389
if ((r = sroute_getnext(&value->var, sub)) == NULL)
390
return (SNMP_ERR_NOSUCHNAME);
391
sroute_index_append(&value->var, sub, r);
392
break;
393
394
case SNMP_OP_GET:
395
if ((r = sroute_get(&value->var, sub)) == NULL)
396
return (SNMP_ERR_NOSUCHNAME);
397
break;
398
399
case SNMP_OP_SET:
400
if ((r = sroute_get(&value->var, sub)) == NULL)
401
return (SNMP_ERR_NOSUCHNAME);
402
return (SNMP_ERR_NOT_WRITEABLE);
403
404
case SNMP_OP_ROLLBACK:
405
case SNMP_OP_COMMIT:
406
abort();
407
408
default:
409
abort();
410
}
411
412
switch (value->var.subs[sub - 1]) {
413
414
case LEAF_ipCidrRouteDest:
415
value->v.ipaddress[0] = r->index[0];
416
value->v.ipaddress[1] = r->index[1];
417
value->v.ipaddress[2] = r->index[2];
418
value->v.ipaddress[3] = r->index[3];
419
break;
420
421
case LEAF_ipCidrRouteMask:
422
value->v.ipaddress[0] = r->index[4];
423
value->v.ipaddress[1] = r->index[5];
424
value->v.ipaddress[2] = r->index[6];
425
value->v.ipaddress[3] = r->index[7];
426
break;
427
428
case LEAF_ipCidrRouteTos:
429
value->v.integer = r->index[8];
430
break;
431
432
case LEAF_ipCidrRouteNextHop:
433
value->v.ipaddress[0] = r->index[9];
434
value->v.ipaddress[1] = r->index[10];
435
value->v.ipaddress[2] = r->index[11];
436
value->v.ipaddress[3] = r->index[12];
437
break;
438
439
case LEAF_ipCidrRouteIfIndex:
440
value->v.integer = r->ifindex;
441
break;
442
443
case LEAF_ipCidrRouteType:
444
value->v.integer = r->type;
445
break;
446
447
case LEAF_ipCidrRouteProto:
448
value->v.integer = r->proto;
449
break;
450
451
case LEAF_ipCidrRouteAge:
452
value->v.integer = 0;
453
break;
454
455
case LEAF_ipCidrRouteInfo:
456
value->v.oid = oid_zeroDotZero;
457
break;
458
459
case LEAF_ipCidrRouteNextHopAS:
460
value->v.integer = 0;
461
break;
462
463
case LEAF_ipCidrRouteMetric1:
464
case LEAF_ipCidrRouteMetric2:
465
case LEAF_ipCidrRouteMetric3:
466
case LEAF_ipCidrRouteMetric4:
467
case LEAF_ipCidrRouteMetric5:
468
value->v.integer = -1;
469
break;
470
471
case LEAF_ipCidrRouteStatus:
472
value->v.integer = 1;
473
break;
474
}
475
return (SNMP_ERR_NOERROR);
476
}
477
478
/*
479
* scalars
480
*/
481
int
482
op_route(struct snmp_context *ctx __unused, struct snmp_value *value,
483
u_int sub, u_int iidx __unused, enum snmp_op op)
484
{
485
switch (op) {
486
487
case SNMP_OP_GETNEXT:
488
abort();
489
490
case SNMP_OP_GET:
491
break;
492
493
case SNMP_OP_SET:
494
return (SNMP_ERR_NOT_WRITEABLE);
495
496
case SNMP_OP_ROLLBACK:
497
case SNMP_OP_COMMIT:
498
abort();
499
}
500
501
if (mib_fetch_route() == -1)
502
return (SNMP_ERR_GENERR);
503
504
switch (value->var.subs[sub - 1]) {
505
506
case LEAF_ipCidrRouteNumber:
507
value->v.uint32 = route_total;
508
break;
509
510
}
511
return (SNMP_ERR_NOERROR);
512
}
513
514
RB_GENERATE(sroutes, sroute, link, sroute_compare);
515
516