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