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.24 2006/02/14 09:04:18 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 */ 41 static struct lmodule *module; 42 43 /* routing socket */ 44 static int route; 45 static void *route_fd; 46 47 /* if-index allocator */ 48 static uint32_t next_if_index = 1; 49 50 /* re-fetch arp table */ 51 static int update_arp; 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 <= 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 */ 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 * Process a new ARP entry 914 */ 915 static void 916 process_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 */ 945 static void 946 handle_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 */ 1131 void 1132 mib_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 */ 1179 u_char * 1180 mib_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 */ 1231 static void 1232 update_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 */ 1292 void 1293 mib_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 */ 1336 static void 1337 route_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 */ 1359 static int 1360 siocaifaddr(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 */ 1390 static int 1391 siocdifaddr(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 */ 1409 static int 1410 verify_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 */ 1442 void 1443 mib_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 */ 1461 int 1462 mib_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 */ 1485 void 1486 mib_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 */ 1506 int 1507 mib_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 */ 1536 void 1537 mib_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 */ 1558 struct mibifa * 1559 mib_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 */ 1588 static void 1589 get_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 */ 1619 static void 1620 mibII_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 */ 1644 static void 1645 mibII_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 */ 1680 static int 1681 mibII_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 1715 static int 1716 mibII_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 1735 static void 1736 mibII_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 1753 const 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 */ 1770 void * 1771 mibif_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 1781 void 1782 mibif_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 } 1790