1 /* $NetBSD: snmp.c,v 1.10 2003/03/05 21:12:26 wiz 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 sprintf(buff, "mrouted%d.%d", PROTOCOL_VERSION, MROUTED_VERSION); 220 *var_len = strlen(buff); 221 return (u_char *)buff; 222 } 223 224 case dvmrpGenerationId: 225 long_return = dvmrp_genid; 226 return (u_char *) &long_return; 227 228 default: 229 ERROR(""); 230 } 231 return NULL; 232 } 233 234 /* 235 * Find if a specific scoped boundary exists on a Vif 236 */ 237 struct vif_acl * 238 find_boundary(vifi, addr, mask) 239 vifi_t vifi; 240 u_long addr; 241 u_long mask; 242 { 243 struct vif_acl *n; 244 245 for (n = uvifs[vifi].uv_acl; n != NULL; n = n->acl_next) { 246 if (addr == n->acl_addr && mask==n->acl_mask) 247 return n; 248 } 249 return NULL; 250 } 251 252 /* 253 * Find the lowest boundary >= (V,A,M) spec 254 */ 255 struct vif_acl * 256 next_boundary(vifi, addr, mask) 257 vifi_t *vifi; 258 u_long addr; 259 u_long mask; 260 { 261 struct vif_acl *bestn, *n; 262 int i; 263 264 for (i = *vifi; i < numvifs; i++) { 265 bestn = NULL; 266 for (n = uvifs[i].uv_acl; n; n=n->acl_next) { 267 if ((i > *vifi || n->acl_addr > addr 268 || (n->acl_addr == addr && n->acl_mask >= mask)) 269 && (!bestn || n->acl_addr < bestn->acl_addr 270 || (n->acl_addr==bestn->acl_addr && n->acl_mask<bestn->acl_mask))) 271 bestn = n; 272 } 273 if (bestn) { 274 *vifi = i; 275 return bestn; 276 } 277 } 278 return NULL; 279 } 280 281 /* 282 * Implements the Boundary Table portion of the DVMRP MIB 283 */ 284 u_char * 285 o_dvmrpBoundaryTable(vp, name, length, exact, var_len, write_method) 286 struct variable *vp; /* IN - pointer to variable entry that points here */ 287 oid *name; /* IN/OUT - input name requested, output name found */ 288 int *length; /* IN/OUT - length of input and output oid's */ 289 int exact; /* IN - TRUE if an exact match was requested. */ 290 int *var_len; /* OUT - length of variable or 0 if function returned. */ 291 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 292 { 293 vifi_t vifi; 294 u_long addr, mask; 295 struct vif_acl *bound; 296 oid newname[MAX_NAME_LEN]; 297 int len; 298 299 /* Copy name OID to new OID */ 300 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 301 302 if (exact) { 303 if (*length != vp->namelen + 9) 304 return NULL; 305 306 if ((vifi = name[vp->namelen]) >= numvifs) 307 return NULL; 308 309 if (!get_address(name, *length, &addr, vp->namelen+1) 310 || !get_address(name, *length, &mask, vp->namelen+5)) 311 return NULL; 312 313 if (!(bound = find_boundary(vifi, addr, mask))) 314 return NULL; 315 316 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 317 } else { 318 len = *length; 319 if (compare(name, *length, vp->name, vp->namelen) < 0) 320 len = vp->namelen; 321 322 if (len < vp->namelen + 9) { /* get first entry */ 323 324 if (len == vp->namelen) { 325 vifi = addr = mask = 0; 326 } else { 327 vifi = name[vp->namelen]; 328 get_address(name, len, &addr, vp->namelen+1); 329 get_address(name, len, &mask, vp->namelen+5); 330 } 331 332 bound = next_boundary(&vifi,addr,mask); 333 if (!bound) 334 return NULL; 335 336 newname[vp->namelen] = vifi; 337 put_address(newname, bound->acl_addr, vp->namelen+1); 338 put_address(newname, bound->acl_mask, vp->namelen+5); 339 } else { /* get next entry given previous */ 340 vifi = name[vp->namelen]; 341 get_address(name, *length, &addr, vp->namelen+1); 342 get_address(name, *length, &mask, vp->namelen+5); 343 344 if (!(bound = next_boundary(&vifi,addr,mask+1))) 345 return NULL; 346 347 newname[vp->namelen] = vifi; 348 put_address(newname, bound->acl_addr, vp->namelen+1); 349 put_address(newname, bound->acl_mask, vp->namelen+5); 350 } 351 } 352 353 /* Save new OID */ 354 *length = vp->namelen + 9; 355 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 356 *write_method = 0; 357 *var_len = sizeof(long); 358 359 switch (vp->magic) { 360 361 case dvmrpBoundaryVifIndex: 362 long_return = vifi; 363 return (u_char *) &long_return; 364 365 default: 366 ERROR(""); 367 } 368 return NULL; 369 } 370 371 /* 372 * Find the lowest neighbor >= (V,A) spec 373 */ 374 struct listaddr * 375 next_neighbor(vifi, addr) 376 vifi_t *vifi; 377 u_long addr; 378 { 379 struct listaddr *bestn, *n; 380 int i; 381 382 for (i = *vifi; i < numvifs; i++) { 383 bestn = NULL; 384 for (n = uvifs[i].uv_neighbors; n; n=n->al_next) { 385 if ((i > *vifi || n->al_addr >= addr) 386 && (!bestn || n->al_addr < bestn->al_addr)) 387 bestn = n; 388 } 389 if (bestn) { 390 *vifi = i; 391 return bestn; 392 } 393 } 394 return NULL; 395 } 396 397 /* 398 * Find a neighbor, if it exists off a given Vif 399 */ 400 struct listaddr * 401 find_neighbor(vifi, addr) 402 vifi_t vifi; 403 u_long addr; 404 { 405 struct listaddr *n; 406 407 for (n = uvifs[vifi].uv_neighbors; n != NULL; n = n->al_next) { 408 if (addr == n->al_addr) 409 return n; 410 } 411 return NULL; 412 } 413 414 u_char * 415 o_dvmrpNeighborTable(vp, name, length, exact, var_len, write_method) 416 struct variable *vp; /* IN - pointer to variable entry that points here */ 417 oid *name; /* IN/OUT - input name requested, output name found */ 418 int *length; /* IN/OUT - length of input and output oid's */ 419 int exact; /* IN - TRUE if an exact match was requested. */ 420 int *var_len; /* OUT - length of variable or 0 if function returned. */ 421 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 422 { 423 vifi_t vifi; 424 u_long addr, mask; 425 struct listaddr *neighbor; 426 oid newname[MAX_NAME_LEN]; 427 int len; 428 429 /* Copy name OID to new OID */ 430 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 431 432 if (exact) { 433 if (*length != vp->namelen + 5) 434 return NULL; 435 436 if ((vifi = name[vp->namelen]) >= numvifs) 437 return NULL; 438 439 if (!get_address(name, *length, &addr, vp->namelen+1)) 440 return NULL; 441 442 if (!(neighbor = find_neighbor(vifi, addr))) 443 return NULL; 444 445 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 446 } else { 447 len = *length; 448 if (compare(name, *length, vp->name, vp->namelen) < 0) 449 len = vp->namelen; 450 451 if (len < vp->namelen + 5) { /* get first entry */ 452 453 if (len == vp->namelen) { 454 vifi = addr = 0; 455 } else { 456 vifi = name[vp->namelen]; 457 get_address(name, len, &addr, vp->namelen+1); 458 } 459 460 neighbor = next_neighbor(&vifi,addr); 461 if (!neighbor) 462 return NULL; 463 464 newname[vp->namelen] = vifi; 465 put_address(newname, neighbor->al_addr, vp->namelen+1); 466 } else { /* get next entry given previous */ 467 vifi = name[vp->namelen]; 468 get_address(name, *length, &addr, vp->namelen+1); 469 470 if (!(neighbor = next_neighbor(&vifi,addr+1))) 471 return NULL; 472 473 newname[vp->namelen] = vifi; 474 put_address(newname, neighbor->al_addr, vp->namelen+1); 475 } 476 } 477 478 /* Save new OID */ 479 *length = vp->namelen + 5; 480 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 481 *write_method = 0; 482 *var_len = sizeof(long); 483 484 switch (vp->magic) { 485 486 case dvmrpNeighborUpTime: { 487 time_t currtime; 488 time(&currtime); 489 long_return = (currtime - neighbor->al_ctime)*100; 490 return (u_char *) &long_return; 491 } 492 493 case dvmrpNeighborExpiryTime: 494 long_return = (NEIGHBOR_EXPIRE_TIME - neighbor->al_timer 495 + secs_remaining_offset()) * 100; 496 return (u_char *) &long_return; 497 498 case dvmrpNeighborVersion: { 499 static char buff[15]; 500 501 sprintf(buff, "%d.%d", neighbor->al_pv, neighbor->al_mv); 502 *var_len = strlen(buff); 503 return (u_char *)buff; 504 } 505 506 case dvmrpNeighborGenerationId: 507 long_return = neighbor->al_genid; 508 return (u_char *) &long_return; 509 510 default: 511 ERROR(""); 512 } 513 return NULL; 514 } 515 516 /* Look up ifIndex given uvifs[ifnum].uv_lcl_addr */ 517 struct in_ifaddr * /* returns: in_ifaddr structure, or null on error */ 518 ipaddr_to_ifindex(ipaddr, ifIndex) 519 u_long ipaddr; 520 int *ifIndex; 521 { 522 int interface; 523 static struct in_ifaddr in_ifaddr; 524 525 Interface_Scan_Init(); 526 for (;;) { 527 if (Interface_Scan_Next(&interface, (char *)0, NULL, &in_ifaddr) == 0) 528 return NULL; 529 530 if (((struct sockaddr_in *) &(in_ifaddr.ia_addr))->sin_addr.s_addr 531 == ipaddr) { 532 *ifIndex = interface; 533 return &in_ifaddr; 534 } 535 } 536 } 537 538 /* 539 * Find if a specific scoped boundary exists on a Vif 540 */ 541 struct listaddr * 542 find_cache(grp, vifi) 543 u_long grp; 544 vifi_t vifi; 545 { 546 struct listaddr *n; 547 548 for (n = uvifs[vifi].uv_groups; n != NULL; n = n->al_next) { 549 if (grp == n->al_addr) 550 return n; 551 } 552 return NULL; 553 } 554 555 /* 556 * Find the next group cache entry >= (A,V) spec 557 */ 558 struct listaddr * 559 next_cache(addr, vifi) 560 u_long addr; 561 vifi_t *vifi; 562 { 563 struct listaddr *bestn=NULL, *n; 564 int i, besti; 565 566 /* Step through all entries looking for the next one */ 567 for (i = 0; i < numvifs; i++) { 568 for (n = uvifs[i].uv_groups; n; n=n->al_next) { 569 if ((n->al_addr > addr || (n->al_addr == addr && i >= *vifi)) 570 && (!bestn || n->al_addr < bestn->al_addr 571 || (n->al_addr == bestn->al_addr && i < besti))) { 572 bestn = n; 573 besti = i; 574 } 575 } 576 } 577 578 if (bestn) { 579 *vifi = besti; 580 return bestn; 581 } 582 return NULL; 583 } 584 585 /* 586 * Implements the IGMP Cache Table portion of the IGMP MIB 587 */ 588 u_char * 589 o_igmpCacheTable(vp, name, length, exact, var_len, write_method) 590 struct variable *vp; /* IN - pointer to variable entry that points here */ 591 oid *name; /* IN/OUT - input name requested, output name found */ 592 int *length; /* IN/OUT - length of input and output oid's */ 593 int exact; /* IN - TRUE if an exact match was requested. */ 594 int *var_len; /* OUT - length of variable or 0 if function returned. */ 595 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 596 { 597 vifi_t vifi; 598 u_long grp; 599 int ifIndex; 600 struct listaddr *cache; 601 oid newname[MAX_NAME_LEN]; 602 int len; 603 struct in_ifaddr *in_ifaddr; 604 struct in_multi in_multi, *inm; 605 606 /* Copy name OID to new OID */ 607 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 608 609 if (exact) { 610 if (*length != vp->namelen + 5) 611 return NULL; 612 613 if ((vifi = name[vp->namelen+4]) >= numvifs) 614 return NULL; 615 616 if (!get_address(name, *length, &grp, vp->namelen)) 617 return NULL; 618 619 if (!(cache = find_cache(grp, vifi))) 620 return NULL; 621 622 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 623 } else { 624 len = *length; 625 if (compare(name, *length, vp->name, vp->namelen) < 0) 626 len = vp->namelen; 627 628 if (len < vp->namelen + 5) { /* get first entry */ 629 630 if (len == vp->namelen) { 631 vifi = grp = 0; 632 } else { 633 get_address(name, len, &grp, vp->namelen); 634 vifi = name[vp->namelen+4]; 635 } 636 637 cache = next_cache(grp,&vifi); 638 if (!cache) 639 return NULL; 640 641 put_address(newname, cache->al_addr, vp->namelen); 642 newname[vp->namelen+4] = vifi; 643 } else { /* get next entry given previous */ 644 get_address(name, *length, &grp, vp->namelen); 645 vifi = name[vp->namelen+4]+1; 646 647 if (!(cache = next_cache(grp,&vifi))) 648 return NULL; 649 650 put_address(newname, cache->al_addr, vp->namelen); 651 newname[vp->namelen+4] = vifi; 652 } 653 } 654 655 /* Save new OID */ 656 *length = vp->namelen + 5; 657 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 658 *write_method = 0; 659 *var_len = sizeof(long); 660 661 /* Look up ifIndex given uvifs[vifi].uv_lcl_addr */ 662 in_ifaddr = ipaddr_to_ifindex(uvifs[vifi].uv_lcl_addr, &ifIndex); 663 664 switch (vp->magic) { 665 666 case igmpCacheSelf: 667 inm = in_ifaddr->ia_multiaddrs; 668 while (inm) { 669 klookup( (int)inm, (char *)&in_multi, sizeof(in_multi)); 670 671 if (in_multi.inm_addr.s_addr == cache->al_addr) { 672 long_return = 1; /* true */ 673 return (u_char *) &long_return; 674 } 675 676 inm = in_multi.inm_next; 677 } 678 long_return = 2; /* false */ 679 return (u_char *) &long_return; 680 681 case igmpCacheLastReporter: 682 return (u_char *) &cache->al_genid; 683 684 case igmpCacheUpTime: { 685 time_t currtime; 686 time(&currtime); 687 long_return = (currtime - cache->al_ctime)*100; 688 return (u_char *) &long_return; 689 } 690 691 case igmpCacheExpiryTime: 692 long_return = secs_remaining(cache->al_timerid)*100; 693 return (u_char *) &long_return; 694 695 case igmpCacheStatus: 696 long_return = 1; 697 return (u_char *) &long_return; 698 699 default: 700 ERROR(""); 701 } 702 return NULL; 703 } 704 705 /* 706 * Implements the IGMP Interface Table portion of the IGMP MIB 707 */ 708 u_char * 709 o_igmpInterfaceTable(vp, name, length, exact, var_len, write_method) 710 struct variable *vp; /* IN - pointer to variable entry that points here */ 711 oid *name; /* IN/OUT - input name requested, output name found */ 712 int *length; /* IN/OUT - length of input and output oid's */ 713 int exact; /* IN - TRUE if an exact match was requested. */ 714 int *var_len; /* OUT - length of variable or 0 if function returned. */ 715 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 716 { 717 oid newname[MAX_NAME_LEN]; 718 int ifnum; 719 int result; 720 static struct sioc_vif_req v_req; 721 722 /* Copy name OID to new OID */ 723 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 724 725 /* find "next" interface */ 726 for(ifnum = 0; ifnum < numvifs; ifnum++){ 727 if (!(uvifs[ifnum].uv_flags & VIFF_QUERIER)) 728 continue; 729 newname[vp->namelen] = (oid)ifnum; 730 result = compare(name, *length, newname, (int)vp->namelen + 1); 731 if ((exact && (result == 0)) || (!exact && (result < 0))) 732 break; 733 } 734 if (ifnum >= numvifs) 735 return NULL; 736 737 /* Save new OID */ 738 bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid)); 739 *length = vp->namelen + 1; 740 *write_method = 0; 741 *var_len = sizeof(long); 742 743 switch (vp->magic){ 744 745 case igmpInterfaceQueryInterval: 746 long_return = GROUP_QUERY_INTERVAL; 747 return (u_char *) &long_return; 748 749 case igmpInterfaceStatus: 750 long_return = 1; /* active */ 751 return (u_char *) &long_return; 752 753 default: 754 ERROR(""); 755 } 756 return NULL; 757 } 758 759 /* 760 * Given a virtual interface number, make sure we have the current 761 * kernel information for that Vif. 762 */ 763 refresh_vif(v_req, ifnum) 764 struct sioc_vif_req *v_req; 765 int ifnum; 766 { 767 static int lastq = -1; 768 769 if (quantum!=lastq || v_req->vifi != ifnum) { 770 lastq = quantum; 771 v_req->vifi = ifnum; 772 if (ioctl(igmp_socket, SIOCGETVIFCNT, (char *)v_req) < 0) 773 v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0; 774 } 775 } 776 777 /* 778 * Implements the Multicast Routing Interface Table portion of the Multicast MIB 779 */ 780 u_char * 781 o_ipMRouteInterfaceTable(vp, name, length, exact, var_len, write_method) 782 struct variable *vp; /* IN - pointer to variable entry that points here */ 783 oid *name; /* IN/OUT - input name requested, output name found */ 784 int *length; /* IN/OUT - length of input and output oid's */ 785 int exact; /* IN - TRUE if an exact match was requested. */ 786 int *var_len; /* OUT - length of variable or 0 if function returned. */ 787 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 788 { 789 oid newname[MAX_NAME_LEN]; 790 int ifnum; 791 int result; 792 static struct sioc_vif_req v_req; 793 794 /* Copy name OID to new OID */ 795 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 796 797 /* find "next" interface */ 798 for(ifnum = 0; ifnum < numvifs; ifnum++){ 799 newname[vp->namelen] = (oid)ifnum; 800 result = compare(name, *length, newname, (int)vp->namelen + 1); 801 if ((exact && (result == 0)) || (!exact && (result < 0))) 802 break; 803 } 804 if (ifnum >= numvifs) 805 return NULL; 806 807 /* Save new OID */ 808 bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid)); 809 *length = vp->namelen + 1; 810 *write_method = 0; 811 *var_len = sizeof(long); 812 813 switch (vp->magic){ 814 815 case ipMRouteInterfaceTtl: 816 long_return = uvifs[ifnum].uv_threshold; 817 return (u_char *) &long_return; 818 819 case dvmrpVInterfaceType: 820 if (uvifs[ifnum].uv_flags & VIFF_SRCRT) 821 long_return = 2; 822 else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL) 823 long_return = 1; 824 else if (uvifs[ifnum].uv_flags & VIFF_QUERIER) 825 long_return = 3; 826 else /* SUBNET */ 827 long_return = 4; 828 return (u_char *) &long_return; 829 830 case dvmrpVInterfaceState: 831 if (uvifs[ifnum].uv_flags & VIFF_DISABLED) 832 long_return = 3; 833 else if ((uvifs[ifnum].uv_flags & VIFF_DOWN) 834 || ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) && (uvifs[ifnum].uv_neighbors==NULL))) 835 long_return = 2; 836 else /* UP */ 837 long_return = 1; 838 return (u_char *) &long_return; 839 840 case dvmrpVInterfaceLocalAddress: 841 return (u_char *) &uvifs[ifnum].uv_lcl_addr; 842 843 case dvmrpVInterfaceRemoteAddress: 844 return (u_char *) ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) ? 845 &uvifs[ifnum].uv_rmt_addr : 846 &uvifs[ifnum].uv_subnet); 847 848 case dvmrpVInterfaceRemoteSubnetMask: 849 return (u_char *) &uvifs[ifnum].uv_subnetmask; 850 851 case dvmrpVInterfaceMetric: 852 long_return = uvifs[ifnum].uv_metric; 853 return (u_char *) &long_return; 854 855 case dvmrpVInterfaceRateLimit: 856 long_return = uvifs[ifnum].uv_rate_limit; 857 return (u_char *) &long_return; 858 859 case dvmrpVInterfaceInPkts: 860 refresh_vif(&v_req, ifnum); 861 long_return = v_req.icount; 862 return (u_char *) &long_return; 863 864 case dvmrpVInterfaceOutPkts: 865 refresh_vif(&v_req, ifnum); 866 long_return = v_req.ocount; 867 return (u_char *) &long_return; 868 869 case dvmrpVInterfaceInOctets: 870 refresh_vif(&v_req, ifnum); 871 long_return = v_req.ibytes; 872 return (u_char *) &long_return; 873 874 case dvmrpVInterfaceOutOctets: 875 refresh_vif(&v_req, ifnum); 876 long_return = v_req.obytes; 877 return (u_char *) &long_return; 878 879 default: 880 ERROR(""); 881 } 882 return NULL; 883 } 884 885 /* 886 * Implements the DVMRP Route Table portion of the DVMRP MIB 887 */ 888 u_char * 889 o_dvmrpRouteTable(vp, name, length, exact, var_len, write_method) 890 struct variable *vp; /* IN - pointer to variable entry that points here */ 891 oid *name; /* IN/OUT - input name requested, output name found */ 892 int *length; /* IN/OUT - length of input and output oid's */ 893 int exact; /* IN - TRUE if an exact match was requested. */ 894 int *var_len; /* OUT - length of variable or 0 if function returned. */ 895 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 896 { 897 u_long src, mask; 898 oid newname[MAX_NAME_LEN]; 899 int len; 900 struct rtentry *rt = NULL; 901 902 /* Copy name OID to new OID */ 903 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 904 905 if (exact) { 906 if (*length != vp->namelen + 8) 907 return NULL; 908 909 if (!get_address(name, *length, &src, vp->namelen) 910 || !get_address(name, *length, &mask, vp->namelen+4)) 911 return NULL; 912 913 if (!(rt = snmp_find_route(src, mask))) 914 return NULL; 915 916 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 917 } else { 918 len = *length; 919 if (compare(name, *length, vp->name, vp->namelen) < 0) 920 len = vp->namelen; 921 922 if (len < vp->namelen + 8) { /* get first entry */ 923 924 if (len == vp->namelen) { 925 src = mask = 0; 926 } else { 927 get_address(name, len, &src, vp->namelen); 928 get_address(name, len, &mask, vp->namelen+4); 929 } 930 931 if (!next_route(&rt,src,mask)) /* Get first entry */ 932 return NULL; 933 934 put_address(newname, rt->rt_origin , vp->namelen); 935 put_address(newname, rt->rt_originmask, vp->namelen+4); 936 } else { /* get next entry given previous */ 937 get_address(name, *length, &src, vp->namelen); 938 get_address(name, *length, &mask, vp->namelen+4); 939 940 if (!next_route(&rt, src,mask)) 941 return NULL; 942 943 put_address(newname, rt->rt_origin, vp->namelen); 944 put_address(newname, rt->rt_originmask, vp->namelen+4); 945 } 946 } 947 948 /* Save new OID */ 949 *length = vp->namelen + 8; 950 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 951 *write_method = 0; 952 *var_len = sizeof(long); 953 954 switch (vp->magic) { 955 956 case dvmrpRouteUpstreamNeighbor: 957 return (u_char *) &rt->rt_gateway; 958 959 case dvmrpRouteInVifIndex: 960 long_return = rt->rt_parent; 961 return (u_char *) &long_return; 962 963 case dvmrpRouteMetric: 964 long_return = rt->rt_metric; 965 return (u_char *) &long_return; 966 967 case dvmrpRouteExpiryTime: 968 long_return = (ROUTE_EXPIRE_TIME - rt->rt_timer 969 + secs_remaining_offset()) * 100; 970 return (u_char *) &long_return; 971 972 default: 973 ERROR(""); 974 } 975 return NULL; 976 } 977 978 /* 979 * Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB 980 */ 981 u_char * 982 o_dvmrpRouteNextHopTable(vp, name, length, exact, var_len, write_method) 983 struct variable *vp; /* IN - pointer to variable entry that points here */ 984 oid *name; /* IN/OUT - input name requested, output name found */ 985 int *length; /* IN/OUT - length of input and output oid's */ 986 int exact; /* IN - TRUE if an exact match was requested. */ 987 int *var_len; /* OUT - length of variable or 0 if function returned. */ 988 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 989 { 990 u_long src, mask; 991 vifi_t vifi; 992 struct rtentry *rt = NULL; 993 oid newname[MAX_NAME_LEN]; 994 int len; 995 996 /* Copy name OID to new OID */ 997 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 998 999 if (exact) { 1000 if (*length != vp->namelen + 9) 1001 return NULL; 1002 1003 if (!get_address(name, *length, &src, vp->namelen) 1004 || !get_address(name, *length, &mask, vp->namelen+4) 1005 || (!(rt=snmp_find_route(src,mask)))) 1006 return NULL; 1007 1008 vifi = name[vp->namelen+8]; 1009 if (!(VIFM_ISSET(vifi, rt->rt_children))) 1010 return NULL; 1011 1012 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 1013 } else { 1014 len = *length; 1015 if (compare(name, *length, vp->name, vp->namelen) < 0) 1016 len = vp->namelen; 1017 1018 if (len < vp->namelen + 9) { /* get first entry */ 1019 1020 get_address(name, len, &src, vp->namelen); 1021 get_address(name, len, &mask, vp->namelen+4); 1022 1023 /* Find first child vif */ 1024 vifi=0; 1025 if (!next_route_child(&rt, src, mask, &vifi)) 1026 return NULL; 1027 1028 put_address(newname, rt->rt_origin, vp->namelen); 1029 put_address(newname, rt->rt_originmask, vp->namelen+4); 1030 newname[vp->namelen+8] = vifi; 1031 } else { /* get next entry given previous */ 1032 vifi = name[vp->namelen+8] + 1; 1033 if (!get_address(name, *length, &src, vp->namelen) 1034 || !get_address(name, *length, &mask, vp->namelen+4) 1035 || !next_route_child(&rt, src, mask, &vifi)) 1036 return NULL; 1037 1038 put_address(newname, rt->rt_origin, vp->namelen); 1039 put_address(newname, rt->rt_originmask, vp->namelen+4); 1040 newname[vp->namelen+8] = vifi; 1041 } 1042 } 1043 1044 /* Save new OID */ 1045 *length = vp->namelen + 9; 1046 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 1047 *write_method = 0; 1048 *var_len = sizeof(long); 1049 1050 switch (vp->magic) { 1051 1052 case dvmrpRouteNextHopType: 1053 long_return = (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2; 1054 return (u_char *) &long_return; 1055 1056 default: 1057 ERROR(""); 1058 } 1059 return NULL; 1060 } 1061 1062 /* 1063 * Implements the IP Multicast Route Table portion of the Multicast MIB 1064 */ 1065 u_char * 1066 o_ipMRouteTable(vp, name, length, exact, var_len, write_method) 1067 struct variable *vp; /* IN - pointer to variable entry that points here */ 1068 oid *name; /* IN/OUT - input name requested, output name found */ 1069 int *length; /* IN/OUT - length of input and output oid's */ 1070 int exact; /* IN - TRUE if an exact match was requested. */ 1071 int *var_len; /* OUT - length of variable or 0 if function returned. */ 1072 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 1073 { 1074 u_long src, grp, mask; 1075 struct gtable *gt = NULL; 1076 struct stable *st = NULL; 1077 static struct sioc_sg_req sg_req; 1078 oid newname[MAX_NAME_LEN]; 1079 int len; 1080 1081 /* Copy name OID to new OID */ 1082 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 1083 1084 if (exact) { 1085 if (*length != vp->namelen + 12) 1086 return NULL; 1087 1088 if (!get_address(name, *length, &grp, vp->namelen) 1089 || !get_address(name, *length, &src, vp->namelen+4) 1090 || !get_address(name, *length, &mask, vp->namelen+8) 1091 || (mask != 0xFFFFFFFF) /* we keep sources now, not subnets */ 1092 || !(gt = find_grp(grp)) 1093 || !(st = find_grp_src(gt,src))) 1094 return NULL; 1095 1096 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 1097 } else { 1098 len = *length; 1099 if (compare(name, *length, vp->name, vp->namelen) < 0) 1100 len = vp->namelen; 1101 1102 if (len < vp->namelen + 12) { /* get first entry */ 1103 1104 get_address(name, len, &grp, vp->namelen); 1105 get_address(name, len, &src, vp->namelen+4); 1106 get_address(name, len, &mask, vp->namelen+8); 1107 1108 if (!next_grp_src_mask(>,&st,grp,src,mask)) /* Get first entry */ 1109 return NULL; 1110 1111 put_address(newname, gt->gt_mcastgrp, vp->namelen); 1112 put_address(newname, st->st_origin, vp->namelen+4); 1113 put_address(newname, 0xFFFFFFFF, vp->namelen+8); 1114 } else { /* get next entry given previous */ 1115 get_address(name, *length, &grp , vp->namelen); 1116 get_address(name, *length, &src , vp->namelen+4); 1117 get_address(name, *length, &mask, vp->namelen+8); 1118 1119 if (!next_grp_src_mask(>, &st, grp,src,mask)) 1120 return NULL; 1121 1122 put_address(newname, gt->gt_mcastgrp, vp->namelen); 1123 put_address(newname, st->st_origin, vp->namelen+4); 1124 put_address(newname, 0xFFFFFFFF, vp->namelen+8); 1125 } 1126 } 1127 1128 /* Save new OID */ 1129 *length = vp->namelen + 12; 1130 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 1131 *write_method = 0; 1132 *var_len = sizeof(long); 1133 1134 switch (vp->magic) { 1135 1136 case ipMRouteUpstreamNeighbor: 1137 return (u_char *) >->gt_route->rt_gateway; 1138 1139 case ipMRouteInIfIndex: 1140 long_return = gt->gt_route->rt_parent; 1141 return (u_char *) &long_return; 1142 1143 case ipMRouteUpTime: { 1144 time_t currtime; 1145 time(&currtime); 1146 long_return = (currtime - gt->gt_ctime)*100; 1147 return (u_char *) &long_return; 1148 } 1149 1150 case ipMRouteExpiryTime: 1151 long_return = 5*((gt->gt_timer+4)/5); /* round up to nearest 5 */ 1152 long_return = (long_return + secs_remaining_offset()) * 100; 1153 return (u_char *) &long_return; 1154 1155 case ipMRoutePkts: 1156 refresh_sg(&sg_req, gt, st); 1157 long_return = sg_req.pktcnt; 1158 return (u_char *) &long_return; 1159 1160 case ipMRouteOctets: 1161 refresh_sg(&sg_req, gt, st); 1162 long_return = sg_req.bytecnt; 1163 return (u_char *) &long_return; 1164 1165 case ipMRouteDifferentInIfIndexes: 1166 refresh_sg(&sg_req, gt, st); 1167 long_return = sg_req.wrong_if; 1168 return (u_char *) &long_return; 1169 1170 case ipMRouteProtocol: 1171 long_return = 4; 1172 return (u_char *) &long_return; 1173 1174 default: 1175 ERROR(""); 1176 } 1177 return NULL; 1178 } 1179 1180 /* 1181 * Implements the IP Multicast Routing Next Hop Table portion of the Multicast 1182 * MIB 1183 */ 1184 u_char * 1185 o_ipMRouteNextHopTable(vp, name, length, exact, var_len, write_method) 1186 struct variable *vp; /* IN - pointer to variable entry that points here */ 1187 oid *name; /* IN/OUT - input name requested, output name found */ 1188 int *length; /* IN/OUT - length of input and output oid's */ 1189 int exact; /* IN - TRUE if an exact match was requested. */ 1190 int *var_len; /* OUT - length of variable or 0 if function returned. */ 1191 int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */ 1192 { 1193 u_long src, grp, mask, addr; 1194 vifi_t vifi; 1195 struct gtable *gt; 1196 struct stable *st; 1197 oid newname[MAX_NAME_LEN]; 1198 int len; 1199 1200 /* Copy name OID to new OID */ 1201 bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid)); 1202 1203 if (exact) { 1204 if (*length != vp->namelen + 17) 1205 return NULL; 1206 1207 if (!get_address(name, *length, &grp, vp->namelen) 1208 || !get_address(name, *length, &src, vp->namelen+4) 1209 || !get_address(name, *length, &mask, vp->namelen+8) 1210 || !get_address(name, *length, &addr, vp->namelen+13) 1211 || grp!=addr 1212 || mask!=0xFFFFFFFF 1213 || (!(gt=find_grp(grp))) 1214 || (!(st=find_grp_src(gt,src)))) 1215 return NULL; 1216 1217 vifi = name[vp->namelen+12]; 1218 if (!(VIFM_ISSET(vifi, gt->gt_route->rt_children))) 1219 return NULL; 1220 1221 bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid)); 1222 } else { 1223 len = *length; 1224 if (compare(name, *length, vp->name, vp->namelen) < 0) 1225 len = vp->namelen; 1226 1227 if (len < vp->namelen + 17) { /* get first entry */ 1228 1229 get_address(name, len, &grp, vp->namelen); 1230 get_address(name, len, &src, vp->namelen+4); 1231 get_address(name, len, &mask, vp->namelen+8); 1232 1233 /* Find first child vif */ 1234 vifi=0; 1235 if (!next_child(>, &st, grp, src, mask, &vifi)) 1236 return NULL; 1237 1238 put_address(newname, gt->gt_mcastgrp, vp->namelen); 1239 put_address(newname, st->st_origin, vp->namelen+4); 1240 put_address(newname, 0xFFFFFFFF, vp->namelen+8); 1241 newname[vp->namelen+12] = vifi; 1242 put_address(newname, gt->gt_mcastgrp, vp->namelen+13); 1243 1244 } else { /* get next entry given previous */ 1245 vifi = name[vp->namelen+12]+1; 1246 if (!get_address(name, *length, &grp, vp->namelen) 1247 || !get_address(name, *length, &src, vp->namelen+4) 1248 || !get_address(name, *length, &mask, vp->namelen+8) 1249 || !next_child(>, &st, grp, src, mask, &vifi)) 1250 return NULL; 1251 1252 put_address(newname, gt->gt_mcastgrp, vp->namelen); 1253 put_address(newname, st->st_origin, vp->namelen+4); 1254 put_address(newname, 0xFFFFFFFF, vp->namelen+8); 1255 newname[vp->namelen+12] = vifi; 1256 put_address(newname, gt->gt_mcastgrp, vp->namelen+13); 1257 } 1258 } 1259 1260 /* Save new OID */ 1261 *length = vp->namelen + 17; 1262 bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid)); 1263 *write_method = 0; 1264 *var_len = sizeof(long); 1265 1266 switch (vp->magic) { 1267 1268 case ipMRouteNextHopState: 1269 long_return = (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1; 1270 return (u_char *) &long_return; 1271 1272 /* Currently equal to ipMRouteUpTime */ 1273 case ipMRouteNextHopUpTime: { 1274 time_t currtime; 1275 time(&currtime); 1276 long_return = (currtime - gt->gt_ctime)*100; 1277 return (u_char *) &long_return; 1278 } 1279 1280 case ipMRouteNextHopExpiryTime: 1281 long_return = 5*((gt->gt_prsent_timer+4)/5); /* round up to nearest 5*/ 1282 long_return = (long_return + secs_remaining_offset()) * 100; 1283 return (u_char *) &long_return; 1284 1285 case ipMRouteNextHopClosestMemberHops: 1286 long_return = 0; 1287 return (u_char *) &long_return; 1288 1289 case ipMRouteNextHopProtocol: 1290 long_return = 4; 1291 return (u_char *) &long_return; 1292 1293 default: 1294 ERROR(""); 1295 } 1296 return NULL; 1297 } 1298 1299 /* sync_timer is called by timer() every TIMER_INTERVAL seconds. 1300 * Its job is to record this time so that we can compute on demand 1301 * the approx # seconds remaining until the next timer() call 1302 */ 1303 static time_t lasttimer; 1304 1305 void 1306 sync_timer() 1307 { 1308 time(&lasttimer); 1309 } 1310 1311 int /* in range [-TIMER_INTERVAL..0] */ 1312 secs_remaining_offset() 1313 { 1314 time_t tm; 1315 1316 time(&tm); 1317 return lasttimer-tm; 1318 } 1319