1 /* $NetBSD: snmp.c,v 1.11 2003/05/16 18:10:38 itojun Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 2001 Xerox Corporation. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without modification, 7 * are permitted provided that the following conditions are met: 8 * 9 * Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * Neither name of the Xerox, PARC, nor the names of its contributors may be used 17 * to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE XEROX CORPORATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include "defs.h" 34 #include <netinet/in_var.h> 35 #include "snmp.h" 36 #include "snmplib/asn1.h" 37 #include "snmplib/party.h" 38 #include "snmplib/snmp_impl.h" 39 #define MROUTED 40 #include "snmpd/snmp_vars.h" 41 42 in_port_t dest_port = 0; 43 int sdlen = 0; 44 45 struct addrCache { 46 u_long addr; 47 int status; 48 #define UNUSED 0 49 #define USED 1 50 #define OLD 2 51 }; 52 53 static struct addrCache addrCache[10]; 54 55 /* 56 * Initialize the SNMP part of mrouted 57 */ 58 int /* returns: 0 on success, true on error */ 59 snmp_init(dest_port) 60 in_port_t dest_port; 61 { 62 u_long myaddr; 63 int ret; 64 struct partyEntry *pp; 65 struct sockaddr_in me; 66 int index, sd, portlist[32]; 67 68 init_snmp(); 69 /* init_mib(); why was this here? */ 70 if (read_party_database("/etc/party.conf") > 0){ 71 fprintf(stderr, "Couldn't read party database from /etc/party.conf\n"); 72 exit(0); 73 } 74 if (read_context_database("/etc/context.conf") > 0){ 75 fprintf(stderr, "Couldn't read context database from /etc/context.conf\n"); 76 exit(0); 77 } 78 if (read_acl_database("/etc/acl.conf") > 0){ 79 fprintf(stderr, "Couldn't read acl database from /etc/acl.conf\n"); 80 exit(0); 81 } 82 if (read_view_database("/etc/view.conf") > 0){ 83 fprintf(stderr, "Couldn't read view database from /etc/view.conf\n"); 84 exit(0); 85 } 86 87 myaddr = get_myaddr(); 88 if (ret = agent_party_init(myaddr, ".1.3.6.1")){ 89 if (ret == 1){ 90 fprintf(stderr, "Conflict found with initial noAuth/noPriv parties... continuing\n"); 91 } else if (ret == -1){ 92 fprintf(stderr, "Error installing initial noAuth/noPriv parties, exiting\n"); 93 exit(1); 94 } else { 95 fprintf(stderr, "Unknown error, exiting\n"); 96 exit(2); 97 } 98 } 99 100 printf("Opening port(s): "); 101 fflush(stdout); 102 party_scanInit(); 103 for(pp = party_scanNext(); pp; pp = party_scanNext()){ 104 if ((pp->partyTDomain != DOMAINSNMPUDP) 105 || bcmp((char *)&myaddr, pp->partyTAddress, 4)) 106 continue; /* don't listen for non-local parties */ 107 108 dest_port = 0; 109 bcopy(pp->partyTAddress + 4, &dest_port, 2); 110 for(index = 0; index < sdlen; index++) 111 if (dest_port == portlist[index]) 112 break; 113 if (index < sdlen) /* found a hit before the end of the list */ 114 continue; 115 printf("%u ", dest_port); 116 fflush(stdout); 117 /* Set up connections */ 118 sd = socket(AF_INET, SOCK_DGRAM, 0); 119 if (sd < 0){ 120 perror("socket"); 121 return 1; 122 } 123 memset(&me, 0, sizeof(me)); 124 me.sin_family = AF_INET; 125 me.sin_addr.s_addr = INADDR_ANY; 126 /* already in network byte order (I think) */ 127 me.sin_port = dest_port; 128 if (bind(sd, (struct sockaddr *)&me, sizeof(me)) != 0){ 129 perror("bind"); 130 return 2; 131 } 132 register_input_handler(sd, snmp_read_packet); 133 portlist[sdlen] = dest_port; 134 if (++sdlen == 32){ 135 printf("No more sockets... ignoring rest of file\n"); 136 break; 137 } 138 } 139 printf("\n"); 140 bzero((char *)addrCache, sizeof(addrCache)); 141 } 142 143 /* 144 * Place an IP address into an OID starting at element n 145 */ 146 void 147 put_address(name, addr, n) 148 oid *name; 149 u_long addr; 150 int n; 151 { 152 int i; 153 154 for (i=n+3; i>=n+0; i--) { 155 name[i] = addr & 0xFF; 156 addr >>= 8; 157 } 158 } 159 160 /* Get an IP address from an OID starting at element n */ 161 int 162 get_address(name, length, addr, n) 163 oid *name; 164 int length; 165 u_long *addr; 166 int n; 167 { 168 int i; 169 int ok = 1; 170 171 (*addr) = 0; 172 173 if (length < n+4) 174 return 0; 175 176 for (i=n; i<n+4; i++) { 177 (*addr) <<= 8; 178 if (i >= length) 179 ok = 0; 180 else 181 (*addr) |= name[i]; 182 } 183 return ok; 184 } 185 186 /* 187 * Implements scalar objects from DVMRP and Multicast MIBs 188 */ 189 u_char * 190 o_scalar(vp, name, length, exact, var_len, write_method) 191 struct variable *vp; /* IN - pointer to variable entry that points here */ 192 oid *name; /* IN/OUT - input name requested, output name found */ 193 int *length; /* IN/OUT - length of input and output oid's */ 194 int exact; /* IN - TRUE if an exact match was requested. */ 195 int *var_len; /* OUT - length of variable or 0 if function returned. */ 196 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 197 { 198 int result; 199 200 *write_method = 0; 201 result = compare(name, *length, vp->name, (int)vp->namelen); 202 if ((exact && (result != 0)) || (!exact && (result >= 0))) 203 return NULL; 204 205 bcopy((char *)vp->name, (char *)name, 206 (int)vp->namelen * sizeof(oid)); 207 *length = vp->namelen; 208 *var_len = sizeof(long); 209 210 switch (vp->magic) { 211 212 case ipMRouteEnable: 213 long_return = 1; 214 return (u_char *) &long_return; 215 216 case dvmrpVersion: { 217 static char buff[15]; 218 219 snprintf(buff, sizeof(buff), "mrouted%d.%d", PROTOCOL_VERSION, 220 MROUTED_VERSION); 221 *var_len = strlen(buff); 222 return (u_char *)buff; 223 } 224 225 case dvmrpGenerationId: 226 long_return = dvmrp_genid; 227 return (u_char *) &long_return; 228 229 default: 230 ERROR(""); 231 } 232 return NULL; 233 } 234 235 /* 236 * Find if a specific scoped boundary exists on a Vif 237 */ 238 struct vif_acl * 239 find_boundary(vifi, addr, mask) 240 vifi_t vifi; 241 u_long addr; 242 u_long mask; 243 { 244 struct vif_acl *n; 245 246 for (n = uvifs[vifi].uv_acl; n != NULL; n = n->acl_next) { 247 if (addr == n->acl_addr && mask==n->acl_mask) 248 return n; 249 } 250 return NULL; 251 } 252 253 /* 254 * Find the lowest boundary >= (V,A,M) spec 255 */ 256 struct vif_acl * 257 next_boundary(vifi, addr, mask) 258 vifi_t *vifi; 259 u_long addr; 260 u_long mask; 261 { 262 struct vif_acl *bestn, *n; 263 int i; 264 265 for (i = *vifi; i < numvifs; i++) { 266 bestn = NULL; 267 for (n = uvifs[i].uv_acl; n; n=n->acl_next) { 268 if ((i > *vifi || n->acl_addr > addr 269 || (n->acl_addr == addr && n->acl_mask >= mask)) 270 && (!bestn || n->acl_addr < bestn->acl_addr 271 || (n->acl_addr==bestn->acl_addr && n->acl_mask<bestn->acl_mask))) 272 bestn = n; 273 } 274 if (bestn) { 275 *vifi = i; 276 return bestn; 277 } 278 } 279 return NULL; 280 } 281 282 /* 283 * Implements the Boundary Table portion of the DVMRP MIB 284 */ 285 u_char * 286 o_dvmrpBoundaryTable(vp, name, length, exact, var_len, write_method) 287 struct variable *vp; /* IN - pointer to variable entry that points here */ 288 oid *name; /* IN/OUT - input name requested, output name found */ 289 int *length; /* IN/OUT - length of input and output oid's */ 290 int exact; /* IN - TRUE if an exact match was requested. */ 291 int *var_len; /* OUT - length of variable or 0 if function returned. */ 292 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 293 { 294 vifi_t vifi; 295 u_long addr, mask; 296 struct vif_acl *bound; 297 oid newname[MAX_NAME_LEN]; 298 int len; 299 300 /* Copy name OID to new OID */ 301 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 302 303 if (exact) { 304 if (*length != vp->namelen + 9) 305 return NULL; 306 307 if ((vifi = name[vp->namelen]) >= numvifs) 308 return NULL; 309 310 if (!get_address(name, *length, &addr, vp->namelen+1) 311 || !get_address(name, *length, &mask, vp->namelen+5)) 312 return NULL; 313 314 if (!(bound = find_boundary(vifi, addr, mask))) 315 return NULL; 316 317 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 318 } else { 319 len = *length; 320 if (compare(name, *length, vp->name, vp->namelen) < 0) 321 len = vp->namelen; 322 323 if (len < vp->namelen + 9) { /* get first entry */ 324 325 if (len == vp->namelen) { 326 vifi = addr = mask = 0; 327 } else { 328 vifi = name[vp->namelen]; 329 get_address(name, len, &addr, vp->namelen+1); 330 get_address(name, len, &mask, vp->namelen+5); 331 } 332 333 bound = next_boundary(&vifi,addr,mask); 334 if (!bound) 335 return NULL; 336 337 newname[vp->namelen] = vifi; 338 put_address(newname, bound->acl_addr, vp->namelen+1); 339 put_address(newname, bound->acl_mask, vp->namelen+5); 340 } else { /* get next entry given previous */ 341 vifi = name[vp->namelen]; 342 get_address(name, *length, &addr, vp->namelen+1); 343 get_address(name, *length, &mask, vp->namelen+5); 344 345 if (!(bound = next_boundary(&vifi,addr,mask+1))) 346 return NULL; 347 348 newname[vp->namelen] = vifi; 349 put_address(newname, bound->acl_addr, vp->namelen+1); 350 put_address(newname, bound->acl_mask, vp->namelen+5); 351 } 352 } 353 354 /* Save new OID */ 355 *length = vp->namelen + 9; 356 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 357 *write_method = 0; 358 *var_len = sizeof(long); 359 360 switch (vp->magic) { 361 362 case dvmrpBoundaryVifIndex: 363 long_return = vifi; 364 return (u_char *) &long_return; 365 366 default: 367 ERROR(""); 368 } 369 return NULL; 370 } 371 372 /* 373 * Find the lowest neighbor >= (V,A) spec 374 */ 375 struct listaddr * 376 next_neighbor(vifi, addr) 377 vifi_t *vifi; 378 u_long addr; 379 { 380 struct listaddr *bestn, *n; 381 int i; 382 383 for (i = *vifi; i < numvifs; i++) { 384 bestn = NULL; 385 for (n = uvifs[i].uv_neighbors; n; n=n->al_next) { 386 if ((i > *vifi || n->al_addr >= addr) 387 && (!bestn || n->al_addr < bestn->al_addr)) 388 bestn = n; 389 } 390 if (bestn) { 391 *vifi = i; 392 return bestn; 393 } 394 } 395 return NULL; 396 } 397 398 /* 399 * Find a neighbor, if it exists off a given Vif 400 */ 401 struct listaddr * 402 find_neighbor(vifi, addr) 403 vifi_t vifi; 404 u_long addr; 405 { 406 struct listaddr *n; 407 408 for (n = uvifs[vifi].uv_neighbors; n != NULL; n = n->al_next) { 409 if (addr == n->al_addr) 410 return n; 411 } 412 return NULL; 413 } 414 415 u_char * 416 o_dvmrpNeighborTable(vp, name, length, exact, var_len, write_method) 417 struct variable *vp; /* IN - pointer to variable entry that points here */ 418 oid *name; /* IN/OUT - input name requested, output name found */ 419 int *length; /* IN/OUT - length of input and output oid's */ 420 int exact; /* IN - TRUE if an exact match was requested. */ 421 int *var_len; /* OUT - length of variable or 0 if function returned. */ 422 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 423 { 424 vifi_t vifi; 425 u_long addr, mask; 426 struct listaddr *neighbor; 427 oid newname[MAX_NAME_LEN]; 428 int len; 429 430 /* Copy name OID to new OID */ 431 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 432 433 if (exact) { 434 if (*length != vp->namelen + 5) 435 return NULL; 436 437 if ((vifi = name[vp->namelen]) >= numvifs) 438 return NULL; 439 440 if (!get_address(name, *length, &addr, vp->namelen+1)) 441 return NULL; 442 443 if (!(neighbor = find_neighbor(vifi, addr))) 444 return NULL; 445 446 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 447 } else { 448 len = *length; 449 if (compare(name, *length, vp->name, vp->namelen) < 0) 450 len = vp->namelen; 451 452 if (len < vp->namelen + 5) { /* get first entry */ 453 454 if (len == vp->namelen) { 455 vifi = addr = 0; 456 } else { 457 vifi = name[vp->namelen]; 458 get_address(name, len, &addr, vp->namelen+1); 459 } 460 461 neighbor = next_neighbor(&vifi,addr); 462 if (!neighbor) 463 return NULL; 464 465 newname[vp->namelen] = vifi; 466 put_address(newname, neighbor->al_addr, vp->namelen+1); 467 } else { /* get next entry given previous */ 468 vifi = name[vp->namelen]; 469 get_address(name, *length, &addr, vp->namelen+1); 470 471 if (!(neighbor = next_neighbor(&vifi,addr+1))) 472 return NULL; 473 474 newname[vp->namelen] = vifi; 475 put_address(newname, neighbor->al_addr, vp->namelen+1); 476 } 477 } 478 479 /* Save new OID */ 480 *length = vp->namelen + 5; 481 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 482 *write_method = 0; 483 *var_len = sizeof(long); 484 485 switch (vp->magic) { 486 487 case dvmrpNeighborUpTime: { 488 time_t currtime; 489 time(&currtime); 490 long_return = (currtime - neighbor->al_ctime)*100; 491 return (u_char *) &long_return; 492 } 493 494 case dvmrpNeighborExpiryTime: 495 long_return = (NEIGHBOR_EXPIRE_TIME - neighbor->al_timer 496 + secs_remaining_offset()) * 100; 497 return (u_char *) &long_return; 498 499 case dvmrpNeighborVersion: { 500 static char buff[15]; 501 502 snprintf(buff, sizeof(buff), "%d.%d", neighbor->al_pv, neighbor->al_mv); 503 *var_len = strlen(buff); 504 return (u_char *)buff; 505 } 506 507 case dvmrpNeighborGenerationId: 508 long_return = neighbor->al_genid; 509 return (u_char *) &long_return; 510 511 default: 512 ERROR(""); 513 } 514 return NULL; 515 } 516 517 /* Look up ifIndex given uvifs[ifnum].uv_lcl_addr */ 518 struct in_ifaddr * /* returns: in_ifaddr structure, or null on error */ 519 ipaddr_to_ifindex(ipaddr, ifIndex) 520 u_long ipaddr; 521 int *ifIndex; 522 { 523 int interface; 524 static struct in_ifaddr in_ifaddr; 525 526 Interface_Scan_Init(); 527 for (;;) { 528 if (Interface_Scan_Next(&interface, (char *)0, NULL, &in_ifaddr) == 0) 529 return NULL; 530 531 if (((struct sockaddr_in *) &(in_ifaddr.ia_addr))->sin_addr.s_addr 532 == ipaddr) { 533 *ifIndex = interface; 534 return &in_ifaddr; 535 } 536 } 537 } 538 539 /* 540 * Find if a specific scoped boundary exists on a Vif 541 */ 542 struct listaddr * 543 find_cache(grp, vifi) 544 u_long grp; 545 vifi_t vifi; 546 { 547 struct listaddr *n; 548 549 for (n = uvifs[vifi].uv_groups; n != NULL; n = n->al_next) { 550 if (grp == n->al_addr) 551 return n; 552 } 553 return NULL; 554 } 555 556 /* 557 * Find the next group cache entry >= (A,V) spec 558 */ 559 struct listaddr * 560 next_cache(addr, vifi) 561 u_long addr; 562 vifi_t *vifi; 563 { 564 struct listaddr *bestn=NULL, *n; 565 int i, besti; 566 567 /* Step through all entries looking for the next one */ 568 for (i = 0; i < numvifs; i++) { 569 for (n = uvifs[i].uv_groups; n; n=n->al_next) { 570 if ((n->al_addr > addr || (n->al_addr == addr && i >= *vifi)) 571 && (!bestn || n->al_addr < bestn->al_addr 572 || (n->al_addr == bestn->al_addr && i < besti))) { 573 bestn = n; 574 besti = i; 575 } 576 } 577 } 578 579 if (bestn) { 580 *vifi = besti; 581 return bestn; 582 } 583 return NULL; 584 } 585 586 /* 587 * Implements the IGMP Cache Table portion of the IGMP MIB 588 */ 589 u_char * 590 o_igmpCacheTable(vp, name, length, exact, var_len, write_method) 591 struct variable *vp; /* IN - pointer to variable entry that points here */ 592 oid *name; /* IN/OUT - input name requested, output name found */ 593 int *length; /* IN/OUT - length of input and output oid's */ 594 int exact; /* IN - TRUE if an exact match was requested. */ 595 int *var_len; /* OUT - length of variable or 0 if function returned. */ 596 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 597 { 598 vifi_t vifi; 599 u_long grp; 600 int ifIndex; 601 struct listaddr *cache; 602 oid newname[MAX_NAME_LEN]; 603 int len; 604 struct in_ifaddr *in_ifaddr; 605 struct in_multi in_multi, *inm; 606 607 /* Copy name OID to new OID */ 608 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 609 610 if (exact) { 611 if (*length != vp->namelen + 5) 612 return NULL; 613 614 if ((vifi = name[vp->namelen+4]) >= numvifs) 615 return NULL; 616 617 if (!get_address(name, *length, &grp, vp->namelen)) 618 return NULL; 619 620 if (!(cache = find_cache(grp, vifi))) 621 return NULL; 622 623 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 624 } else { 625 len = *length; 626 if (compare(name, *length, vp->name, vp->namelen) < 0) 627 len = vp->namelen; 628 629 if (len < vp->namelen + 5) { /* get first entry */ 630 631 if (len == vp->namelen) { 632 vifi = grp = 0; 633 } else { 634 get_address(name, len, &grp, vp->namelen); 635 vifi = name[vp->namelen+4]; 636 } 637 638 cache = next_cache(grp,&vifi); 639 if (!cache) 640 return NULL; 641 642 put_address(newname, cache->al_addr, vp->namelen); 643 newname[vp->namelen+4] = vifi; 644 } else { /* get next entry given previous */ 645 get_address(name, *length, &grp, vp->namelen); 646 vifi = name[vp->namelen+4]+1; 647 648 if (!(cache = next_cache(grp,&vifi))) 649 return NULL; 650 651 put_address(newname, cache->al_addr, vp->namelen); 652 newname[vp->namelen+4] = vifi; 653 } 654 } 655 656 /* Save new OID */ 657 *length = vp->namelen + 5; 658 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 659 *write_method = 0; 660 *var_len = sizeof(long); 661 662 /* Look up ifIndex given uvifs[vifi].uv_lcl_addr */ 663 in_ifaddr = ipaddr_to_ifindex(uvifs[vifi].uv_lcl_addr, &ifIndex); 664 665 switch (vp->magic) { 666 667 case igmpCacheSelf: 668 inm = in_ifaddr->ia_multiaddrs; 669 while (inm) { 670 klookup( (int)inm, (char *)&in_multi, sizeof(in_multi)); 671 672 if (in_multi.inm_addr.s_addr == cache->al_addr) { 673 long_return = 1; /* true */ 674 return (u_char *) &long_return; 675 } 676 677 inm = in_multi.inm_next; 678 } 679 long_return = 2; /* false */ 680 return (u_char *) &long_return; 681 682 case igmpCacheLastReporter: 683 return (u_char *) &cache->al_genid; 684 685 case igmpCacheUpTime: { 686 time_t currtime; 687 time(&currtime); 688 long_return = (currtime - cache->al_ctime)*100; 689 return (u_char *) &long_return; 690 } 691 692 case igmpCacheExpiryTime: 693 long_return = secs_remaining(cache->al_timerid)*100; 694 return (u_char *) &long_return; 695 696 case igmpCacheStatus: 697 long_return = 1; 698 return (u_char *) &long_return; 699 700 default: 701 ERROR(""); 702 } 703 return NULL; 704 } 705 706 /* 707 * Implements the IGMP Interface Table portion of the IGMP MIB 708 */ 709 u_char * 710 o_igmpInterfaceTable(vp, name, length, exact, var_len, write_method) 711 struct variable *vp; /* IN - pointer to variable entry that points here */ 712 oid *name; /* IN/OUT - input name requested, output name found */ 713 int *length; /* IN/OUT - length of input and output oid's */ 714 int exact; /* IN - TRUE if an exact match was requested. */ 715 int *var_len; /* OUT - length of variable or 0 if function returned. */ 716 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 717 { 718 oid newname[MAX_NAME_LEN]; 719 int ifnum; 720 int result; 721 static struct sioc_vif_req v_req; 722 723 /* Copy name OID to new OID */ 724 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 725 726 /* find "next" interface */ 727 for(ifnum = 0; ifnum < numvifs; ifnum++){ 728 if (!(uvifs[ifnum].uv_flags & VIFF_QUERIER)) 729 continue; 730 newname[vp->namelen] = (oid)ifnum; 731 result = compare(name, *length, newname, (int)vp->namelen + 1); 732 if ((exact && (result == 0)) || (!exact && (result < 0))) 733 break; 734 } 735 if (ifnum >= numvifs) 736 return NULL; 737 738 /* Save new OID */ 739 bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid)); 740 *length = vp->namelen + 1; 741 *write_method = 0; 742 *var_len = sizeof(long); 743 744 switch (vp->magic){ 745 746 case igmpInterfaceQueryInterval: 747 long_return = GROUP_QUERY_INTERVAL; 748 return (u_char *) &long_return; 749 750 case igmpInterfaceStatus: 751 long_return = 1; /* active */ 752 return (u_char *) &long_return; 753 754 default: 755 ERROR(""); 756 } 757 return NULL; 758 } 759 760 /* 761 * Given a virtual interface number, make sure we have the current 762 * kernel information for that Vif. 763 */ 764 refresh_vif(v_req, ifnum) 765 struct sioc_vif_req *v_req; 766 int ifnum; 767 { 768 static int lastq = -1; 769 770 if (quantum!=lastq || v_req->vifi != ifnum) { 771 lastq = quantum; 772 v_req->vifi = ifnum; 773 if (ioctl(igmp_socket, SIOCGETVIFCNT, (char *)v_req) < 0) 774 v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0; 775 } 776 } 777 778 /* 779 * Implements the Multicast Routing Interface Table portion of the Multicast MIB 780 */ 781 u_char * 782 o_ipMRouteInterfaceTable(vp, name, length, exact, var_len, write_method) 783 struct variable *vp; /* IN - pointer to variable entry that points here */ 784 oid *name; /* IN/OUT - input name requested, output name found */ 785 int *length; /* IN/OUT - length of input and output oid's */ 786 int exact; /* IN - TRUE if an exact match was requested. */ 787 int *var_len; /* OUT - length of variable or 0 if function returned. */ 788 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 789 { 790 oid newname[MAX_NAME_LEN]; 791 int ifnum; 792 int result; 793 static struct sioc_vif_req v_req; 794 795 /* Copy name OID to new OID */ 796 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 797 798 /* find "next" interface */ 799 for(ifnum = 0; ifnum < numvifs; ifnum++){ 800 newname[vp->namelen] = (oid)ifnum; 801 result = compare(name, *length, newname, (int)vp->namelen + 1); 802 if ((exact && (result == 0)) || (!exact && (result < 0))) 803 break; 804 } 805 if (ifnum >= numvifs) 806 return NULL; 807 808 /* Save new OID */ 809 bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid)); 810 *length = vp->namelen + 1; 811 *write_method = 0; 812 *var_len = sizeof(long); 813 814 switch (vp->magic){ 815 816 case ipMRouteInterfaceTtl: 817 long_return = uvifs[ifnum].uv_threshold; 818 return (u_char *) &long_return; 819 820 case dvmrpVInterfaceType: 821 if (uvifs[ifnum].uv_flags & VIFF_SRCRT) 822 long_return = 2; 823 else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL) 824 long_return = 1; 825 else if (uvifs[ifnum].uv_flags & VIFF_QUERIER) 826 long_return = 3; 827 else /* SUBNET */ 828 long_return = 4; 829 return (u_char *) &long_return; 830 831 case dvmrpVInterfaceState: 832 if (uvifs[ifnum].uv_flags & VIFF_DISABLED) 833 long_return = 3; 834 else if ((uvifs[ifnum].uv_flags & VIFF_DOWN) 835 || ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) && (uvifs[ifnum].uv_neighbors==NULL))) 836 long_return = 2; 837 else /* UP */ 838 long_return = 1; 839 return (u_char *) &long_return; 840 841 case dvmrpVInterfaceLocalAddress: 842 return (u_char *) &uvifs[ifnum].uv_lcl_addr; 843 844 case dvmrpVInterfaceRemoteAddress: 845 return (u_char *) ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) ? 846 &uvifs[ifnum].uv_rmt_addr : 847 &uvifs[ifnum].uv_subnet); 848 849 case dvmrpVInterfaceRemoteSubnetMask: 850 return (u_char *) &uvifs[ifnum].uv_subnetmask; 851 852 case dvmrpVInterfaceMetric: 853 long_return = uvifs[ifnum].uv_metric; 854 return (u_char *) &long_return; 855 856 case dvmrpVInterfaceRateLimit: 857 long_return = uvifs[ifnum].uv_rate_limit; 858 return (u_char *) &long_return; 859 860 case dvmrpVInterfaceInPkts: 861 refresh_vif(&v_req, ifnum); 862 long_return = v_req.icount; 863 return (u_char *) &long_return; 864 865 case dvmrpVInterfaceOutPkts: 866 refresh_vif(&v_req, ifnum); 867 long_return = v_req.ocount; 868 return (u_char *) &long_return; 869 870 case dvmrpVInterfaceInOctets: 871 refresh_vif(&v_req, ifnum); 872 long_return = v_req.ibytes; 873 return (u_char *) &long_return; 874 875 case dvmrpVInterfaceOutOctets: 876 refresh_vif(&v_req, ifnum); 877 long_return = v_req.obytes; 878 return (u_char *) &long_return; 879 880 default: 881 ERROR(""); 882 } 883 return NULL; 884 } 885 886 /* 887 * Implements the DVMRP Route Table portion of the DVMRP MIB 888 */ 889 u_char * 890 o_dvmrpRouteTable(vp, name, length, exact, var_len, write_method) 891 struct variable *vp; /* IN - pointer to variable entry that points here */ 892 oid *name; /* IN/OUT - input name requested, output name found */ 893 int *length; /* IN/OUT - length of input and output oid's */ 894 int exact; /* IN - TRUE if an exact match was requested. */ 895 int *var_len; /* OUT - length of variable or 0 if function returned. */ 896 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 897 { 898 u_long src, mask; 899 oid newname[MAX_NAME_LEN]; 900 int len; 901 struct rtentry *rt = NULL; 902 903 /* Copy name OID to new OID */ 904 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 905 906 if (exact) { 907 if (*length != vp->namelen + 8) 908 return NULL; 909 910 if (!get_address(name, *length, &src, vp->namelen) 911 || !get_address(name, *length, &mask, vp->namelen+4)) 912 return NULL; 913 914 if (!(rt = snmp_find_route(src, mask))) 915 return NULL; 916 917 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 918 } else { 919 len = *length; 920 if (compare(name, *length, vp->name, vp->namelen) < 0) 921 len = vp->namelen; 922 923 if (len < vp->namelen + 8) { /* get first entry */ 924 925 if (len == vp->namelen) { 926 src = mask = 0; 927 } else { 928 get_address(name, len, &src, vp->namelen); 929 get_address(name, len, &mask, vp->namelen+4); 930 } 931 932 if (!next_route(&rt,src,mask)) /* Get first entry */ 933 return NULL; 934 935 put_address(newname, rt->rt_origin , vp->namelen); 936 put_address(newname, rt->rt_originmask, vp->namelen+4); 937 } else { /* get next entry given previous */ 938 get_address(name, *length, &src, vp->namelen); 939 get_address(name, *length, &mask, vp->namelen+4); 940 941 if (!next_route(&rt, src,mask)) 942 return NULL; 943 944 put_address(newname, rt->rt_origin, vp->namelen); 945 put_address(newname, rt->rt_originmask, vp->namelen+4); 946 } 947 } 948 949 /* Save new OID */ 950 *length = vp->namelen + 8; 951 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 952 *write_method = 0; 953 *var_len = sizeof(long); 954 955 switch (vp->magic) { 956 957 case dvmrpRouteUpstreamNeighbor: 958 return (u_char *) &rt->rt_gateway; 959 960 case dvmrpRouteInVifIndex: 961 long_return = rt->rt_parent; 962 return (u_char *) &long_return; 963 964 case dvmrpRouteMetric: 965 long_return = rt->rt_metric; 966 return (u_char *) &long_return; 967 968 case dvmrpRouteExpiryTime: 969 long_return = (ROUTE_EXPIRE_TIME - rt->rt_timer 970 + secs_remaining_offset()) * 100; 971 return (u_char *) &long_return; 972 973 default: 974 ERROR(""); 975 } 976 return NULL; 977 } 978 979 /* 980 * Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB 981 */ 982 u_char * 983 o_dvmrpRouteNextHopTable(vp, name, length, exact, var_len, write_method) 984 struct variable *vp; /* IN - pointer to variable entry that points here */ 985 oid *name; /* IN/OUT - input name requested, output name found */ 986 int *length; /* IN/OUT - length of input and output oid's */ 987 int exact; /* IN - TRUE if an exact match was requested. */ 988 int *var_len; /* OUT - length of variable or 0 if function returned. */ 989 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 990 { 991 u_long src, mask; 992 vifi_t vifi; 993 struct rtentry *rt = NULL; 994 oid newname[MAX_NAME_LEN]; 995 int len; 996 997 /* Copy name OID to new OID */ 998 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 999 1000 if (exact) { 1001 if (*length != vp->namelen + 9) 1002 return NULL; 1003 1004 if (!get_address(name, *length, &src, vp->namelen) 1005 || !get_address(name, *length, &mask, vp->namelen+4) 1006 || (!(rt=snmp_find_route(src,mask)))) 1007 return NULL; 1008 1009 vifi = name[vp->namelen+8]; 1010 if (!(VIFM_ISSET(vifi, rt->rt_children))) 1011 return NULL; 1012 1013 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 1014 } else { 1015 len = *length; 1016 if (compare(name, *length, vp->name, vp->namelen) < 0) 1017 len = vp->namelen; 1018 1019 if (len < vp->namelen + 9) { /* get first entry */ 1020 1021 get_address(name, len, &src, vp->namelen); 1022 get_address(name, len, &mask, vp->namelen+4); 1023 1024 /* Find first child vif */ 1025 vifi=0; 1026 if (!next_route_child(&rt, src, mask, &vifi)) 1027 return NULL; 1028 1029 put_address(newname, rt->rt_origin, vp->namelen); 1030 put_address(newname, rt->rt_originmask, vp->namelen+4); 1031 newname[vp->namelen+8] = vifi; 1032 } else { /* get next entry given previous */ 1033 vifi = name[vp->namelen+8] + 1; 1034 if (!get_address(name, *length, &src, vp->namelen) 1035 || !get_address(name, *length, &mask, vp->namelen+4) 1036 || !next_route_child(&rt, src, mask, &vifi)) 1037 return NULL; 1038 1039 put_address(newname, rt->rt_origin, vp->namelen); 1040 put_address(newname, rt->rt_originmask, vp->namelen+4); 1041 newname[vp->namelen+8] = vifi; 1042 } 1043 } 1044 1045 /* Save new OID */ 1046 *length = vp->namelen + 9; 1047 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 1048 *write_method = 0; 1049 *var_len = sizeof(long); 1050 1051 switch (vp->magic) { 1052 1053 case dvmrpRouteNextHopType: 1054 long_return = (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2; 1055 return (u_char *) &long_return; 1056 1057 default: 1058 ERROR(""); 1059 } 1060 return NULL; 1061 } 1062 1063 /* 1064 * Implements the IP Multicast Route Table portion of the Multicast MIB 1065 */ 1066 u_char * 1067 o_ipMRouteTable(vp, name, length, exact, var_len, write_method) 1068 struct variable *vp; /* IN - pointer to variable entry that points here */ 1069 oid *name; /* IN/OUT - input name requested, output name found */ 1070 int *length; /* IN/OUT - length of input and output oid's */ 1071 int exact; /* IN - TRUE if an exact match was requested. */ 1072 int *var_len; /* OUT - length of variable or 0 if function returned. */ 1073 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 1074 { 1075 u_long src, grp, mask; 1076 struct gtable *gt = NULL; 1077 struct stable *st = NULL; 1078 static struct sioc_sg_req sg_req; 1079 oid newname[MAX_NAME_LEN]; 1080 int len; 1081 1082 /* Copy name OID to new OID */ 1083 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 1084 1085 if (exact) { 1086 if (*length != vp->namelen + 12) 1087 return NULL; 1088 1089 if (!get_address(name, *length, &grp, vp->namelen) 1090 || !get_address(name, *length, &src, vp->namelen+4) 1091 || !get_address(name, *length, &mask, vp->namelen+8) 1092 || (mask != 0xFFFFFFFF) /* we keep sources now, not subnets */ 1093 || !(gt = find_grp(grp)) 1094 || !(st = find_grp_src(gt,src))) 1095 return NULL; 1096 1097 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 1098 } else { 1099 len = *length; 1100 if (compare(name, *length, vp->name, vp->namelen) < 0) 1101 len = vp->namelen; 1102 1103 if (len < vp->namelen + 12) { /* get first entry */ 1104 1105 get_address(name, len, &grp, vp->namelen); 1106 get_address(name, len, &src, vp->namelen+4); 1107 get_address(name, len, &mask, vp->namelen+8); 1108 1109 if (!next_grp_src_mask(>,&st,grp,src,mask)) /* Get first entry */ 1110 return NULL; 1111 1112 put_address(newname, gt->gt_mcastgrp, vp->namelen); 1113 put_address(newname, st->st_origin, vp->namelen+4); 1114 put_address(newname, 0xFFFFFFFF, vp->namelen+8); 1115 } else { /* get next entry given previous */ 1116 get_address(name, *length, &grp , vp->namelen); 1117 get_address(name, *length, &src , vp->namelen+4); 1118 get_address(name, *length, &mask, vp->namelen+8); 1119 1120 if (!next_grp_src_mask(>, &st, grp,src,mask)) 1121 return NULL; 1122 1123 put_address(newname, gt->gt_mcastgrp, vp->namelen); 1124 put_address(newname, st->st_origin, vp->namelen+4); 1125 put_address(newname, 0xFFFFFFFF, vp->namelen+8); 1126 } 1127 } 1128 1129 /* Save new OID */ 1130 *length = vp->namelen + 12; 1131 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 1132 *write_method = 0; 1133 *var_len = sizeof(long); 1134 1135 switch (vp->magic) { 1136 1137 case ipMRouteUpstreamNeighbor: 1138 return (u_char *) >->gt_route->rt_gateway; 1139 1140 case ipMRouteInIfIndex: 1141 long_return = gt->gt_route->rt_parent; 1142 return (u_char *) &long_return; 1143 1144 case ipMRouteUpTime: { 1145 time_t currtime; 1146 time(&currtime); 1147 long_return = (currtime - gt->gt_ctime)*100; 1148 return (u_char *) &long_return; 1149 } 1150 1151 case ipMRouteExpiryTime: 1152 long_return = 5*((gt->gt_timer+4)/5); /* round up to nearest 5 */ 1153 long_return = (long_return + secs_remaining_offset()) * 100; 1154 return (u_char *) &long_return; 1155 1156 case ipMRoutePkts: 1157 refresh_sg(&sg_req, gt, st); 1158 long_return = sg_req.pktcnt; 1159 return (u_char *) &long_return; 1160 1161 case ipMRouteOctets: 1162 refresh_sg(&sg_req, gt, st); 1163 long_return = sg_req.bytecnt; 1164 return (u_char *) &long_return; 1165 1166 case ipMRouteDifferentInIfIndexes: 1167 refresh_sg(&sg_req, gt, st); 1168 long_return = sg_req.wrong_if; 1169 return (u_char *) &long_return; 1170 1171 case ipMRouteProtocol: 1172 long_return = 4; 1173 return (u_char *) &long_return; 1174 1175 default: 1176 ERROR(""); 1177 } 1178 return NULL; 1179 } 1180 1181 /* 1182 * Implements the IP Multicast Routing Next Hop Table portion of the Multicast 1183 * MIB 1184 */ 1185 u_char * 1186 o_ipMRouteNextHopTable(vp, name, length, exact, var_len, write_method) 1187 struct variable *vp; /* IN - pointer to variable entry that points here */ 1188 oid *name; /* IN/OUT - input name requested, output name found */ 1189 int *length; /* IN/OUT - length of input and output oid's */ 1190 int exact; /* IN - TRUE if an exact match was requested. */ 1191 int *var_len; /* OUT - length of variable or 0 if function returned. */ 1192 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 1193 { 1194 u_long src, grp, mask, addr; 1195 vifi_t vifi; 1196 struct gtable *gt; 1197 struct stable *st; 1198 oid newname[MAX_NAME_LEN]; 1199 int len; 1200 1201 /* Copy name OID to new OID */ 1202 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 1203 1204 if (exact) { 1205 if (*length != vp->namelen + 17) 1206 return NULL; 1207 1208 if (!get_address(name, *length, &grp, vp->namelen) 1209 || !get_address(name, *length, &src, vp->namelen+4) 1210 || !get_address(name, *length, &mask, vp->namelen+8) 1211 || !get_address(name, *length, &addr, vp->namelen+13) 1212 || grp!=addr 1213 || mask!=0xFFFFFFFF 1214 || (!(gt=find_grp(grp))) 1215 || (!(st=find_grp_src(gt,src)))) 1216 return NULL; 1217 1218 vifi = name[vp->namelen+12]; 1219 if (!(VIFM_ISSET(vifi, gt->gt_route->rt_children))) 1220 return NULL; 1221 1222 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 1223 } else { 1224 len = *length; 1225 if (compare(name, *length, vp->name, vp->namelen) < 0) 1226 len = vp->namelen; 1227 1228 if (len < vp->namelen + 17) { /* get first entry */ 1229 1230 get_address(name, len, &grp, vp->namelen); 1231 get_address(name, len, &src, vp->namelen+4); 1232 get_address(name, len, &mask, vp->namelen+8); 1233 1234 /* Find first child vif */ 1235 vifi=0; 1236 if (!next_child(>, &st, grp, src, mask, &vifi)) 1237 return NULL; 1238 1239 put_address(newname, gt->gt_mcastgrp, vp->namelen); 1240 put_address(newname, st->st_origin, vp->namelen+4); 1241 put_address(newname, 0xFFFFFFFF, vp->namelen+8); 1242 newname[vp->namelen+12] = vifi; 1243 put_address(newname, gt->gt_mcastgrp, vp->namelen+13); 1244 1245 } else { /* get next entry given previous */ 1246 vifi = name[vp->namelen+12]+1; 1247 if (!get_address(name, *length, &grp, vp->namelen) 1248 || !get_address(name, *length, &src, vp->namelen+4) 1249 || !get_address(name, *length, &mask, vp->namelen+8) 1250 || !next_child(>, &st, grp, src, mask, &vifi)) 1251 return NULL; 1252 1253 put_address(newname, gt->gt_mcastgrp, vp->namelen); 1254 put_address(newname, st->st_origin, vp->namelen+4); 1255 put_address(newname, 0xFFFFFFFF, vp->namelen+8); 1256 newname[vp->namelen+12] = vifi; 1257 put_address(newname, gt->gt_mcastgrp, vp->namelen+13); 1258 } 1259 } 1260 1261 /* Save new OID */ 1262 *length = vp->namelen + 17; 1263 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 1264 *write_method = 0; 1265 *var_len = sizeof(long); 1266 1267 switch (vp->magic) { 1268 1269 case ipMRouteNextHopState: 1270 long_return = (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1; 1271 return (u_char *) &long_return; 1272 1273 /* Currently equal to ipMRouteUpTime */ 1274 case ipMRouteNextHopUpTime: { 1275 time_t currtime; 1276 time(&currtime); 1277 long_return = (currtime - gt->gt_ctime)*100; 1278 return (u_char *) &long_return; 1279 } 1280 1281 case ipMRouteNextHopExpiryTime: 1282 long_return = 5*((gt->gt_prsent_timer+4)/5); /* round up to nearest 5*/ 1283 long_return = (long_return + secs_remaining_offset()) * 100; 1284 return (u_char *) &long_return; 1285 1286 case ipMRouteNextHopClosestMemberHops: 1287 long_return = 0; 1288 return (u_char *) &long_return; 1289 1290 case ipMRouteNextHopProtocol: 1291 long_return = 4; 1292 return (u_char *) &long_return; 1293 1294 default: 1295 ERROR(""); 1296 } 1297 return NULL; 1298 } 1299 1300 /* sync_timer is called by timer() every TIMER_INTERVAL seconds. 1301 * Its job is to record this time so that we can compute on demand 1302 * the approx # seconds remaining until the next timer() call 1303 */ 1304 static time_t lasttimer; 1305 1306 void 1307 sync_timer() 1308 { 1309 time(&lasttimer); 1310 } 1311 1312 int /* in range [-TIMER_INTERVAL..0] */ 1313 secs_remaining_offset() 1314 { 1315 time_t tm; 1316 1317 time(&tm); 1318 return lasttimer-tm; 1319 } 1320