Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bsnmp/snmp_mibII/mibII.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: mibII.c 516 2006-10-27 15:54:02Z brandt_h $
30
*
31
* Implementation of the standard interfaces and ip MIB.
32
*/
33
#include "mibII.h"
34
#include "mibII_oid.h"
35
#include <net/if.h>
36
#include <net/if_types.h>
37
38
39
/*****************************/
40
41
/* our module */
42
static struct lmodule *module;
43
44
/* routing socket */
45
static int route;
46
static void *route_fd;
47
48
/* if-index allocator */
49
static uint32_t next_if_index = 1;
50
51
/* currently fetching the arp table */
52
static int in_update_arp;
53
54
/* OR registrations */
55
static u_int ifmib_reg;
56
static u_int ipmib_reg;
57
static u_int tcpmib_reg;
58
static u_int udpmib_reg;
59
static u_int ipForward_reg;
60
61
/*****************************/
62
63
/* list of all IP addresses */
64
struct mibifa_list mibifa_list = TAILQ_HEAD_INITIALIZER(mibifa_list);
65
66
/* list of all interfaces */
67
struct mibif_list mibif_list = TAILQ_HEAD_INITIALIZER(mibif_list);
68
69
/* list of dynamic interface names */
70
struct mibdynif_list mibdynif_list = SLIST_HEAD_INITIALIZER(mibdynif_list);
71
72
/* list of all interface index mappings */
73
struct mibindexmap_list mibindexmap_list = STAILQ_HEAD_INITIALIZER(mibindexmap_list);
74
75
/* list of all stacking entries */
76
struct mibifstack_list mibifstack_list = TAILQ_HEAD_INITIALIZER(mibifstack_list);
77
78
/* list of all receive addresses */
79
struct mibrcvaddr_list mibrcvaddr_list = TAILQ_HEAD_INITIALIZER(mibrcvaddr_list);
80
81
/* list of all NetToMedia entries */
82
struct mibarp_list mibarp_list = TAILQ_HEAD_INITIALIZER(mibarp_list);
83
84
/* number of interfaces */
85
int32_t mib_if_number;
86
87
/* last change of table */
88
uint64_t mib_iftable_last_change;
89
90
/* last change of stack table */
91
uint64_t mib_ifstack_last_change;
92
93
/* if this is set, one of our lists may be bad. refresh them when idle */
94
int mib_iflist_bad;
95
96
/* network socket */
97
int mib_netsock;
98
99
/* last time refreshed */
100
uint64_t mibarpticks;
101
102
/* list of all New if registrations */
103
static struct newifreg_list newifreg_list = TAILQ_HEAD_INITIALIZER(newifreg_list);
104
105
/* baud rate of fastest interface */
106
uint64_t mibif_maxspeed;
107
108
/* user-forced update interval */
109
u_int mibif_force_hc_update_interval;
110
111
/* current update interval */
112
u_int mibif_hc_update_interval;
113
114
/* HC update timer handle */
115
static void *hc_update_timer;
116
117
/* Idle poll timer */
118
static void *mibII_poll_timer;
119
120
/* interfaces' data poll interval */
121
u_int mibII_poll_ticks;
122
123
/* Idle poll hook */
124
static void mibII_idle(void *arg __unused);
125
126
/*****************************/
127
128
static const struct asn_oid oid_ifMIB = OIDX_ifMIB;
129
static const struct asn_oid oid_ipMIB = OIDX_ipMIB;
130
static const struct asn_oid oid_tcpMIB = OIDX_tcpMIB;
131
static const struct asn_oid oid_udpMIB = OIDX_udpMIB;
132
static const struct asn_oid oid_ipForward = OIDX_ipForward;
133
static const struct asn_oid oid_linkDown = OIDX_linkDown;
134
static const struct asn_oid oid_linkUp = OIDX_linkUp;
135
static const struct asn_oid oid_ifIndex = OIDX_ifIndex;
136
137
/*****************************/
138
139
/*
140
* Find an interface
141
*/
142
struct mibif *
143
mib_find_if(u_int idx)
144
{
145
struct mibif *ifp;
146
147
TAILQ_FOREACH(ifp, &mibif_list, link)
148
if (ifp->index == idx)
149
return (ifp);
150
return (NULL);
151
}
152
153
struct mibif *
154
mib_find_if_sys(u_int sysindex)
155
{
156
struct mibif *ifp;
157
158
TAILQ_FOREACH(ifp, &mibif_list, link)
159
if (ifp->sysindex == sysindex)
160
return (ifp);
161
return (NULL);
162
}
163
164
struct mibif *
165
mib_find_if_name(const char *name)
166
{
167
struct mibif *ifp;
168
169
TAILQ_FOREACH(ifp, &mibif_list, link)
170
if (strcmp(ifp->name, name) == 0)
171
return (ifp);
172
return (NULL);
173
}
174
175
/*
176
* Check whether an interface is dynamic. The argument may include the
177
* unit number. This assumes, that the name part does NOT contain digits.
178
*/
179
int
180
mib_if_is_dyn(const char *name)
181
{
182
size_t len;
183
struct mibdynif *d;
184
185
for (len = 0; name[len] != '\0' && isalpha(name[len]) ; len++)
186
;
187
SLIST_FOREACH(d, &mibdynif_list, link)
188
if (strlen(d->name) == len && strncmp(d->name, name, len) == 0)
189
return (1);
190
return (0);
191
}
192
193
/* set an interface name to dynamic mode */
194
void
195
mib_if_set_dyn(const char *name)
196
{
197
struct mibdynif *d;
198
199
SLIST_FOREACH(d, &mibdynif_list, link)
200
if (strcmp(name, d->name) == 0)
201
return;
202
if ((d = malloc(sizeof(*d))) == NULL)
203
err(1, NULL);
204
strlcpy(d->name, name, sizeof(d->name));
205
SLIST_INSERT_HEAD(&mibdynif_list, d, link);
206
}
207
208
/*
209
* register for interface creations
210
*/
211
int
212
mib_register_newif(int (*func)(struct mibif *), const struct lmodule *mod)
213
{
214
struct newifreg *reg;
215
216
TAILQ_FOREACH(reg, &newifreg_list, link)
217
if (reg->mod == mod) {
218
reg->func = func;
219
return (0);
220
}
221
if ((reg = malloc(sizeof(*reg))) == NULL) {
222
syslog(LOG_ERR, "newifreg: %m");
223
return (-1);
224
}
225
reg->mod = mod;
226
reg->func = func;
227
TAILQ_INSERT_TAIL(&newifreg_list, reg, link);
228
229
return (0);
230
}
231
232
void
233
mib_unregister_newif(const struct lmodule *mod)
234
{
235
struct newifreg *reg;
236
237
TAILQ_FOREACH(reg, &newifreg_list, link)
238
if (reg->mod == mod) {
239
TAILQ_REMOVE(&newifreg_list, reg, link);
240
free(reg);
241
return;
242
}
243
244
}
245
246
struct mibif *
247
mib_first_if(void)
248
{
249
return (TAILQ_FIRST(&mibif_list));
250
}
251
struct mibif *
252
mib_next_if(const struct mibif *ifp)
253
{
254
return (TAILQ_NEXT(ifp, link));
255
}
256
257
/*
258
* Change the admin status of an interface
259
*/
260
int
261
mib_if_admin(struct mibif *ifp, int up)
262
{
263
struct ifreq ifr;
264
265
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
266
if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) {
267
syslog(LOG_ERR, "SIOCGIFFLAGS(%s): %m", ifp->name);
268
return (-1);
269
}
270
if (up)
271
ifr.ifr_flags |= IFF_UP;
272
else
273
ifr.ifr_flags &= ~IFF_UP;
274
if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) {
275
syslog(LOG_ERR, "SIOCSIFFLAGS(%s): %m", ifp->name);
276
return (-1);
277
}
278
279
(void)mib_fetch_ifmib(ifp);
280
281
return (0);
282
}
283
284
/*
285
* Generate a link up/down trap
286
*/
287
static void
288
link_trap(struct mibif *ifp, int up)
289
{
290
struct snmp_value ifindex;
291
292
ifindex.var = oid_ifIndex;
293
ifindex.var.subs[ifindex.var.len++] = ifp->index;
294
ifindex.syntax = SNMP_SYNTAX_INTEGER;
295
ifindex.v.integer = ifp->index;
296
297
snmp_send_trap(up ? &oid_linkUp : &oid_linkDown, &ifindex,
298
(struct snmp_value *)NULL);
299
}
300
301
/**
302
* Fetch the GENERIC IFMIB and update the HC counters
303
*/
304
static int
305
fetch_generic_mib(struct mibif *ifp, const struct ifmibdata *old)
306
{
307
int name[6];
308
size_t len;
309
struct mibif_private *p = ifp->private;
310
311
name[0] = CTL_NET;
312
name[1] = PF_LINK;
313
name[2] = NETLINK_GENERIC;
314
name[3] = IFMIB_IFDATA;
315
name[4] = ifp->sysindex;
316
name[5] = IFDATA_GENERAL;
317
318
len = sizeof(ifp->mib);
319
if (sysctl(name, nitems(name), &ifp->mib, &len, NULL, 0) == -1) {
320
if (errno != ENOENT)
321
syslog(LOG_WARNING, "sysctl(ifmib, %s) failed %m",
322
ifp->name);
323
return (-1);
324
}
325
326
/*
327
* Assume that one of the two following compounds is optimized away
328
*/
329
if (ULONG_MAX >= 0xffffffffffffffffULL) {
330
p->hc_inoctets = ifp->mib.ifmd_data.ifi_ibytes;
331
p->hc_outoctets = ifp->mib.ifmd_data.ifi_obytes;
332
p->hc_omcasts = ifp->mib.ifmd_data.ifi_omcasts;
333
p->hc_opackets = ifp->mib.ifmd_data.ifi_opackets;
334
p->hc_imcasts = ifp->mib.ifmd_data.ifi_imcasts;
335
p->hc_ipackets = ifp->mib.ifmd_data.ifi_ipackets;
336
337
} else if (ULONG_MAX >= 0xffffffff) {
338
339
#define UPDATE(HC, MIB) \
340
if (old->ifmd_data.MIB > ifp->mib.ifmd_data.MIB) \
341
p->HC += (0x100000000ULL + \
342
ifp->mib.ifmd_data.MIB) - \
343
old->ifmd_data.MIB; \
344
else \
345
p->HC += ifp->mib.ifmd_data.MIB - \
346
old->ifmd_data.MIB;
347
348
UPDATE(hc_inoctets, ifi_ibytes)
349
UPDATE(hc_outoctets, ifi_obytes)
350
UPDATE(hc_omcasts, ifi_omcasts)
351
UPDATE(hc_opackets, ifi_opackets)
352
UPDATE(hc_imcasts, ifi_imcasts)
353
UPDATE(hc_ipackets, ifi_ipackets)
354
355
#undef UPDATE
356
} else
357
abort();
358
return (0);
359
}
360
361
/**
362
* Update the 64-bit interface counters
363
*/
364
static void
365
update_hc_counters(void *arg __unused)
366
{
367
struct mibif *ifp;
368
struct ifmibdata oldmib;
369
370
TAILQ_FOREACH(ifp, &mibif_list, link) {
371
oldmib = ifp->mib;
372
(void)fetch_generic_mib(ifp, &oldmib);
373
}
374
}
375
376
/**
377
* Recompute the poll timer for the HC counters
378
*/
379
void
380
mibif_reset_hc_timer(void)
381
{
382
u_int ticks;
383
384
if ((ticks = mibif_force_hc_update_interval) == 0) {
385
if (mibif_maxspeed <= IF_Mbps(10)) {
386
/* at 10Mbps overflow needs 3436 seconds */
387
ticks = 3000 * 100; /* 50 minutes */
388
} else if (mibif_maxspeed <= IF_Mbps(100)) {
389
/* at 100Mbps overflow needs 343 seconds */
390
ticks = 300 * 100; /* 5 minutes */
391
} else if (mibif_maxspeed < IF_Mbps(622)) {
392
/* at 622Mbps overflow needs 53 seconds */
393
ticks = 40 * 100; /* 40 seconds */
394
} else if (mibif_maxspeed <= IF_Mbps(1000)) {
395
/* at 1Gbps overflow needs 34 seconds */
396
ticks = 20 * 100; /* 20 seconds */
397
} else {
398
/* at 10Gbps overflow needs 3.4 seconds */
399
ticks = 100; /* 1 seconds */
400
}
401
}
402
403
if (ticks == mibif_hc_update_interval)
404
return;
405
406
if (hc_update_timer != NULL) {
407
timer_stop(hc_update_timer);
408
hc_update_timer = NULL;
409
}
410
update_hc_counters(NULL);
411
if ((hc_update_timer = timer_start_repeat(ticks, ticks,
412
update_hc_counters, NULL, module)) == NULL) {
413
syslog(LOG_ERR, "timer_start(%u): %m", ticks);
414
return;
415
}
416
mibif_hc_update_interval = ticks;
417
}
418
419
/**
420
* Restart the idle poll timer.
421
*/
422
void
423
mibif_restart_mibII_poll_timer(void)
424
{
425
if (mibII_poll_timer != NULL)
426
timer_stop(mibII_poll_timer);
427
428
if ((mibII_poll_timer = timer_start_repeat(mibII_poll_ticks * 10,
429
mibII_poll_ticks * 10, mibII_idle, NULL, module)) == NULL)
430
syslog(LOG_ERR, "timer_start(%u): %m", mibII_poll_ticks);
431
}
432
433
/*
434
* Fetch new MIB data.
435
*/
436
int
437
mib_fetch_ifmib(struct mibif *ifp)
438
{
439
static int kmib[2] = { -1, 0 }; /* for sysctl net.ifdescr_maxlen */
440
441
int name[6];
442
size_t kmiblen = nitems(kmib);
443
size_t len;
444
void *newmib;
445
struct ifmibdata oldmib = ifp->mib;
446
struct ifreq irr;
447
u_int alias_maxlen = MIBIF_ALIAS_SIZE_MAX;
448
449
if (fetch_generic_mib(ifp, &oldmib) == -1)
450
return (-1);
451
452
/*
453
* Quoting RFC2863, 3.1.15: "... LinkUp and linkDown traps are
454
* generated just after ifOperStatus leaves, or just before it
455
* enters, the down state, respectively;"
456
*/
457
if (ifp->trap_enable && ifp->mib.ifmd_data.ifi_link_state !=
458
oldmib.ifmd_data.ifi_link_state &&
459
(ifp->mib.ifmd_data.ifi_link_state == LINK_STATE_DOWN ||
460
oldmib.ifmd_data.ifi_link_state == LINK_STATE_DOWN))
461
link_trap(ifp, ifp->mib.ifmd_data.ifi_link_state ==
462
LINK_STATE_UP ? 1 : 0);
463
464
ifp->flags &= ~(MIBIF_HIGHSPEED | MIBIF_VERYHIGHSPEED);
465
if (ifp->mib.ifmd_data.ifi_baudrate > 20000000) {
466
ifp->flags |= MIBIF_HIGHSPEED;
467
if (ifp->mib.ifmd_data.ifi_baudrate > 650000000)
468
ifp->flags |= MIBIF_VERYHIGHSPEED;
469
}
470
if (ifp->mib.ifmd_data.ifi_baudrate > mibif_maxspeed) {
471
mibif_maxspeed = ifp->mib.ifmd_data.ifi_baudrate;
472
mibif_reset_hc_timer();
473
}
474
475
/*
476
* linkspecific MIB
477
*/
478
name[0] = CTL_NET;
479
name[1] = PF_LINK;
480
name[2] = NETLINK_GENERIC;
481
name[3] = IFMIB_IFDATA;
482
name[4] = ifp->sysindex;
483
name[5] = IFDATA_LINKSPECIFIC;
484
if (sysctl(name, nitems(name), NULL, &len, NULL, 0) == -1) {
485
syslog(LOG_WARNING, "sysctl linkmib estimate (%s): %m",
486
ifp->name);
487
if (ifp->specmib != NULL) {
488
ifp->specmib = NULL;
489
ifp->specmiblen = 0;
490
}
491
goto out;
492
}
493
if (len == 0) {
494
if (ifp->specmib != NULL) {
495
ifp->specmib = NULL;
496
ifp->specmiblen = 0;
497
}
498
goto out;
499
}
500
501
if (ifp->specmiblen != len) {
502
if ((newmib = realloc(ifp->specmib, len)) == NULL) {
503
ifp->specmib = NULL;
504
ifp->specmiblen = 0;
505
goto out;
506
}
507
ifp->specmib = newmib;
508
ifp->specmiblen = len;
509
}
510
if (sysctl(name, nitems(name), ifp->specmib, &len, NULL, 0) == -1) {
511
syslog(LOG_WARNING, "sysctl linkmib (%s): %m", ifp->name);
512
if (ifp->specmib != NULL) {
513
ifp->specmib = NULL;
514
ifp->specmiblen = 0;
515
}
516
}
517
518
out:
519
/*
520
* Find sysctl mib for net.ifdescr_maxlen (one time).
521
* kmib[0] == -1 at first call to mib_fetch_ifmib().
522
* Then kmib[0] > 0 if we found sysctl mib for net.ifdescr_maxlen.
523
* Else, kmib[0] == 0 (unexpected error from a kernel).
524
*/
525
if (kmib[0] < 0 &&
526
sysctlnametomib("net.ifdescr_maxlen", kmib, &kmiblen) < 0) {
527
kmib[0] = 0;
528
syslog(LOG_WARNING, "sysctlnametomib net.ifdescr_maxlen: %m");
529
}
530
531
/*
532
* Fetch net.ifdescr_maxlen value every time to catch up with changes.
533
*/
534
len = sizeof(alias_maxlen);
535
if (kmib[0] > 0 && sysctl(kmib, 2, &alias_maxlen, &len, NULL, 0) < 0) {
536
/* unexpected error from the kernel, use default value */
537
alias_maxlen = MIBIF_ALIAS_SIZE_MAX;
538
syslog(LOG_WARNING, "sysctl net.ifdescr_maxlen: %m");
539
}
540
541
/*
542
* Kernel limit might be decreased after interfaces got
543
* their descriptions assigned. Try to obtain them anyway.
544
*/
545
if (alias_maxlen == 0)
546
alias_maxlen = MIBIF_ALIAS_SIZE_MAX;
547
548
/*
549
* Allocate maximum memory for a buffer and later reallocate
550
* to free extra memory.
551
*/
552
if ((ifp->alias = malloc(alias_maxlen)) == NULL) {
553
syslog(LOG_WARNING, "malloc(%d) failed: %m", (int)alias_maxlen);
554
goto fin;
555
}
556
557
strlcpy(irr.ifr_name, ifp->name, sizeof(irr.ifr_name));
558
irr.ifr_buffer.buffer = ifp->alias;
559
irr.ifr_buffer.length = alias_maxlen;
560
if (ioctl(mib_netsock, SIOCGIFDESCR, &irr) == -1) {
561
free(ifp->alias);
562
ifp->alias = NULL;
563
if (errno != ENOMSG)
564
syslog(LOG_WARNING, "SIOCGIFDESCR (%s): %m", ifp->name);
565
} else if (irr.ifr_buffer.buffer == NULL) {
566
free(ifp->alias);
567
ifp->alias = NULL;
568
syslog(LOG_WARNING, "SIOCGIFDESCR (%s): too long (%zu)",
569
ifp->name, irr.ifr_buffer.length);
570
} else {
571
ifp->alias_size = strnlen(ifp->alias, alias_maxlen) + 1;
572
573
if (ifp->alias_size > MIBIF_ALIAS_SIZE)
574
ifp->alias_size = MIBIF_ALIAS_SIZE;
575
576
if (ifp->alias_size < alias_maxlen)
577
ifp->alias = realloc(ifp->alias, ifp->alias_size);
578
}
579
580
fin:
581
ifp->mibtick = get_ticks();
582
return (0);
583
}
584
585
/* find first/next address for a given interface */
586
struct mibifa *
587
mib_first_ififa(const struct mibif *ifp)
588
{
589
struct mibifa *ifa;
590
591
TAILQ_FOREACH(ifa, &mibifa_list, link)
592
if (ifp->index == ifa->ifindex)
593
return (ifa);
594
return (NULL);
595
}
596
597
struct mibifa *
598
mib_next_ififa(struct mibifa *ifa0)
599
{
600
struct mibifa *ifa;
601
602
ifa = ifa0;
603
while ((ifa = TAILQ_NEXT(ifa, link)) != NULL)
604
if (ifa->ifindex == ifa0->ifindex)
605
return (ifa);
606
return (NULL);
607
}
608
609
/*
610
* Allocate a new IFA
611
*/
612
static struct mibifa *
613
alloc_ifa(u_int ifindex, struct in_addr addr)
614
{
615
struct mibifa *ifa;
616
uint32_t ha;
617
618
if ((ifa = malloc(sizeof(struct mibifa))) == NULL) {
619
syslog(LOG_ERR, "ifa: %m");
620
return (NULL);
621
}
622
ifa->inaddr = addr;
623
ifa->ifindex = ifindex;
624
625
ha = ntohl(ifa->inaddr.s_addr);
626
ifa->index.len = 4;
627
ifa->index.subs[0] = (ha >> 24) & 0xff;
628
ifa->index.subs[1] = (ha >> 16) & 0xff;
629
ifa->index.subs[2] = (ha >> 8) & 0xff;
630
ifa->index.subs[3] = (ha >> 0) & 0xff;
631
632
ifa->flags = 0;
633
ifa->inbcast.s_addr = 0;
634
ifa->inmask.s_addr = 0xffffffff;
635
636
INSERT_OBJECT_OID(ifa, &mibifa_list);
637
638
return (ifa);
639
}
640
641
/*
642
* Delete an interface address
643
*/
644
static void
645
destroy_ifa(struct mibifa *ifa)
646
{
647
TAILQ_REMOVE(&mibifa_list, ifa, link);
648
free(ifa);
649
}
650
651
652
/*
653
* Helper routine to extract the sockaddr structures from a routing
654
* socket message.
655
*/
656
void
657
mib_extract_addrs(int addrs, u_char *info, struct sockaddr **out)
658
{
659
u_int i;
660
661
for (i = 0; i < RTAX_MAX; i++) {
662
if ((addrs & (1 << i)) != 0) {
663
*out = (struct sockaddr *)(void *)info;
664
info += roundup((*out)->sa_len, sizeof(long));
665
} else
666
*out = NULL;
667
out++;
668
}
669
}
670
671
/*
672
* save the phys address of an interface. Handle receive address entries here.
673
*/
674
static void
675
get_physaddr(struct mibif *ifp, struct sockaddr_dl *sdl, u_char *ptr)
676
{
677
u_char *np;
678
struct mibrcvaddr *rcv;
679
680
if (sdl->sdl_alen == 0) {
681
/* no address */
682
if (ifp->physaddrlen != 0) {
683
if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr,
684
ifp->physaddrlen)) != NULL)
685
mib_rcvaddr_delete(rcv);
686
free(ifp->physaddr);
687
ifp->physaddr = NULL;
688
ifp->physaddrlen = 0;
689
}
690
return;
691
}
692
693
if (ifp->physaddrlen != sdl->sdl_alen) {
694
/* length changed */
695
if (ifp->physaddrlen) {
696
/* delete olf receive address */
697
if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr,
698
ifp->physaddrlen)) != NULL)
699
mib_rcvaddr_delete(rcv);
700
}
701
if ((np = realloc(ifp->physaddr, sdl->sdl_alen)) == NULL) {
702
free(ifp->physaddr);
703
ifp->physaddr = NULL;
704
ifp->physaddrlen = 0;
705
return;
706
}
707
ifp->physaddr = np;
708
ifp->physaddrlen = sdl->sdl_alen;
709
710
} else if (memcmp(ifp->physaddr, ptr, ifp->physaddrlen) == 0) {
711
/* no change */
712
return;
713
714
} else {
715
/* address changed */
716
717
/* delete olf receive address */
718
if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr,
719
ifp->physaddrlen)) != NULL)
720
mib_rcvaddr_delete(rcv);
721
}
722
723
memcpy(ifp->physaddr, ptr, ifp->physaddrlen);
724
725
/* make new receive address */
726
if ((rcv = mib_rcvaddr_create(ifp, ifp->physaddr, ifp->physaddrlen)) != NULL)
727
rcv->flags |= MIBRCVADDR_HW;
728
}
729
730
/*
731
* Free an interface
732
*/
733
static void
734
mibif_free(struct mibif *ifp)
735
{
736
struct mibif *ifp1;
737
struct mibindexmap *map;
738
struct mibifa *ifa, *ifa1;
739
struct mibrcvaddr *rcv, *rcv1;
740
struct mibarp *at, *at1;
741
742
if (ifp->xnotify != NULL)
743
(*ifp->xnotify)(ifp, MIBIF_NOTIFY_DESTROY, ifp->xnotify_data);
744
745
(void)mib_ifstack_delete(ifp, NULL);
746
(void)mib_ifstack_delete(NULL, ifp);
747
748
TAILQ_REMOVE(&mibif_list, ifp, link);
749
750
/* if this was the fastest interface - recompute this */
751
if (ifp->mib.ifmd_data.ifi_baudrate == mibif_maxspeed) {
752
mibif_maxspeed = ifp->mib.ifmd_data.ifi_baudrate;
753
TAILQ_FOREACH(ifp1, &mibif_list, link)
754
if (ifp1->mib.ifmd_data.ifi_baudrate > mibif_maxspeed)
755
mibif_maxspeed =
756
ifp1->mib.ifmd_data.ifi_baudrate;
757
mibif_reset_hc_timer();
758
}
759
760
if (ifp->alias != NULL) {
761
free(ifp->alias);
762
ifp->alias = NULL;
763
}
764
free(ifp->private);
765
ifp->private = NULL;
766
free(ifp->physaddr);
767
ifp->physaddr = NULL;
768
free(ifp->specmib);
769
ifp->specmib = NULL;
770
771
STAILQ_FOREACH(map, &mibindexmap_list, link)
772
if (map->mibif == ifp) {
773
map->mibif = NULL;
774
break;
775
}
776
777
/* purge interface addresses */
778
ifa = TAILQ_FIRST(&mibifa_list);
779
while (ifa != NULL) {
780
ifa1 = TAILQ_NEXT(ifa, link);
781
if (ifa->ifindex == ifp->index)
782
destroy_ifa(ifa);
783
ifa = ifa1;
784
}
785
786
/* purge receive addresses */
787
rcv = TAILQ_FIRST(&mibrcvaddr_list);
788
while (rcv != NULL) {
789
rcv1 = TAILQ_NEXT(rcv, link);
790
if (rcv->ifindex == ifp->index)
791
mib_rcvaddr_delete(rcv);
792
rcv = rcv1;
793
}
794
795
/* purge ARP entries */
796
at = TAILQ_FIRST(&mibarp_list);
797
while (at != NULL) {
798
at1 = TAILQ_NEXT(at, link);
799
if (at->index.subs[0] == ifp->index)
800
mib_arp_delete(at);
801
at = at1;
802
}
803
804
free(ifp);
805
ifp = NULL;
806
mib_if_number--;
807
mib_iftable_last_change = this_tick;
808
}
809
810
/*
811
* Create a new interface
812
*/
813
static struct mibif *
814
mibif_create(u_int sysindex, const char *name)
815
{
816
struct mibif *ifp;
817
struct mibindexmap *map;
818
819
if ((ifp = malloc(sizeof(*ifp))) == NULL) {
820
syslog(LOG_WARNING, "%s: %m", __func__);
821
return (NULL);
822
}
823
memset(ifp, 0, sizeof(*ifp));
824
if ((ifp->private = malloc(sizeof(struct mibif_private))) == NULL) {
825
syslog(LOG_WARNING, "%s: %m", __func__);
826
free(ifp);
827
return (NULL);
828
}
829
memset(ifp->private, 0, sizeof(struct mibif_private));
830
831
ifp->sysindex = sysindex;
832
strlcpy(ifp->name, name, sizeof(ifp->name));
833
strlcpy(ifp->descr, name, sizeof(ifp->descr));
834
ifp->spec_oid = oid_zeroDotZero;
835
836
map = NULL;
837
if (!mib_if_is_dyn(ifp->name)) {
838
/* non-dynamic. look whether we know the interface */
839
STAILQ_FOREACH(map, &mibindexmap_list, link)
840
if (strcmp(map->name, ifp->name) == 0) {
841
ifp->index = map->ifindex;
842
map->mibif = ifp;
843
break;
844
}
845
/* assume it has a connector if it is not dynamic */
846
ifp->has_connector = 1;
847
ifp->trap_enable = 1;
848
}
849
if (map == NULL) {
850
/* new interface - get new index */
851
if (next_if_index > 0x7fffffff)
852
errx(1, "ifindex wrap");
853
854
if ((map = malloc(sizeof(*map))) == NULL) {
855
syslog(LOG_ERR, "ifmap: %m");
856
free(ifp);
857
return (NULL);
858
}
859
map->ifindex = next_if_index++;
860
map->sysindex = ifp->sysindex;
861
strcpy(map->name, ifp->name);
862
map->mibif = ifp;
863
STAILQ_INSERT_TAIL(&mibindexmap_list, map, link);
864
} else {
865
/* re-instantiate. Introduce a counter discontinuity */
866
ifp->counter_disc = get_ticks();
867
}
868
ifp->index = map->ifindex;
869
ifp->mib.ifmd_data.ifi_link_state = LINK_STATE_UNKNOWN;
870
871
INSERT_OBJECT_INT(ifp, &mibif_list);
872
mib_if_number++;
873
mib_iftable_last_change = this_tick;
874
875
/* instantiate default ifStack entries */
876
(void)mib_ifstack_create(ifp, NULL);
877
(void)mib_ifstack_create(NULL, ifp);
878
879
return (ifp);
880
}
881
882
/*
883
* Inform all interested parties about a new interface
884
*/
885
static void
886
notify_newif(struct mibif *ifp)
887
{
888
struct newifreg *reg;
889
890
TAILQ_FOREACH(reg, &newifreg_list, link)
891
if ((*reg->func)(ifp))
892
return;
893
}
894
895
/*
896
* This is called for new interfaces after we have fetched the interface
897
* MIB. If this is a broadcast interface try to guess the broadcast address
898
* depending on the interface type.
899
*/
900
static void
901
check_llbcast(struct mibif *ifp)
902
{
903
static u_char ether_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
904
struct mibrcvaddr *rcv;
905
906
if (!(ifp->mib.ifmd_flags & IFF_BROADCAST))
907
return;
908
909
switch (ifp->mib.ifmd_data.ifi_type) {
910
911
case IFT_ETHER:
912
case IFT_FDDI:
913
case IFT_ISO88025:
914
case IFT_L2VLAN:
915
if (mib_find_rcvaddr(ifp->index, ether_bcast, 6) == NULL &&
916
(rcv = mib_rcvaddr_create(ifp, ether_bcast, 6)) != NULL)
917
rcv->flags |= MIBRCVADDR_BCAST;
918
break;
919
}
920
}
921
922
923
/*
924
* Retrieve the current interface list from the system.
925
*/
926
void
927
mib_refresh_iflist(void)
928
{
929
struct mibif *ifp, *ifp1;
930
size_t len;
931
u_short idx;
932
int name[6];
933
int count;
934
struct ifmibdata mib;
935
936
TAILQ_FOREACH(ifp, &mibif_list, link)
937
ifp->flags &= ~MIBIF_FOUND;
938
939
len = sizeof(count);
940
if (sysctlbyname("net.link.generic.system.ifcount", &count, &len,
941
NULL, 0) == -1) {
942
syslog(LOG_ERR, "ifcount: %m");
943
return;
944
}
945
name[0] = CTL_NET;
946
name[1] = PF_LINK;
947
name[2] = NETLINK_GENERIC;
948
name[3] = IFMIB_IFDATA;
949
name[5] = IFDATA_GENERAL;
950
for (idx = 1; idx <= count; idx++) {
951
name[4] = idx;
952
len = sizeof(mib);
953
if (sysctl(name, nitems(name), &mib, &len, NULL, 0) == -1) {
954
if (errno == ENOENT)
955
continue;
956
syslog(LOG_ERR, "ifmib(%u): %m", idx);
957
return;
958
}
959
if ((ifp = mib_find_if_sys(idx)) != NULL) {
960
ifp->flags |= MIBIF_FOUND;
961
continue;
962
}
963
/* Unknown interface - create */
964
if ((ifp = mibif_create(idx, mib.ifmd_name)) != NULL) {
965
ifp->flags |= MIBIF_FOUND;
966
(void)mib_fetch_ifmib(ifp);
967
check_llbcast(ifp);
968
notify_newif(ifp);
969
}
970
}
971
972
/*
973
* Purge interfaces that disappeared
974
*/
975
ifp = TAILQ_FIRST(&mibif_list);
976
while (ifp != NULL) {
977
ifp1 = TAILQ_NEXT(ifp, link);
978
if (!(ifp->flags & MIBIF_FOUND))
979
mibif_free(ifp);
980
ifp = ifp1;
981
}
982
}
983
984
/*
985
* Find an interface address
986
*/
987
struct mibifa *
988
mib_find_ifa(struct in_addr addr)
989
{
990
struct mibifa *ifa;
991
992
TAILQ_FOREACH(ifa, &mibifa_list, link)
993
if (ifa->inaddr.s_addr == addr.s_addr)
994
return (ifa);
995
return (NULL);
996
}
997
998
/*
999
* Process a new ARP entry
1000
*/
1001
static void
1002
process_arp(const struct rt_msghdr *rtm, const struct sockaddr_dl *sdl,
1003
const struct sockaddr_in *sa)
1004
{
1005
struct mibif *ifp;
1006
struct mibarp *at;
1007
1008
/* IP arp table entry */
1009
if (sdl->sdl_alen == 0)
1010
return;
1011
if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL)
1012
return;
1013
/* have a valid entry */
1014
if ((at = mib_find_arp(ifp, sa->sin_addr)) == NULL &&
1015
(at = mib_arp_create(ifp, sa->sin_addr,
1016
sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL)
1017
return;
1018
1019
if (rtm->rtm_rmx.rmx_expire == 0)
1020
at->flags |= MIBARP_PERM;
1021
else
1022
at->flags &= ~MIBARP_PERM;
1023
at->flags |= MIBARP_FOUND;
1024
}
1025
1026
/*
1027
* Handle a routing socket message.
1028
*/
1029
static void
1030
handle_rtmsg(struct rt_msghdr *rtm)
1031
{
1032
struct sockaddr *addrs[RTAX_MAX];
1033
struct if_msghdr *ifm;
1034
struct ifa_msghdr ifam, *ifamp;
1035
struct ifma_msghdr *ifmam;
1036
#ifdef RTM_IFANNOUNCE
1037
struct if_announcemsghdr *ifan;
1038
#endif
1039
struct mibif *ifp;
1040
struct sockaddr_dl *sdl;
1041
struct sockaddr_in *sa;
1042
struct mibifa *ifa;
1043
struct mibrcvaddr *rcv;
1044
u_char *ptr;
1045
1046
if (rtm->rtm_version != RTM_VERSION) {
1047
syslog(LOG_ERR, "Bogus RTM version %u", rtm->rtm_version);
1048
return;
1049
}
1050
1051
switch (rtm->rtm_type) {
1052
1053
case RTM_NEWADDR:
1054
ifamp = (struct ifa_msghdr *)rtm;
1055
memcpy(&ifam, ifamp, sizeof(ifam));
1056
mib_extract_addrs(ifam.ifam_addrs, (u_char *)(ifamp + 1), addrs);
1057
if (addrs[RTAX_IFA] == NULL || addrs[RTAX_NETMASK] == NULL)
1058
break;
1059
1060
sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA];
1061
if ((ifa = mib_find_ifa(sa->sin_addr)) == NULL) {
1062
/* unknown address */
1063
if ((ifp = mib_find_if_sys(ifam.ifam_index)) == NULL) {
1064
syslog(LOG_WARNING, "RTM_NEWADDR for unknown "
1065
"interface %u", ifam.ifam_index);
1066
break;
1067
}
1068
if ((ifa = alloc_ifa(ifp->index, sa->sin_addr)) == NULL)
1069
break;
1070
}
1071
sa = (struct sockaddr_in *)(void *)addrs[RTAX_NETMASK];
1072
ifa->inmask = sa->sin_addr;
1073
1074
if (addrs[RTAX_BRD] != NULL) {
1075
sa = (struct sockaddr_in *)(void *)addrs[RTAX_BRD];
1076
ifa->inbcast = sa->sin_addr;
1077
}
1078
ifa->flags |= MIBIFA_FOUND;
1079
break;
1080
1081
case RTM_DELADDR:
1082
ifamp = (struct ifa_msghdr *)rtm;
1083
memcpy(&ifam, ifamp, sizeof(ifam));
1084
mib_extract_addrs(ifam.ifam_addrs, (u_char *)(ifamp + 1), addrs);
1085
if (addrs[RTAX_IFA] == NULL)
1086
break;
1087
1088
sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA];
1089
if ((ifa = mib_find_ifa(sa->sin_addr)) != NULL) {
1090
ifa->flags |= MIBIFA_FOUND;
1091
if (!(ifa->flags & MIBIFA_DESTROYED))
1092
destroy_ifa(ifa);
1093
}
1094
break;
1095
1096
case RTM_NEWMADDR:
1097
ifmam = (struct ifma_msghdr *)rtm;
1098
mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs);
1099
if (addrs[RTAX_IFA] == NULL ||
1100
addrs[RTAX_IFA]->sa_family != AF_LINK)
1101
break;
1102
sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA];
1103
if ((rcv = mib_find_rcvaddr(sdl->sdl_index,
1104
sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) {
1105
/* unknown address */
1106
if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL) {
1107
syslog(LOG_WARNING, "RTM_NEWMADDR for unknown "
1108
"interface %u", sdl->sdl_index);
1109
break;
1110
}
1111
if ((rcv = mib_rcvaddr_create(ifp,
1112
sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL)
1113
break;
1114
rcv->flags |= MIBRCVADDR_VOLATILE;
1115
}
1116
rcv->flags |= MIBRCVADDR_FOUND;
1117
break;
1118
1119
case RTM_DELMADDR:
1120
ifmam = (struct ifma_msghdr *)rtm;
1121
mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs);
1122
if (addrs[RTAX_IFA] == NULL ||
1123
addrs[RTAX_IFA]->sa_family != AF_LINK)
1124
break;
1125
sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA];
1126
if ((rcv = mib_find_rcvaddr(sdl->sdl_index,
1127
sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) != NULL)
1128
mib_rcvaddr_delete(rcv);
1129
break;
1130
1131
case RTM_IFINFO:
1132
ifm = (struct if_msghdr *)(void *)rtm;
1133
mib_extract_addrs(ifm->ifm_addrs, (u_char *)(ifm + 1), addrs);
1134
if ((ifp = mib_find_if_sys(ifm->ifm_index)) == NULL)
1135
break;
1136
if (addrs[RTAX_IFP] != NULL &&
1137
addrs[RTAX_IFP]->sa_family == AF_LINK) {
1138
sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFP];
1139
ptr = sdl->sdl_data + sdl->sdl_nlen;
1140
get_physaddr(ifp, sdl, ptr);
1141
}
1142
(void)mib_fetch_ifmib(ifp);
1143
break;
1144
1145
#ifdef RTM_IFANNOUNCE
1146
case RTM_IFANNOUNCE:
1147
ifan = (struct if_announcemsghdr *)rtm;
1148
ifp = mib_find_if_sys(ifan->ifan_index);
1149
1150
switch (ifan->ifan_what) {
1151
1152
case IFAN_ARRIVAL:
1153
if (ifp == NULL && (ifp = mibif_create(ifan->ifan_index,
1154
ifan->ifan_name)) != NULL) {
1155
(void)mib_fetch_ifmib(ifp);
1156
check_llbcast(ifp);
1157
notify_newif(ifp);
1158
}
1159
break;
1160
1161
case IFAN_DEPARTURE:
1162
if (ifp != NULL)
1163
mibif_free(ifp);
1164
break;
1165
}
1166
break;
1167
#endif
1168
case RTM_GET:
1169
case RTM_ADD:
1170
mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs);
1171
if (rtm->rtm_flags & RTF_LLINFO) {
1172
if (addrs[RTAX_DST] == NULL ||
1173
addrs[RTAX_GATEWAY] == NULL ||
1174
addrs[RTAX_DST]->sa_family != AF_INET ||
1175
addrs[RTAX_GATEWAY]->sa_family != AF_LINK)
1176
break;
1177
process_arp(rtm,
1178
(struct sockaddr_dl *)(void *)addrs[RTAX_GATEWAY],
1179
(struct sockaddr_in *)(void *)addrs[RTAX_DST]);
1180
} else {
1181
if (rtm->rtm_errno == 0 && (rtm->rtm_flags & RTF_UP))
1182
mib_sroute_process(rtm, addrs[RTAX_GATEWAY],
1183
addrs[RTAX_DST], addrs[RTAX_NETMASK]);
1184
}
1185
break;
1186
1187
case RTM_DELETE:
1188
mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs);
1189
1190
if (rtm->rtm_errno == 0 && (rtm->rtm_flags & RTF_UP))
1191
mib_sroute_process(rtm, addrs[RTAX_GATEWAY],
1192
addrs[RTAX_DST], addrs[RTAX_NETMASK]);
1193
break;
1194
}
1195
}
1196
1197
/*
1198
* send a routing message
1199
*/
1200
void
1201
mib_send_rtmsg(struct rt_msghdr *rtm, struct sockaddr *gw,
1202
struct sockaddr *dst, struct sockaddr *mask)
1203
{
1204
size_t len;
1205
struct rt_msghdr *msg;
1206
char *cp;
1207
ssize_t sent;
1208
1209
len = sizeof(*rtm) + SA_SIZE(gw) + SA_SIZE(dst) + SA_SIZE(mask);
1210
if ((msg = malloc(len)) == NULL) {
1211
syslog(LOG_ERR, "%s: %m", __func__);
1212
return;
1213
}
1214
cp = (char *)(msg + 1);
1215
1216
memset(msg, 0, sizeof(*msg));
1217
msg->rtm_flags = 0;
1218
msg->rtm_version = RTM_VERSION;
1219
msg->rtm_addrs = RTA_DST | RTA_GATEWAY;
1220
1221
memcpy(cp, dst, SA_SIZE(dst));
1222
cp += SA_SIZE(dst);
1223
memcpy(cp, gw, SA_SIZE(gw));
1224
cp += SA_SIZE(gw);
1225
if (mask != NULL) {
1226
memcpy(cp, mask, SA_SIZE(mask));
1227
cp += SA_SIZE(mask);
1228
msg->rtm_addrs |= RTA_NETMASK;
1229
}
1230
msg->rtm_msglen = cp - (char *)msg;
1231
msg->rtm_type = RTM_GET;
1232
if ((sent = write(route, msg, msg->rtm_msglen)) == -1) {
1233
syslog(LOG_ERR, "%s: write: %m", __func__);
1234
free(msg);
1235
return;
1236
}
1237
if (sent != msg->rtm_msglen) {
1238
syslog(LOG_ERR, "%s: short write", __func__);
1239
free(msg);
1240
return;
1241
}
1242
free(msg);
1243
}
1244
1245
/*
1246
* Fetch the routing table via sysctl
1247
*/
1248
u_char *
1249
mib_fetch_rtab(int af, int info, int arg, size_t *lenp)
1250
{
1251
int name[6];
1252
u_char *buf, *newbuf;
1253
1254
name[0] = CTL_NET;
1255
name[1] = PF_ROUTE;
1256
name[2] = 0;
1257
name[3] = af;
1258
name[4] = info;
1259
name[5] = arg;
1260
1261
*lenp = 0;
1262
1263
/* initial estimate */
1264
if (sysctl(name, nitems(name), NULL, lenp, NULL, 0) == -1) {
1265
syslog(LOG_ERR, "sysctl estimate (%d,%d,%d,%d,%d,%d): %m",
1266
name[0], name[1], name[2], name[3], name[4], name[5]);
1267
return (NULL);
1268
}
1269
if (*lenp == 0)
1270
return (NULL);
1271
1272
buf = NULL;
1273
for (;;) {
1274
if ((newbuf = realloc(buf, *lenp)) == NULL) {
1275
syslog(LOG_ERR, "sysctl buffer: %m");
1276
free(buf);
1277
return (NULL);
1278
}
1279
buf = newbuf;
1280
1281
if (sysctl(name, nitems(name), buf, lenp, NULL, 0) == 0)
1282
break;
1283
1284
if (errno != ENOMEM) {
1285
syslog(LOG_ERR, "sysctl get: %m");
1286
free(buf);
1287
return (NULL);
1288
}
1289
*lenp += *lenp / 8 + 1;
1290
}
1291
1292
return (buf);
1293
}
1294
1295
/*
1296
* Update the following info: interface, interface addresses, interface
1297
* receive addresses, arp-table.
1298
* This does not change the interface list itself.
1299
*/
1300
static void
1301
update_ifa_info(void)
1302
{
1303
u_char *buf, *next;
1304
struct rt_msghdr *rtm;
1305
struct mibifa *ifa, *ifa1;
1306
struct mibrcvaddr *rcv, *rcv1;
1307
size_t needed;
1308
static const int infos[][3] = {
1309
{ 0, NET_RT_IFLIST, 0 },
1310
#ifdef NET_RT_IFMALIST
1311
{ AF_LINK, NET_RT_IFMALIST, 0 },
1312
#endif
1313
};
1314
u_int i;
1315
1316
TAILQ_FOREACH(ifa, &mibifa_list, link)
1317
ifa->flags &= ~MIBIFA_FOUND;
1318
TAILQ_FOREACH(rcv, &mibrcvaddr_list, link)
1319
rcv->flags &= ~MIBRCVADDR_FOUND;
1320
1321
for (i = 0; i < sizeof(infos) / sizeof(infos[0]); i++) {
1322
if ((buf = mib_fetch_rtab(infos[i][0], infos[i][1], infos[i][2],
1323
&needed)) == NULL)
1324
continue;
1325
1326
next = buf;
1327
while (next < buf + needed) {
1328
rtm = (struct rt_msghdr *)(void *)next;
1329
next += rtm->rtm_msglen;
1330
handle_rtmsg(rtm);
1331
}
1332
free(buf);
1333
}
1334
1335
/*
1336
* Purge the address list of unused entries. These may happen for
1337
* interface aliases that are on the same subnet. We don't receive
1338
* routing socket messages for them.
1339
*/
1340
ifa = TAILQ_FIRST(&mibifa_list);
1341
while (ifa != NULL) {
1342
ifa1 = TAILQ_NEXT(ifa, link);
1343
if (!(ifa->flags & MIBIFA_FOUND))
1344
destroy_ifa(ifa);
1345
ifa = ifa1;
1346
}
1347
1348
rcv = TAILQ_FIRST(&mibrcvaddr_list);
1349
while (rcv != NULL) {
1350
rcv1 = TAILQ_NEXT(rcv, link);
1351
if (!(rcv->flags & (MIBRCVADDR_FOUND | MIBRCVADDR_BCAST |
1352
MIBRCVADDR_HW)))
1353
mib_rcvaddr_delete(rcv);
1354
rcv = rcv1;
1355
}
1356
}
1357
1358
/*
1359
* Update arp table
1360
*/
1361
void
1362
mib_arp_update(void)
1363
{
1364
struct mibarp *at, *at1;
1365
size_t needed;
1366
u_char *buf, *next;
1367
struct rt_msghdr *rtm;
1368
1369
if (in_update_arp)
1370
return; /* Aaargh */
1371
in_update_arp = 1;
1372
1373
TAILQ_FOREACH(at, &mibarp_list, link)
1374
at->flags &= ~MIBARP_FOUND;
1375
1376
if ((buf = mib_fetch_rtab(AF_INET, NET_RT_FLAGS, 0, &needed)) == NULL) {
1377
in_update_arp = 0;
1378
return;
1379
}
1380
1381
next = buf;
1382
while (next < buf + needed) {
1383
rtm = (struct rt_msghdr *)(void *)next;
1384
next += rtm->rtm_msglen;
1385
handle_rtmsg(rtm);
1386
}
1387
free(buf);
1388
1389
at = TAILQ_FIRST(&mibarp_list);
1390
while (at != NULL) {
1391
at1 = TAILQ_NEXT(at, link);
1392
if (!(at->flags & MIBARP_FOUND))
1393
mib_arp_delete(at);
1394
at = at1;
1395
}
1396
mibarpticks = get_ticks();
1397
in_update_arp = 0;
1398
}
1399
1400
1401
/*
1402
* Input on the routing socket.
1403
*/
1404
static void
1405
route_input(int fd, void *udata __unused)
1406
{
1407
u_char buf[1024 * 16];
1408
ssize_t n;
1409
struct rt_msghdr *rtm;
1410
1411
if ((n = read(fd, buf, sizeof(buf))) == -1)
1412
err(1, "read(rt_socket)");
1413
1414
if (n == 0)
1415
errx(1, "EOF on rt_socket");
1416
1417
rtm = (struct rt_msghdr *)(void *)buf;
1418
if ((size_t)n != rtm->rtm_msglen)
1419
errx(1, "n=%zu, rtm_msglen=%u", (size_t)n, rtm->rtm_msglen);
1420
1421
handle_rtmsg(rtm);
1422
}
1423
1424
/*
1425
* execute and SIOCAIFADDR
1426
*/
1427
static int
1428
siocaifaddr(char *ifname, struct in_addr addr, struct in_addr mask,
1429
struct in_addr bcast)
1430
{
1431
struct ifaliasreq addreq;
1432
struct sockaddr_in *sa;
1433
1434
memset(&addreq, 0, sizeof(addreq));
1435
strlcpy(addreq.ifra_name, ifname, sizeof(addreq.ifra_name));
1436
1437
sa = (struct sockaddr_in *)(void *)&addreq.ifra_addr;
1438
sa->sin_family = AF_INET;
1439
sa->sin_len = sizeof(*sa);
1440
sa->sin_addr = addr;
1441
1442
sa = (struct sockaddr_in *)(void *)&addreq.ifra_mask;
1443
sa->sin_family = AF_INET;
1444
sa->sin_len = sizeof(*sa);
1445
sa->sin_addr = mask;
1446
1447
sa = (struct sockaddr_in *)(void *)&addreq.ifra_broadaddr;
1448
sa->sin_family = AF_INET;
1449
sa->sin_len = sizeof(*sa);
1450
sa->sin_addr = bcast;
1451
1452
return (ioctl(mib_netsock, SIOCAIFADDR, &addreq));
1453
}
1454
1455
/*
1456
* Exececute a SIOCDIFADDR
1457
*/
1458
static int
1459
siocdifaddr(const char *ifname, struct in_addr addr)
1460
{
1461
struct ifreq delreq;
1462
struct sockaddr_in *sa;
1463
1464
memset(&delreq, 0, sizeof(delreq));
1465
strlcpy(delreq.ifr_name, ifname, sizeof(delreq.ifr_name));
1466
sa = (struct sockaddr_in *)(void *)&delreq.ifr_addr;
1467
sa->sin_family = AF_INET;
1468
sa->sin_len = sizeof(*sa);
1469
sa->sin_addr = addr;
1470
1471
return (ioctl(mib_netsock, SIOCDIFADDR, &delreq));
1472
}
1473
1474
/*
1475
* Verify an interface address without fetching the entire list
1476
*/
1477
static int
1478
verify_ifa(const char *name, struct mibifa *ifa)
1479
{
1480
struct ifreq req;
1481
struct sockaddr_in *sa;
1482
1483
memset(&req, 0, sizeof(req));
1484
strlcpy(req.ifr_name, name, sizeof(req.ifr_name));
1485
sa = (struct sockaddr_in *)(void *)&req.ifr_addr;
1486
sa->sin_family = AF_INET;
1487
sa->sin_len = sizeof(*sa);
1488
sa->sin_addr = ifa->inaddr;
1489
1490
if (ioctl(mib_netsock, SIOCGIFADDR, &req) == -1)
1491
return (-1);
1492
if (ifa->inaddr.s_addr != sa->sin_addr.s_addr) {
1493
syslog(LOG_ERR, "%s: address mismatch", __func__);
1494
return (-1);
1495
}
1496
1497
if (ioctl(mib_netsock, SIOCGIFNETMASK, &req) == -1)
1498
return (-1);
1499
if (ifa->inmask.s_addr != sa->sin_addr.s_addr) {
1500
syslog(LOG_ERR, "%s: netmask mismatch", __func__);
1501
return (-1);
1502
}
1503
return (0);
1504
}
1505
1506
/*
1507
* Restore a deleted interface address. Don't wait for the routing socket
1508
* to update us.
1509
*/
1510
void
1511
mib_undestroy_ifa(struct mibifa *ifa)
1512
{
1513
struct mibif *ifp;
1514
1515
if ((ifp = mib_find_if(ifa->ifindex)) == NULL)
1516
/* keep it destroyed */
1517
return;
1518
1519
if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast))
1520
/* keep it destroyed */
1521
return;
1522
1523
ifa->flags &= ~MIBIFA_DESTROYED;
1524
}
1525
1526
/*
1527
* Destroy an interface address
1528
*/
1529
int
1530
mib_destroy_ifa(struct mibifa *ifa)
1531
{
1532
struct mibif *ifp;
1533
1534
if ((ifp = mib_find_if(ifa->ifindex)) == NULL) {
1535
/* ups. */
1536
mib_iflist_bad = 1;
1537
return (-1);
1538
}
1539
if (siocdifaddr(ifp->name, ifa->inaddr)) {
1540
/* ups. */
1541
syslog(LOG_ERR, "SIOCDIFADDR: %m");
1542
mib_iflist_bad = 1;
1543
return (-1);
1544
}
1545
ifa->flags |= MIBIFA_DESTROYED;
1546
return (0);
1547
}
1548
1549
/*
1550
* Rollback the modification of an address. Don't bother to wait for
1551
* the routing socket.
1552
*/
1553
void
1554
mib_unmodify_ifa(struct mibifa *ifa)
1555
{
1556
struct mibif *ifp;
1557
1558
if ((ifp = mib_find_if(ifa->ifindex)) == NULL) {
1559
/* ups. */
1560
mib_iflist_bad = 1;
1561
return;
1562
}
1563
1564
if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) {
1565
/* ups. */
1566
mib_iflist_bad = 1;
1567
return;
1568
}
1569
}
1570
1571
/*
1572
* Modify an IFA.
1573
*/
1574
int
1575
mib_modify_ifa(struct mibifa *ifa)
1576
{
1577
struct mibif *ifp;
1578
1579
if ((ifp = mib_find_if(ifa->ifindex)) == NULL) {
1580
/* ups. */
1581
mib_iflist_bad = 1;
1582
return (-1);
1583
}
1584
1585
if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) {
1586
/* ups. */
1587
mib_iflist_bad = 1;
1588
return (-1);
1589
}
1590
1591
if (verify_ifa(ifp->name, ifa)) {
1592
/* ups. */
1593
mib_iflist_bad = 1;
1594
return (-1);
1595
}
1596
1597
return (0);
1598
}
1599
1600
/*
1601
* Destroy a freshly created interface address. Don't bother to wait for
1602
* the routing socket.
1603
*/
1604
void
1605
mib_uncreate_ifa(struct mibifa *ifa)
1606
{
1607
struct mibif *ifp;
1608
1609
if ((ifp = mib_find_if(ifa->ifindex)) == NULL) {
1610
/* ups. */
1611
mib_iflist_bad = 1;
1612
return;
1613
}
1614
if (siocdifaddr(ifp->name, ifa->inaddr)) {
1615
/* ups. */
1616
mib_iflist_bad = 1;
1617
return;
1618
}
1619
1620
destroy_ifa(ifa);
1621
}
1622
1623
/*
1624
* Create a new ifa and verify it
1625
*/
1626
struct mibifa *
1627
mib_create_ifa(u_int ifindex, struct in_addr addr, struct in_addr mask,
1628
struct in_addr bcast)
1629
{
1630
struct mibif *ifp;
1631
struct mibifa *ifa;
1632
1633
if ((ifp = mib_find_if(ifindex)) == NULL)
1634
return (NULL);
1635
if ((ifa = alloc_ifa(ifindex, addr)) == NULL)
1636
return (NULL);
1637
ifa->inmask = mask;
1638
ifa->inbcast = bcast;
1639
1640
if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) {
1641
syslog(LOG_ERR, "%s: %m", __func__);
1642
destroy_ifa(ifa);
1643
return (NULL);
1644
}
1645
if (verify_ifa(ifp->name, ifa)) {
1646
destroy_ifa(ifa);
1647
return (NULL);
1648
}
1649
return (ifa);
1650
}
1651
1652
/*
1653
* Get all cloning interfaces and make them dynamic.
1654
* Hah! Whe should probably do this on a periodic basis (XXX).
1655
*/
1656
static void
1657
get_cloners(void)
1658
{
1659
struct if_clonereq req;
1660
char *buf, *cp;
1661
int i;
1662
1663
memset(&req, 0, sizeof(req));
1664
if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) {
1665
syslog(LOG_ERR, "get cloners: %m");
1666
return;
1667
}
1668
if ((buf = malloc(req.ifcr_total * IFNAMSIZ)) == NULL) {
1669
syslog(LOG_ERR, "%m");
1670
return;
1671
}
1672
req.ifcr_count = req.ifcr_total;
1673
req.ifcr_buffer = buf;
1674
if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) {
1675
syslog(LOG_ERR, "get cloners: %m");
1676
free(buf);
1677
return;
1678
}
1679
for (cp = buf, i = 0; i < req.ifcr_total; i++, cp += IFNAMSIZ)
1680
mib_if_set_dyn(cp);
1681
free(buf);
1682
}
1683
1684
/*
1685
* Idle function
1686
*/
1687
static void
1688
mibII_idle(void *arg __unused)
1689
{
1690
struct mibifa *ifa;
1691
1692
if (mib_iflist_bad) {
1693
TAILQ_FOREACH(ifa, &mibifa_list, link)
1694
ifa->flags &= ~MIBIFA_DESTROYED;
1695
1696
/* assume, that all cloning interfaces are dynamic */
1697
get_cloners();
1698
1699
mib_refresh_iflist();
1700
update_ifa_info();
1701
mib_arp_update();
1702
mib_iflist_bad = 0;
1703
}
1704
1705
mib_arp_update();
1706
}
1707
1708
1709
/*
1710
* Start the module
1711
*/
1712
static void
1713
mibII_start(void)
1714
{
1715
if ((route_fd = fd_select(route, route_input, NULL, module)) == NULL) {
1716
syslog(LOG_ERR, "fd_select(route): %m");
1717
return;
1718
}
1719
mib_refresh_iflist();
1720
update_ifa_info();
1721
mib_arp_update();
1722
(void)mib_fetch_route();
1723
mib_iftable_last_change = 0;
1724
mib_ifstack_last_change = 0;
1725
1726
ifmib_reg = or_register(&oid_ifMIB,
1727
"The MIB module to describe generic objects for network interface"
1728
" sub-layers.", module);
1729
1730
ipmib_reg = or_register(&oid_ipMIB,
1731
"The MIB module for managing IP and ICMP implementations, but "
1732
"excluding their management of IP routes.", module);
1733
1734
tcpmib_reg = or_register(&oid_tcpMIB,
1735
"The MIB module for managing TCP implementations.", module);
1736
1737
udpmib_reg = or_register(&oid_udpMIB,
1738
"The MIB module for managing UDP implementations.", module);
1739
1740
ipForward_reg = or_register(&oid_ipForward,
1741
"The MIB module for the display of CIDR multipath IP Routes.",
1742
module);
1743
1744
mibII_poll_timer = NULL;
1745
mibII_poll_ticks = MIBII_POLL_TICKS;
1746
mibif_restart_mibII_poll_timer();
1747
}
1748
1749
/*
1750
* Initialize the module
1751
*/
1752
static int
1753
mibII_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
1754
{
1755
module = mod;
1756
1757
if ((route = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) == -1) {
1758
syslog(LOG_ERR, "PF_ROUTE: %m");
1759
return (-1);
1760
}
1761
1762
if ((mib_netsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
1763
syslog(LOG_ERR, "PF_INET: %m");
1764
(void)close(route);
1765
return (-1);
1766
}
1767
(void)shutdown(mib_netsock, SHUT_RDWR);
1768
1769
/* assume, that all cloning interfaces are dynamic */
1770
get_cloners();
1771
1772
return (0);
1773
}
1774
1775
static int
1776
mibII_fini(void)
1777
{
1778
if (mibII_poll_timer != NULL ) {
1779
timer_stop(mibII_poll_timer);
1780
mibII_poll_timer = NULL;
1781
}
1782
1783
if (route_fd != NULL)
1784
fd_deselect(route_fd);
1785
if (route != -1)
1786
(void)close(route);
1787
if (mib_netsock != -1)
1788
(void)close(mib_netsock);
1789
/* XXX free memory */
1790
1791
or_unregister(ipForward_reg);
1792
or_unregister(udpmib_reg);
1793
or_unregister(tcpmib_reg);
1794
or_unregister(ipmib_reg);
1795
or_unregister(ifmib_reg);
1796
1797
return (0);
1798
}
1799
1800
static void
1801
mibII_loading(const struct lmodule *mod, int loaded)
1802
{
1803
struct mibif *ifp;
1804
1805
if (loaded == 1)
1806
return;
1807
1808
TAILQ_FOREACH(ifp, &mibif_list, link)
1809
if (ifp->xnotify_mod == mod) {
1810
ifp->xnotify_mod = NULL;
1811
ifp->xnotify_data = NULL;
1812
ifp->xnotify = NULL;
1813
}
1814
1815
mib_unregister_newif(mod);
1816
}
1817
1818
extern const struct snmp_module config;
1819
const struct snmp_module config = {
1820
"This module implements the interface and ip groups.",
1821
mibII_init,
1822
mibII_fini,
1823
NULL, /* idle */
1824
NULL, /* dump */
1825
NULL, /* config */
1826
mibII_start,
1827
NULL,
1828
mibII_ctree,
1829
mibII_CTREE_SIZE,
1830
mibII_loading
1831
};
1832
1833
/*
1834
* Should have a list of these attached to each interface.
1835
*/
1836
void *
1837
mibif_notify(struct mibif *ifp, const struct lmodule *mod,
1838
mibif_notify_f func, void *data)
1839
{
1840
ifp->xnotify = func;
1841
ifp->xnotify_data = data;
1842
ifp->xnotify_mod = mod;
1843
1844
return (ifp);
1845
}
1846
1847
void
1848
mibif_unnotify(void *arg)
1849
{
1850
struct mibif *ifp = arg;
1851
1852
ifp->xnotify = NULL;
1853
ifp->xnotify_data = NULL;
1854
ifp->xnotify_mod = NULL;
1855
}
1856
1857