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: 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 /* info on system clocks */ 103 struct clockinfo clockinfo; 104 105 /* list of all New if registrations */ 106 static struct newifreg_list newifreg_list = TAILQ_HEAD_INITIALIZER(newifreg_list); 107 108 /* baud rate of fastest interface */ 109 uint64_t mibif_maxspeed; 110 111 /* user-forced update interval */ 112 u_int mibif_force_hc_update_interval; 113 114 /* current update interval */ 115 u_int mibif_hc_update_interval; 116 117 /* HC update timer handle */ 118 static void *hc_update_timer; 119 120 /*****************************/ 121 122 static const struct asn_oid oid_ifMIB = OIDX_ifMIB; 123 static const struct asn_oid oid_ipMIB = OIDX_ipMIB; 124 static const struct asn_oid oid_tcpMIB = OIDX_tcpMIB; 125 static const struct asn_oid oid_udpMIB = OIDX_udpMIB; 126 static const struct asn_oid oid_ipForward = OIDX_ipForward; 127 static const struct asn_oid oid_linkDown = OIDX_linkDown; 128 static const struct asn_oid oid_linkUp = OIDX_linkUp; 129 static const struct asn_oid oid_ifIndex = OIDX_ifIndex; 130 131 /*****************************/ 132 133 /* 134 * Find an interface 135 */ 136 struct mibif * 137 mib_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 147 struct mibif * 148 mib_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 158 struct mibif * 159 mib_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 */ 173 int 174 mib_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 */ 188 void 189 mib_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 */ 205 int 206 mib_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 226 void 227 mib_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 240 struct mibif * 241 mib_first_if(void) 242 { 243 return (TAILQ_FIRST(&mibif_list)); 244 } 245 struct mibif * 246 mib_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 */ 254 int 255 mib_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 */ 281 static void 282 link_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 295 /** 296 * Fetch the GENERIC IFMIB and update the HC counters 297 */ 298 static int 299 fetch_generic_mib(struct mibif *ifp, const struct ifmibdata *old) 300 { 301 int name[6]; 302 size_t len; 303 struct mibif_private *p = ifp->private; 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 */ 358 static void 359 update_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 */ 373 void 374 mibif_reset_hc_timer(void) 375 { 376 u_int ticks; 377 378 if ((ticks = mibif_force_hc_update_interval) == 0) { 379 if (mibif_maxspeed <= IF_Mbps(10)) { 380 /* at 10Mbps overflow needs 3436 seconds */ 381 ticks = 3000 * 100; /* 50 minutes */ 382 } else if (mibif_maxspeed <= IF_Mbps(100)) { 383 /* at 100Mbps overflow needs 343 seconds */ 384 ticks = 300 * 100; /* 5 minutes */ 385 } else if (mibif_maxspeed < IF_Mbps(622)) { 386 /* at 622Mbps overflow needs 53 seconds */ 387 ticks = 40 * 100; /* 40 seconds */ 388 } else if (mibif_maxspeed <= IF_Mbps(1000)) { 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 */ 416 int 417 mib_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 /* 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 } 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; 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 */ 499 struct mibifa * 500 mib_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 510 struct mibifa * 511 mib_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 */ 525 static struct mibifa * 526 alloc_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 */ 557 static void 558 destroy_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 */ 569 void 570 mib_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 */ 587 static void 588 get_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 */ 646 static void 647 mibif_free(struct mibif *ifp) 648 { 649 struct mibif *ifp1; 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); 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 */ 721 static struct mibif * 722 mibif_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 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 */ 793 static void 794 notify_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 */ 808 static void 809 check_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 */ 840 void 841 mib_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 */ 901 struct mibifa * 902 mib_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 * Handle a routing socket message. 914 */ 915 static void 916 handle_rtmsg(struct rt_msghdr *rtm) 917 { 918 struct sockaddr *addrs[RTAX_MAX]; 919 struct if_msghdr *ifm; 920 struct ifa_msghdr *ifam; 921 struct ifma_msghdr *ifmam; 922 #ifdef RTM_IFANNOUNCE 923 struct if_announcemsghdr *ifan; 924 #endif 925 struct mibif *ifp; 926 struct sockaddr_dl *sdl; 927 struct sockaddr_in *sa; 928 struct mibifa *ifa; 929 struct mibrcvaddr *rcv; 930 u_char *ptr; 931 932 if (rtm->rtm_version != RTM_VERSION) { 933 syslog(LOG_ERR, "Bogus RTM version %u", rtm->rtm_version); 934 return; 935 } 936 937 switch (rtm->rtm_type) { 938 939 case RTM_NEWADDR: 940 ifam = (struct ifa_msghdr *)rtm; 941 mib_extract_addrs(ifam->ifam_addrs, (u_char *)(ifam + 1), addrs); 942 if (addrs[RTAX_IFA] == NULL || addrs[RTAX_NETMASK] == NULL) 943 break; 944 945 sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA]; 946 if ((ifa = mib_find_ifa(sa->sin_addr)) == NULL) { 947 /* unknown address */ 948 if ((ifp = mib_find_if_sys(ifam->ifam_index)) == NULL) { 949 syslog(LOG_WARNING, "RTM_NEWADDR for unknown " 950 "interface %u", ifam->ifam_index); 951 break; 952 } 953 if ((ifa = alloc_ifa(ifp->index, sa->sin_addr)) == NULL) 954 break; 955 } 956 sa = (struct sockaddr_in *)(void *)addrs[RTAX_NETMASK]; 957 ifa->inmask = sa->sin_addr; 958 959 if (addrs[RTAX_BRD] != NULL) { 960 sa = (struct sockaddr_in *)(void *)addrs[RTAX_BRD]; 961 ifa->inbcast = sa->sin_addr; 962 } 963 ifa->flags |= MIBIFA_FOUND; 964 break; 965 966 case RTM_DELADDR: 967 ifam = (struct ifa_msghdr *)rtm; 968 mib_extract_addrs(ifam->ifam_addrs, (u_char *)(ifam + 1), addrs); 969 if (addrs[RTAX_IFA] == NULL) 970 break; 971 972 sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA]; 973 if ((ifa = mib_find_ifa(sa->sin_addr)) != NULL) { 974 ifa->flags |= MIBIFA_FOUND; 975 if (!(ifa->flags & MIBIFA_DESTROYED)) 976 destroy_ifa(ifa); 977 } 978 break; 979 980 case RTM_NEWMADDR: 981 ifmam = (struct ifma_msghdr *)rtm; 982 mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs); 983 if (addrs[RTAX_IFA] == NULL || 984 addrs[RTAX_IFA]->sa_family != AF_LINK) 985 break; 986 sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA]; 987 if ((rcv = mib_find_rcvaddr(sdl->sdl_index, 988 sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) { 989 /* unknown address */ 990 if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL) { 991 syslog(LOG_WARNING, "RTM_NEWMADDR for unknown " 992 "interface %u", sdl->sdl_index); 993 break; 994 } 995 if ((rcv = mib_rcvaddr_create(ifp, 996 sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) 997 break; 998 rcv->flags |= MIBRCVADDR_VOLATILE; 999 } 1000 rcv->flags |= MIBRCVADDR_FOUND; 1001 break; 1002 1003 case RTM_DELMADDR: 1004 ifmam = (struct ifma_msghdr *)rtm; 1005 mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs); 1006 if (addrs[RTAX_IFA] == NULL || 1007 addrs[RTAX_IFA]->sa_family != AF_LINK) 1008 break; 1009 sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA]; 1010 if ((rcv = mib_find_rcvaddr(sdl->sdl_index, 1011 sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) != NULL) 1012 mib_rcvaddr_delete(rcv); 1013 break; 1014 1015 case RTM_IFINFO: 1016 ifm = (struct if_msghdr *)(void *)rtm; 1017 mib_extract_addrs(ifm->ifm_addrs, (u_char *)(ifm + 1), addrs); 1018 if ((ifp = mib_find_if_sys(ifm->ifm_index)) == NULL) 1019 break; 1020 if (addrs[RTAX_IFP] != NULL && 1021 addrs[RTAX_IFP]->sa_family == AF_LINK) { 1022 sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFP]; 1023 ptr = sdl->sdl_data + sdl->sdl_nlen; 1024 get_physaddr(ifp, sdl, ptr); 1025 } 1026 (void)mib_fetch_ifmib(ifp); 1027 break; 1028 1029 #ifdef RTM_IFANNOUNCE 1030 case RTM_IFANNOUNCE: 1031 ifan = (struct if_announcemsghdr *)rtm; 1032 ifp = mib_find_if_sys(ifan->ifan_index); 1033 1034 switch (ifan->ifan_what) { 1035 1036 case IFAN_ARRIVAL: 1037 if (ifp == NULL && (ifp = mibif_create(ifan->ifan_index, 1038 ifan->ifan_name)) != NULL) { 1039 (void)mib_fetch_ifmib(ifp); 1040 check_llbcast(ifp); 1041 notify_newif(ifp); 1042 } 1043 break; 1044 1045 case IFAN_DEPARTURE: 1046 if (ifp != NULL) 1047 mibif_free(ifp); 1048 break; 1049 } 1050 break; 1051 #endif 1052 case RTM_GET: 1053 case RTM_ADD: 1054 case RTM_DELETE: 1055 mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); 1056 1057 if (rtm->rtm_errno == 0 && (rtm->rtm_flags & RTF_UP)) 1058 mib_sroute_process(rtm, addrs[RTAX_GATEWAY], 1059 addrs[RTAX_DST], addrs[RTAX_NETMASK]); 1060 break; 1061 } 1062 } 1063 1064 /* 1065 * send a routing message 1066 */ 1067 void 1068 mib_send_rtmsg(struct rt_msghdr *rtm, struct sockaddr *gw, 1069 struct sockaddr *dst, struct sockaddr *mask) 1070 { 1071 size_t len; 1072 struct rt_msghdr *msg; 1073 char *cp; 1074 ssize_t sent; 1075 1076 len = sizeof(*rtm) + SA_SIZE(gw) + SA_SIZE(dst) + SA_SIZE(mask); 1077 if ((msg = malloc(len)) == NULL) { 1078 syslog(LOG_ERR, "%s: %m", __func__); 1079 return; 1080 } 1081 cp = (char *)(msg + 1); 1082 1083 memset(msg, 0, sizeof(*msg)); 1084 msg->rtm_flags = 0; 1085 msg->rtm_version = RTM_VERSION; 1086 msg->rtm_addrs = RTA_DST | RTA_GATEWAY; 1087 1088 memcpy(cp, dst, SA_SIZE(dst)); 1089 cp += SA_SIZE(dst); 1090 memcpy(cp, gw, SA_SIZE(gw)); 1091 cp += SA_SIZE(gw); 1092 if (mask != NULL) { 1093 memcpy(cp, mask, SA_SIZE(mask)); 1094 cp += SA_SIZE(mask); 1095 msg->rtm_addrs |= RTA_NETMASK; 1096 } 1097 msg->rtm_msglen = cp - (char *)msg; 1098 msg->rtm_type = RTM_GET; 1099 if ((sent = write(route, msg, msg->rtm_msglen)) == -1) { 1100 syslog(LOG_ERR, "%s: write: %m", __func__); 1101 free(msg); 1102 return; 1103 } 1104 if (sent != msg->rtm_msglen) { 1105 syslog(LOG_ERR, "%s: short write", __func__); 1106 free(msg); 1107 return; 1108 } 1109 free(msg); 1110 } 1111 1112 /* 1113 * Fetch the routing table via sysctl 1114 */ 1115 u_char * 1116 mib_fetch_rtab(int af, int info, int arg, size_t *lenp) 1117 { 1118 int name[6]; 1119 u_char *buf, *newbuf; 1120 1121 name[0] = CTL_NET; 1122 name[1] = PF_ROUTE; 1123 name[2] = 0; 1124 name[3] = af; 1125 name[4] = info; 1126 name[5] = arg; 1127 1128 *lenp = 0; 1129 1130 /* initial estimate */ 1131 if (sysctl(name, 6, NULL, lenp, NULL, 0) == -1) { 1132 syslog(LOG_ERR, "sysctl estimate (%d,%d,%d,%d,%d,%d): %m", 1133 name[0], name[1], name[2], name[3], name[4], name[5]); 1134 return (NULL); 1135 } 1136 if (*lenp == 0) 1137 return (NULL); 1138 1139 buf = NULL; 1140 for (;;) { 1141 if ((newbuf = realloc(buf, *lenp)) == NULL) { 1142 syslog(LOG_ERR, "sysctl buffer: %m"); 1143 free(buf); 1144 return (NULL); 1145 } 1146 buf = newbuf; 1147 1148 if (sysctl(name, 6, buf, lenp, NULL, 0) == 0) 1149 break; 1150 1151 if (errno != ENOMEM) { 1152 syslog(LOG_ERR, "sysctl get: %m"); 1153 free(buf); 1154 return (NULL); 1155 } 1156 *lenp += *lenp / 8 + 1; 1157 } 1158 1159 return (buf); 1160 } 1161 1162 /* 1163 * Update the following info: interface, interface addresses, interface 1164 * receive addresses, arp-table. 1165 * This does not change the interface list itself. 1166 */ 1167 static void 1168 update_ifa_info(void) 1169 { 1170 u_char *buf, *next; 1171 struct rt_msghdr *rtm; 1172 struct mibifa *ifa, *ifa1; 1173 struct mibrcvaddr *rcv, *rcv1; 1174 size_t needed; 1175 static const int infos[][3] = { 1176 { 0, NET_RT_IFLIST, 0 }, 1177 #ifdef NET_RT_IFMALIST 1178 { AF_LINK, NET_RT_IFMALIST, 0 }, 1179 #endif 1180 }; 1181 u_int i; 1182 1183 TAILQ_FOREACH(ifa, &mibifa_list, link) 1184 ifa->flags &= ~MIBIFA_FOUND; 1185 TAILQ_FOREACH(rcv, &mibrcvaddr_list, link) 1186 rcv->flags &= ~MIBRCVADDR_FOUND; 1187 1188 for (i = 0; i < sizeof(infos) / sizeof(infos[0]); i++) { 1189 if ((buf = mib_fetch_rtab(infos[i][0], infos[i][1], infos[i][2], 1190 &needed)) == NULL) 1191 continue; 1192 1193 next = buf; 1194 while (next < buf + needed) { 1195 rtm = (struct rt_msghdr *)(void *)next; 1196 next += rtm->rtm_msglen; 1197 handle_rtmsg(rtm); 1198 } 1199 free(buf); 1200 } 1201 1202 /* 1203 * Purge the address list of unused entries. These may happen for 1204 * interface aliases that are on the same subnet. We don't receive 1205 * routing socket messages for them. 1206 */ 1207 ifa = TAILQ_FIRST(&mibifa_list); 1208 while (ifa != NULL) { 1209 ifa1 = TAILQ_NEXT(ifa, link); 1210 if (!(ifa->flags & MIBIFA_FOUND)) 1211 destroy_ifa(ifa); 1212 ifa = ifa1; 1213 } 1214 1215 rcv = TAILQ_FIRST(&mibrcvaddr_list); 1216 while (rcv != NULL) { 1217 rcv1 = TAILQ_NEXT(rcv, link); 1218 if (!(rcv->flags & (MIBRCVADDR_FOUND | MIBRCVADDR_BCAST | 1219 MIBRCVADDR_HW))) 1220 mib_rcvaddr_delete(rcv); 1221 rcv = rcv1; 1222 } 1223 } 1224 1225 /* 1226 * Update arp table 1227 * 1228 */ 1229 void 1230 mib_arp_update(void) 1231 { 1232 struct mibarp *at, *at1; 1233 size_t needed; 1234 u_char *buf, *next; 1235 struct rt_msghdr *rtm; 1236 1237 if (in_update_arp) 1238 return; /* Aaargh */ 1239 in_update_arp = 1; 1240 1241 TAILQ_FOREACH(at, &mibarp_list, link) 1242 at->flags &= ~MIBARP_FOUND; 1243 1244 if ((buf = mib_fetch_rtab(AF_INET, NET_RT_FLAGS, 0, &needed)) == NULL) { 1245 in_update_arp = 0; 1246 return; 1247 } 1248 1249 next = buf; 1250 while (next < buf + needed) { 1251 rtm = (struct rt_msghdr *)(void *)next; 1252 next += rtm->rtm_msglen; 1253 handle_rtmsg(rtm); 1254 } 1255 free(buf); 1256 1257 at = TAILQ_FIRST(&mibarp_list); 1258 while (at != NULL) { 1259 at1 = TAILQ_NEXT(at, link); 1260 if (!(at->flags & MIBARP_FOUND)) 1261 mib_arp_delete(at); 1262 at = at1; 1263 } 1264 mibarpticks = get_ticks(); 1265 in_update_arp = 0; 1266 } 1267 1268 1269 /* 1270 * Intput on the routing socket. 1271 */ 1272 static void 1273 route_input(int fd, void *udata __unused) 1274 { 1275 u_char buf[1024 * 16]; 1276 ssize_t n; 1277 struct rt_msghdr *rtm; 1278 1279 if ((n = read(fd, buf, sizeof(buf))) == -1) 1280 err(1, "read(rt_socket)"); 1281 1282 if (n == 0) 1283 errx(1, "EOF on rt_socket"); 1284 1285 rtm = (struct rt_msghdr *)(void *)buf; 1286 if ((size_t)n != rtm->rtm_msglen) 1287 errx(1, "n=%zu, rtm_msglen=%u", (size_t)n, rtm->rtm_msglen); 1288 1289 handle_rtmsg(rtm); 1290 } 1291 1292 /* 1293 * execute and SIOCAIFADDR 1294 */ 1295 static int 1296 siocaifaddr(char *ifname, struct in_addr addr, struct in_addr mask, 1297 struct in_addr bcast) 1298 { 1299 struct ifaliasreq addreq; 1300 struct sockaddr_in *sa; 1301 1302 memset(&addreq, 0, sizeof(addreq)); 1303 strncpy(addreq.ifra_name, ifname, sizeof(addreq.ifra_name)); 1304 1305 sa = (struct sockaddr_in *)(void *)&addreq.ifra_addr; 1306 sa->sin_family = AF_INET; 1307 sa->sin_len = sizeof(*sa); 1308 sa->sin_addr = addr; 1309 1310 sa = (struct sockaddr_in *)(void *)&addreq.ifra_mask; 1311 sa->sin_family = AF_INET; 1312 sa->sin_len = sizeof(*sa); 1313 sa->sin_addr = mask; 1314 1315 sa = (struct sockaddr_in *)(void *)&addreq.ifra_broadaddr; 1316 sa->sin_family = AF_INET; 1317 sa->sin_len = sizeof(*sa); 1318 sa->sin_addr = bcast; 1319 1320 return (ioctl(mib_netsock, SIOCAIFADDR, &addreq)); 1321 } 1322 1323 /* 1324 * Exececute a SIOCDIFADDR 1325 */ 1326 static int 1327 siocdifaddr(const char *ifname, struct in_addr addr) 1328 { 1329 struct ifreq delreq; 1330 struct sockaddr_in *sa; 1331 1332 memset(&delreq, 0, sizeof(delreq)); 1333 strncpy(delreq.ifr_name, ifname, sizeof(delreq.ifr_name)); 1334 sa = (struct sockaddr_in *)(void *)&delreq.ifr_addr; 1335 sa->sin_family = AF_INET; 1336 sa->sin_len = sizeof(*sa); 1337 sa->sin_addr = addr; 1338 1339 return (ioctl(mib_netsock, SIOCDIFADDR, &delreq)); 1340 } 1341 1342 /* 1343 * Verify an interface address without fetching the entire list 1344 */ 1345 static int 1346 verify_ifa(const char *name, struct mibifa *ifa) 1347 { 1348 struct ifreq req; 1349 struct sockaddr_in *sa; 1350 1351 memset(&req, 0, sizeof(req)); 1352 strncpy(req.ifr_name, name, sizeof(req.ifr_name)); 1353 sa = (struct sockaddr_in *)(void *)&req.ifr_addr; 1354 sa->sin_family = AF_INET; 1355 sa->sin_len = sizeof(*sa); 1356 sa->sin_addr = ifa->inaddr; 1357 1358 if (ioctl(mib_netsock, SIOCGIFADDR, &req) == -1) 1359 return (-1); 1360 if (ifa->inaddr.s_addr != sa->sin_addr.s_addr) { 1361 syslog(LOG_ERR, "%s: address mismatch", __func__); 1362 return (-1); 1363 } 1364 1365 if (ioctl(mib_netsock, SIOCGIFNETMASK, &req) == -1) 1366 return (-1); 1367 if (ifa->inmask.s_addr != sa->sin_addr.s_addr) { 1368 syslog(LOG_ERR, "%s: netmask mismatch", __func__); 1369 return (-1); 1370 } 1371 return (0); 1372 } 1373 1374 /* 1375 * Restore a deleted interface address. Don't wait for the routing socket 1376 * to update us. 1377 */ 1378 void 1379 mib_undestroy_ifa(struct mibifa *ifa) 1380 { 1381 struct mibif *ifp; 1382 1383 if ((ifp = mib_find_if(ifa->ifindex)) == NULL) 1384 /* keep it destroyed */ 1385 return; 1386 1387 if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) 1388 /* keep it destroyed */ 1389 return; 1390 1391 ifa->flags &= ~MIBIFA_DESTROYED; 1392 } 1393 1394 /* 1395 * Destroy an interface address 1396 */ 1397 int 1398 mib_destroy_ifa(struct mibifa *ifa) 1399 { 1400 struct mibif *ifp; 1401 1402 if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { 1403 /* ups. */ 1404 mib_iflist_bad = 1; 1405 return (-1); 1406 } 1407 if (siocdifaddr(ifp->name, ifa->inaddr)) { 1408 /* ups. */ 1409 syslog(LOG_ERR, "SIOCDIFADDR: %m"); 1410 mib_iflist_bad = 1; 1411 return (-1); 1412 } 1413 ifa->flags |= MIBIFA_DESTROYED; 1414 return (0); 1415 } 1416 1417 /* 1418 * Rollback the modification of an address. Don't bother to wait for 1419 * the routing socket. 1420 */ 1421 void 1422 mib_unmodify_ifa(struct mibifa *ifa) 1423 { 1424 struct mibif *ifp; 1425 1426 if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { 1427 /* ups. */ 1428 mib_iflist_bad = 1; 1429 return; 1430 } 1431 1432 if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { 1433 /* ups. */ 1434 mib_iflist_bad = 1; 1435 return; 1436 } 1437 } 1438 1439 /* 1440 * Modify an IFA. 1441 */ 1442 int 1443 mib_modify_ifa(struct mibifa *ifa) 1444 { 1445 struct mibif *ifp; 1446 1447 if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { 1448 /* ups. */ 1449 mib_iflist_bad = 1; 1450 return (-1); 1451 } 1452 1453 if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { 1454 /* ups. */ 1455 mib_iflist_bad = 1; 1456 return (-1); 1457 } 1458 1459 if (verify_ifa(ifp->name, ifa)) { 1460 /* ups. */ 1461 mib_iflist_bad = 1; 1462 return (-1); 1463 } 1464 1465 return (0); 1466 } 1467 1468 /* 1469 * Destroy a freshly created interface address. Don't bother to wait for 1470 * the routing socket. 1471 */ 1472 void 1473 mib_uncreate_ifa(struct mibifa *ifa) 1474 { 1475 struct mibif *ifp; 1476 1477 if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { 1478 /* ups. */ 1479 mib_iflist_bad = 1; 1480 return; 1481 } 1482 if (siocdifaddr(ifp->name, ifa->inaddr)) { 1483 /* ups. */ 1484 mib_iflist_bad = 1; 1485 return; 1486 } 1487 1488 destroy_ifa(ifa); 1489 } 1490 1491 /* 1492 * Create a new ifa and verify it 1493 */ 1494 struct mibifa * 1495 mib_create_ifa(u_int ifindex, struct in_addr addr, struct in_addr mask, 1496 struct in_addr bcast) 1497 { 1498 struct mibif *ifp; 1499 struct mibifa *ifa; 1500 1501 if ((ifp = mib_find_if(ifindex)) == NULL) 1502 return (NULL); 1503 if ((ifa = alloc_ifa(ifindex, addr)) == NULL) 1504 return (NULL); 1505 ifa->inmask = mask; 1506 ifa->inbcast = bcast; 1507 1508 if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { 1509 syslog(LOG_ERR, "%s: %m", __func__); 1510 destroy_ifa(ifa); 1511 return (NULL); 1512 } 1513 if (verify_ifa(ifp->name, ifa)) { 1514 destroy_ifa(ifa); 1515 return (NULL); 1516 } 1517 return (ifa); 1518 } 1519 1520 /* 1521 * Get all cloning interfaces and make them dynamic. 1522 * Hah! Whe should probably do this on a periodic basis (XXX). 1523 */ 1524 static void 1525 get_cloners(void) 1526 { 1527 struct if_clonereq req; 1528 char *buf, *cp; 1529 int i; 1530 1531 memset(&req, 0, sizeof(req)); 1532 if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) { 1533 syslog(LOG_ERR, "get cloners: %m"); 1534 return; 1535 } 1536 if ((buf = malloc(req.ifcr_total * IFNAMSIZ)) == NULL) { 1537 syslog(LOG_ERR, "%m"); 1538 return; 1539 } 1540 req.ifcr_count = req.ifcr_total; 1541 req.ifcr_buffer = buf; 1542 if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) { 1543 syslog(LOG_ERR, "get cloners: %m"); 1544 free(buf); 1545 return; 1546 } 1547 for (cp = buf, i = 0; i < req.ifcr_total; i++, cp += IFNAMSIZ) 1548 mib_if_set_dyn(cp); 1549 free(buf); 1550 } 1551 1552 /* 1553 * Idle function 1554 */ 1555 static void 1556 mibII_idle(void) 1557 { 1558 struct mibifa *ifa; 1559 1560 if (mib_iflist_bad) { 1561 TAILQ_FOREACH(ifa, &mibifa_list, link) 1562 ifa->flags &= ~MIBIFA_DESTROYED; 1563 1564 /* assume, that all cloning interfaces are dynamic */ 1565 get_cloners(); 1566 1567 mib_refresh_iflist(); 1568 update_ifa_info(); 1569 mib_arp_update(); 1570 mib_iflist_bad = 0; 1571 } 1572 1573 mib_arp_update(); 1574 } 1575 1576 1577 /* 1578 * Start the module 1579 */ 1580 static void 1581 mibII_start(void) 1582 { 1583 if ((route_fd = fd_select(route, route_input, NULL, module)) == NULL) { 1584 syslog(LOG_ERR, "fd_select(route): %m"); 1585 return; 1586 } 1587 mib_refresh_iflist(); 1588 update_ifa_info(); 1589 mib_arp_update(); 1590 (void)mib_fetch_route(); 1591 mib_iftable_last_change = 0; 1592 mib_ifstack_last_change = 0; 1593 1594 ifmib_reg = or_register(&oid_ifMIB, 1595 "The MIB module to describe generic objects for network interface" 1596 " sub-layers.", module); 1597 1598 ipmib_reg = or_register(&oid_ipMIB, 1599 "The MIB module for managing IP and ICMP implementations, but " 1600 "excluding their management of IP routes.", module); 1601 1602 tcpmib_reg = or_register(&oid_tcpMIB, 1603 "The MIB module for managing TCP implementations.", module); 1604 1605 udpmib_reg = or_register(&oid_udpMIB, 1606 "The MIB module for managing UDP implementations.", module); 1607 1608 ipForward_reg = or_register(&oid_ipForward, 1609 "The MIB module for the display of CIDR multipath IP Routes.", 1610 module); 1611 } 1612 1613 /* 1614 * Initialize the module 1615 */ 1616 static int 1617 mibII_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) 1618 { 1619 size_t len; 1620 1621 module = mod; 1622 1623 len = sizeof(clockinfo); 1624 if (sysctlbyname("kern.clockrate", &clockinfo, &len, NULL, 0) == -1) { 1625 syslog(LOG_ERR, "kern.clockrate: %m"); 1626 return (-1); 1627 } 1628 if (len != sizeof(clockinfo)) { 1629 syslog(LOG_ERR, "kern.clockrate: wrong size"); 1630 return (-1); 1631 } 1632 1633 if ((route = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) == -1) { 1634 syslog(LOG_ERR, "PF_ROUTE: %m"); 1635 return (-1); 1636 } 1637 1638 if ((mib_netsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 1639 syslog(LOG_ERR, "PF_INET: %m"); 1640 (void)close(route); 1641 return (-1); 1642 } 1643 (void)shutdown(mib_netsock, SHUT_RDWR); 1644 1645 /* assume, that all cloning interfaces are dynamic */ 1646 get_cloners(); 1647 1648 return (0); 1649 } 1650 1651 static int 1652 mibII_fini(void) 1653 { 1654 if (route_fd != NULL) 1655 fd_deselect(route_fd); 1656 if (route != -1) 1657 (void)close(route); 1658 if (mib_netsock != -1) 1659 (void)close(mib_netsock); 1660 /* XXX free memory */ 1661 1662 or_unregister(ipForward_reg); 1663 or_unregister(udpmib_reg); 1664 or_unregister(tcpmib_reg); 1665 or_unregister(ipmib_reg); 1666 or_unregister(ifmib_reg); 1667 1668 return (0); 1669 } 1670 1671 static void 1672 mibII_loading(const struct lmodule *mod, int loaded) 1673 { 1674 struct mibif *ifp; 1675 1676 if (loaded == 1) 1677 return; 1678 1679 TAILQ_FOREACH(ifp, &mibif_list, link) 1680 if (ifp->xnotify_mod == mod) { 1681 ifp->xnotify_mod = NULL; 1682 ifp->xnotify_data = NULL; 1683 ifp->xnotify = NULL; 1684 } 1685 1686 mib_unregister_newif(mod); 1687 } 1688 1689 const struct snmp_module config = { 1690 "This module implements the interface and ip groups.", 1691 mibII_init, 1692 mibII_fini, 1693 mibII_idle, /* idle */ 1694 NULL, /* dump */ 1695 NULL, /* config */ 1696 mibII_start, 1697 NULL, 1698 mibII_ctree, 1699 mibII_CTREE_SIZE, 1700 mibII_loading 1701 }; 1702 1703 /* 1704 * Should have a list of these attached to each interface. 1705 */ 1706 void * 1707 mibif_notify(struct mibif *ifp, const struct lmodule *mod, 1708 mibif_notify_f func, void *data) 1709 { 1710 ifp->xnotify = func; 1711 ifp->xnotify_data = data; 1712 ifp->xnotify_mod = mod; 1713 1714 return (ifp); 1715 } 1716 1717 void 1718 mibif_unnotify(void *arg) 1719 { 1720 struct mibif *ifp = arg; 1721 1722 ifp->xnotify = NULL; 1723 ifp->xnotify_data = NULL; 1724 ifp->xnotify_mod = NULL; 1725 } 1726