Branch: Tag:

2001-07-18

2001-07-18 21:10:04 by Honza Petrous <hop@unibase.cz>

Again rather big rewrite. The moving to the more OOB variant is a little bit evident here. Preparation for simple SNMPmanager object skeleton usage.

Rev: server/base_server/configuration.pike:1.450
Rev: server/base_server/snmpagent.pike:1.5

1:   /* -  * $Id: snmpagent.pike,v 1.4 2001/06/30 23:02:43 hop Exp $ +  * $Id: snmpagent.pike,v 1.5 2001/07/18 21:10:04 hop Exp $    *    * The Roxen SNMP agent    * Copyright © 2001, Roxen IS.
8:    * January 2001       - RFC 1156 base MIB (done marked by *): -  system: -  sysDescr * -  sysObjectID * -  sysUpTime * -  sysL -  snmp: -  snmpInPkts * -  snmpOutPkts * + RFC 1213 base MIB +  system.* (all done) +  snmp.* (all done, but most of them all still death) +  + Future: +  + RFC 1215 Convention for defining traps + RFC 1227 SNMP MUX procotol and MIB   RFC 2248 Network Services Monitoring MIB -  + RFC 2576 Coexistence between v1, v2 and v3 of SNMP protocol + RFC 2594 Definitions of managed objects for WWW services      Developer notes:       Known issues:    - every reload spawne a new thread, I guess that old ones are never    used then. [threads leak] // FIXME: solved by switching to the async i/o -  +  - the OID must be minimally 5 elements long, otherwise GETNEXT return +  "no such name" error +  - the tree walking returns the 'end of MIB' instead of some object +  from next subtree    Todos:    v1.0 todo:    - cold/warm start trap generation
48:          - // FIXME: thread leaking is hided by moving to the async i/o model + // FIXME: thread leaking is hiden by moving to the async i/o model   //#define NO_THREADS !constant(thread_create)   #define NO_THREADS 1   
67:   #define SNMP_OP_SETREQUEST 3   #define SNMP_OP_TRAP 4    + #define OBJ_STR(x) ({"str", x}) + #define OBJ_INT(x) ({"int", x}) + #define OBJ_OID(x) ({"oid", x}) + #define OBJ_TICK(x) ({"tick", x}) + #define OBJ_COUNT(x) ({"count", x}) +    #define RISMIB_BASE "1.3.6.1.4.1.8614"   #define RISMIB_BASE_WEBSERVER RISMIB_BASE+".1.1"    - #define RET_NEXTOID(oidnext) if(op == SNMP_OP_GETNEXT) rdata += ([attrname:({"oid", oidnext+".0"})]) - //#define RET_VALUE(arr) if(op == SNMP_OP_GETREQUEST) rdata[attrname] += arr - #define RET_VALUE(arr) rdata[attrname] += arr + //! The starting part of OID of every object will have, so we stripp it out + //! before making index from OID to the MIB DB + #define MIBTREE_BASE "1.3.6.1" +    #define LOG_EVENT(txt, pkt) log_event(txt, pkt)    - // base external feeders -  - string get_description() { return("Roxen Webserver SNMP agent v"+("$Revision: 1.4 $"/" ")[1]+" (devel. rel.)"); } - //! External function for MIB object 'system.sysDescr' -  - string get_sysoid() { return RISMIB_BASE_WEBSERVER; } - //! External function for MIB object 'system.sysOID' -  - int get_uptime() { return ((time(1) - roxen->start_time)*100); } - //! External function for MIB object 'system.sysUpTime' -  - string get_syscontact() { return query("snmp_syscontact"); } - //! External function for MIB object 'system.sysContact' -  - string get_sysname() { return query("snmp_sysname"); } - //! External function for MIB object 'system.sysName' -  - string get_syslocation() { return query("snmp_syslocation"); } - //! External function for MIB object 'system.sysLocation' -  - int get_sysservices() { return query("snmp_sysservices"); } - //! External function for MIB object 'system.sysServices' -  -  +    class SNMPagent {    private int enabled;   
114:    private mapping events;    private mixed co;    private object th; -  private static SNMPmib mib; +  private static object mib; +  private mapping vsdb;    -  int get_null() { return 0; } -  //! External function for MIB object returning nothing +  array get_snmpinpkts() { return OBJ_COUNT(snmpinpkts); }; +  array get_snmpoutpkts() { return OBJ_COUNT(snmpoutpkts); }; +  array get_snmpbadver() { return OBJ_COUNT(snmpbadver); }; +  array get_snmpbadcommnames() { return OBJ_COUNT(snmpbadcommnames); }; +  array get_snmpbadcommuses() { return OBJ_COUNT(snmpbadcommuses); }; +  array get_snmpenaauth() { return OBJ_COUNT(snmpenaauth); };    -  int get_snmpinpkts() { return(snmpinpkts); }; -  int get_snmpoutpkts() { return(snmpoutpkts); }; -  int get_snmpbadver() { return(snmpbadver); }; -  int get_snmpbadcommnames() { return(snmpbadcommnames); }; -  int get_snmpbadcommuses() { return(snmpbadcommuses); }; -  int get_snmpenaauth() { return(snmpenaauth); }; +  array get_virtserv() { return OBJ_COUNT(sizeof(vsdb)); };    - class SNMPmib { - #define MIBTREE_BASE "1.3.6.1" +     -  private mapping(string:array) mibtable; -  -  public string|int oid_strip (string oid) { // note: this method must be public! -  //! Removes first four octets from OID string, as internal table works -  //! on such stripped OIDs. -  array arr = oid / "."; -  if (sizeof(arr) < 7) -  return 0; -  oid = arr[4..] * "."; -  return oid; -  } -  -  private int|string oid_check(string oid) { -  //! Checks existence of an managed object in the database -  if(!(oid = oid_strip(oid))) return 0; -  return zero_type(mibtable[oid]) ? 0 : oid; -  } -  -  int register(string oid, array data) { -  //! Low level method for registering a new managed object -  if(!(oid = oid_strip(oid))) return -1; // false => bad OID -  if(oid_check(oid)) -  return 0; // false => the OID is already registered -  mibtable += ([oid: data]); // FIXME: what about type checking of 'data' ? -  return 1; // ok (registered) -  } -  -  void create(string|void filename) { -  -  mibtable = ([ -  // system -  "2.1.1": ({ 0, get_null, "2.1.1.1.0"}), -  // system.sysDescr -  "2.1.1.1.0": ({ "str", -  get_description, -  "2.1.1.2.0"}), -  // system.sysObjectID -  "2.1.1.2.0": -  ({ "oid", get_sysoid, "2.1.1.3.0" }), -  // system.sysUpTime -  "2.1.1.3.0": -  ({ "tick", get_uptime, "2.1.1.4.0" }), -  // system.sysContact -  "2.1.1.4.0": -  ({ "str", get_syscontact, "2.1.1.5.0" }), -  // system.sysName -  "2.1.1.5.0": -  ({ "str", get_sysname, "2.1.1.6.0" }), -  // system.sysLocation -  "2.1.1.6.0": -  ({ "str", get_syslocation, "2.1.1.7.0" }), -  // system.sysServices -  "2.1.1.7.0": -  ({ "int", get_sysservices, 0 }), -  -  // snmp -  "2.1.11": -  ({ 0, get_null, "2.1.11.1.0" }), -  // snmp.snmpInPkts -  "2.1.11.1.0": -  ({ "count", get_snmpinpkts, "2.1.11.2.0" }), -  // snmp.snmpOutPkts -  "2.1.11.2.0": -  ({ "count", get_snmpoutpkts, "2.1.11.3.0" }), -  // snmp.snmpBadVers -  "2.1.11.3.0": -  ({ "count", get_snmpbadver, "2.1.11.4.0" }), -  // snmp.snmpInBadCommunityNames -  "2.1.11.4.0": -  ({ "count", get_snmpbadcommnames, "2.1.11.5.0" }), -  // snmp.snmpInBadCommunityUses -  "2.1.11.5.0": -  ({ "count", get_null, "2.1.11.6.0" }), -  // snmp.snmpInASNParseErrs -  "2.1.11.6.0": -  ({ "count", get_null, "2.1.11.8.0" }), -  // 7 is not used -  // snmp.snmpInTooBigs -  "2.1.11.8.0": -  ({ "count", get_null, "2.1.11.9.0" }), -  // snmp.snmpInNoSuchNames -  "2.1.11.9.0": -  ({ "count", get_null, "2.1.11.10.0" }), -  // snmp.snmpInBadValues -  "2.1.11.10.0": -  ({ "count", get_null, "2.1.11.11.0" }), -  // snmp.snmpInReadOnlys -  "2.1.11.11.0": -  ({ "count", get_null, "2.1.11.12.0" }), -  // snmp.snmpInGenErrs -  "2.1.11.12.0": -  ({ "count", get_null, "2.1.11.13.0" }), -  // snmp.snmpInTotalReqVars -  "2.1.11.13.0": -  ({ "count", get_null, "2.1.11.14.0" }), -  // snmp.snmpInTotalSetVars -  "2.1.11.14.0": -  ({ "count", get_null, "2.1.11.15.0" }), -  // snmp.snmpInGetRequests -  "2.1.11.15.0": -  ({ "count", get_null, "2.1.11.16.0" }), -  // snmp.snmpInGetNexts -  "2.1.11.16.0": -  ({ "count", get_null, "2.1.11.17.0" }), -  // snmp.snmpInSetRequests -  "2.1.11.17.0": -  ({ "count", get_null, "2.1.11.18.0" }), -  // snmp.snmpInGetResponses -  "2.1.11.18.0": -  ({ "count", get_null, "2.1.11.19.0" }), -  // snmp.snmpInTraps -  "2.1.11.19.0": -  ({ "count", get_null, "2.1.11.20.0" }), -  // snmp.snmpOutTooBigs -  "2.1.11.20.0": -  ({ "count", get_null, "2.1.11.21.0" }), -  // snmp.snmpOutNoSuchNames -  "2.1.11.21.0": -  ({ "count", get_null, "2.1.11.22.0" }), -  // snmp.snmpOutBadValues -  "2.1.11.22.0": -  ({ "count", get_null, "2.1.11.24.0" }), -  // 23 is not used -  // snmp.snmpOutGenErrs -  "2.1.11.24.0": -  ({ "count", get_null, "2.1.11.25.0" }), -  // snmp.snmpOutGetRequests -  "2.1.11.25.0": -  ({ "count", get_null, "2.1.11.26.0" }), -  // snmp.snmpOutGetNexts -  "2.1.11.26.0": -  ({ "count", get_null, "2.1.11.27.0" }), -  // snmp.snmpOutSetRequests -  "2.1.11.27.0": -  ({ "count", get_null, "2.1.11.28.0" }), -  // snmp.snmpOutGetResponses -  "2.1.11.28.0": -  ({ "count", get_null, "2.1.11.29.0" }), -  // snmp.snmpOutTraps -  "2.1.11.29.0": -  ({ "count", get_null, "2.1.11.30.0" }), -  // snmp.snmpEnableAuthenTraps -  "2.1.11.30.0": -  ({ "int", get_snmpenaauth, 0 }), -  -  // enterprises.roxenIS.webserver -  "4.1.8614.1.1": -  ({ 0, get_null, "4.1.8614.1.1.999.0" }), -  // HACK!! -  "4.1.8614.1.1.999.0": -  ({ 0, get_null, 0 }) -  -  ]); -  - #if 0 -  // external definitions from the file -  if (stringp(filename)) { -  -  } - #endif -  -  } // create -  -  array `[](string oid) { -  //! Returns array -  if (!oid_check(oid)) { -  return 0; -  } -  oid = oid_strip(oid); -  return (({mibtable[oid][0], mibtable[oid][1](), mibtable[oid][2]})); -  } -  -  string|int oid_guess_next(string oid) { -  //! Tries to guess next OID. Usable to situation when GET_NEXT op -  //! contains OID without .0 -  -  if(oid_check(oid+".0")) -  return oid+".1"; -  return 0; -  } -  - } // SNMPmib -  +     void create() { -  +  vsdb = ([]);    //disable();    }    -  int enable() { +     //! Enable SNMPagent processing. -  +  int enable() {    -  mib = SNMPmib(); +  mib = SubMIBsystem(); // system.* table +  if(objectp(mib)) // snmp.* table +  //mib->register(MIBTREE_BASE+"."+"2.1.11", SubMIBsnmp(this_object())); + { object mib2 = SubMIBsnmp(this_object()); +  mib->register(MIBTREE_BASE+"."+"2.1.11", SubMIBsnmp(this_object())); + }    if (!status())    start();    enabled = 1;    return (enabled);    }    -  int disable() { +     //! Disable SNMPagent processing. -  +  int disable() { +     if(status())    stop();    enabled = 0;
349:    events[txt][pkt->ip][pkt->community]++;    }    -  private int chk_access(string level /*, string attrname*/, mapping pkt) { +     //! Check access aginst snmp_community array. -  +  private int chk_access(string level /*, string attrname*/, mapping pkt) {       return    (search(query("snmp_community"), pkt->community+":"+level) > -1) ||
358:    }       -  private void process_query(mapping data) { +     //! The main code of SNMPagent. -  +  private void process_query(mapping data) {       mapping pdata, rdata = ([]);    int msgid, op, errnum = 0, setflg = 0;
391:    mixed attrval = values(attrs)[0];    attrname = indices(attrs)[0];    -  if(!mib) +  if(!mib) {    SNMPAGENT_MSG(" MIB table isn't loaded!\n"); -  val = mib[attrname]; -  if (!val && op == SNMP_OP_GETNEXT) { // FIXME: move guessing to the MIB object -  val = mib[attrname+".0"]; -  if(arrayp(val)) -  val[2] = mib->oid_strip(attrname)+".0"; +  // what to do now ?    } -  if (val) +     switch(op) {       case SNMP_OP_GETREQUEST: -  if (val[0]) -  rdata[attrname] += val[0..1]; +  val = mib->get(attrname, pdata[msgid]); +  if (arrayp(val) && val[0]) +  rdata[attrname] += val;    break;       case SNMP_OP_GETNEXT: -  if (val[2]) { -  string noid = MIBTREE_BASE+"."+val[2]; -  val = mib[noid]; -  if (val && val[0]) -  rdata[noid] += val[0..1]; -  } +  val = mib->getnext(attrname, pdata[msgid]); +  if (arrayp(val) && val[0]) +  //rdata[attrname] += val; +  rdata[val[0]] += val[1..2];    break;       case SNMP_OP_SETREQUEST: -  -  switch (attrname) { -  case RISMIB_BASE_WEBSERVER+".1.0": -  // HACK! For testing purpose only! -  // Server restart = 1; server shutdown = 2 -  if(chk_access("rw", pdata[msgid])) { -  setflg = 1; -  rdata[attrname] += ({ "int", attrval }); +  val = mib->set(attrname, attrval, pdata[msgid]); +  if(arrayp(val)) +  setflg = val[0]; +  //rdata[attrname] += ({ "int", attrval });    rdata["1.3.6.1.2.1.1.3.0"] += ({"tick", get_uptime() }); -  if(attrval == 1 || attrval == 2) { -  report_warning("SNMPagent: Initiated " + ((attrval==1)?"restart":"shutdown") + " from snmp://" + pdata[msgid]->community + "@" + pdata[msgid]->ip + "/\n"); -  if (attrval == 1) roxen->restart(0.5); -  if (attrval == 2) roxen->shutdown(0.5); -  } -  } else -  snmpbadcommuses++; +  if (arrayp(val) && stringp(val[1])) +  report_warning(val[1]);    break; -  case MIBTREE_BASE+".2.1.11.30.0": -  // The standard-based (RFC1213) method of disabling auth. traps -  if(chk_access("rw", pdata[msgid])) { -  setflg = 1; -  rdata[attrname] += ({ "int", attrval }); -  rdata["1.3.6.1.2.1.1.3.0"] += ({"tick", get_uptime() }); -  if(attrval == 0 || attrval == 1) { -  report_warning("SNMPagent: Requested " + attrval?"en":"dis" + "abling of auth. traps from snmp://" + pdata[msgid]->community + "@" + pdata[msgid]->ip + "/\n"); -  // here will be ena/disabling of such traps -  } -  } else -  snmpbadcommuses++; -  break; +     -  +     } //switch -  break; -  } //switch -  else -  SNMPAGENT_MSG(sprintf(" unknown or unsupported OID: %O:%O", attrname, attrval)); +  //else +  // SNMPAGENT_MSG(sprintf(" unknown or unsupported OID: %O:%O", attrname, attrval));    -  - /* -  // www group 1.3.6.1.2.1.65.1 -  // www.wwwService 1.3.6.1.2.1.65.1.1 -  // www.wwwServiceTable 1.3.6.1.2.1.65.1.1.1 -  // www.wwwServiceEntry 1.3.6.1.2.1.65.1.1.1.1 ... -  break; - */ -  +     } //foreach       if(op == SNMP_OP_SETREQUEST && !setflg && !errnum) {    LOG_EVENT("Set not allowed", pdata[msgid]); -  +  snmpbadcommuses++;    }       //SNMPAGENT_MSG(sprintf("Answer: %O", rdata));
478:    fd->get_response(rdata, pdata);    }    -  private void real_start() { +     //! Opens the SNMP port. Then waits for the requests. -  +  private void real_start() {       mixed err;    mapping data;    array hp = query("snmp_hostport")/":"; -  int p = (sizeof(hp)>1) ? (int)hp[1] : 161; // FIXME: SNMPAGENT_DEFAULT_PORT +  int p = (sizeof(hp)>1) ? (int)hp[1] : 161; // FIXME: SNMPAGENT_DEFAULT_PORT !!!       -  fd = Protocols.SNMP.protocol(0, hp[0], p||161); +  err = catch( fd = Protocols.SNMP.protocol(0, hp[0], p||161) );    if(arrayp(err))    RXML.run_error("SNMPagent: can't open UDP port " + hp[0]+":"+(string)(p||161)+"[" + err[0] + "].");    SNMPAGENT_MSG(sprintf("SNMP UDP port %s:%d binded successfully.", hp[0], p||161));    - #ifdef COLDSTART_TRAP // Not working, yet -  // Cold start TRAP -  if (sizeof(query("snmp_traphost"))) { -  mapping rdata; -  rdata = ([attrname:({"oid", "1.3.6.1.4.1.0.1.1"})]); -  rdata += ([attrname:({"ipaddr", "127.0.0.1" }) ]); // FIXME -  rdata += ([attrname:({"int", 1 }) ]); // generic trap = warmStart -  rdata += ([attrname:({"int", 0 }) ]); // specific trap = none -  rdata += ([attrname:({"tick", (time(1) - roxen->start_time)*1000 }) ]); // uptime -  } - #endif -  +     enabled = 1;   #if NO_THREADS    // set callbacks
518:       }    +  //! Starts SNMP agent by calling real_start method    private void start() {       events = ([]);
536:    }    }    +  //! Stops processing of SNMP agent by cleaning all internal objects    void stop() {       SNMPAGENT_MSG("Shutting down...");
553:    SNMPAGENT_MSG("Shutdown complete.");    }    - /* -  string status2() { -  string rv = ""; +  //! Cold start notificator. Sends trap for all virtual servers in the vsarr. +  void coldstart_trap(array(int) vsarr) {    -  rv = "<h2>SNMP access table</h2>\n"; - #if 0 //SNMP_STATS -  rv += "<table>\n"; -  rv += "<tr ><th>From</th><th>To</th><th>Size</th></tr>\n"; -  foreach(mails, mapping m) -  rv += "<tr ><td>"+(m->from||"[N/A]")+"</td><td>"+(m->to||"[default]")+"</td><td>"+m->length+"</td></tr>\n"; -  rv += "</table>\n"; - #else -  rv += "<pre>" + sprintf("%O<br />\n", events) + "</pre>\n"; - #endif -  return rv; +  object uri; +  +  if(intp(vsarr)) +  return; +  foreach(vsarr, int vsid) +  if(vsdb[vsid] && vsdb[vsid]->variables["snmp_traphosts"]) { +  SNMPAGENT_MSG(sprintf("virt.serv[%d/%s]'s traphosts:%O", vsid, vsdb[vsid]->name, vsdb[vsid]->variables["snmp_traphosts"])); +  foreach(vsdb[vsid]->variables["snmp_traphosts"], string thost) { +  uri = Standards.URI(thost); +  SNMPAGENT_MSG(sprintf("Trap sent: %s.", thost)); +  fd->trap(RISMIB_BASE_WEBSERVER, +  Standards.URI(vsdb[vsid]->varibles["MyWorldLocation"])->host, 0, 0, +  get_uptime(), 0, uri->host, uri->port);    } - */ +  } else +  SNMPAGENT_MSG(sprintf("virt.serv[%d/%s] hasn't any traphosts.", vsid, vsdb[vsid]->name));    -  int add_virtserv(int vs) { - report_debug(sprintf("snmpagent:DEB: add: %O->%O\n",vs,roxen->configurations[vs]->name)); +  }    -  +  //! Warm start notificator +  void warmstart_trap() { +  +  } +  +  //! Authentication failure notificator +  void authfailure_trap() { +  +  } +  +  //! Enterprise specific trap notificator +  void enterprise_trap() { +  +  } +  +  //! Adds virtual server to the DB of managed objects +  int add_virtserv(int vsid) { +  +  if(zero_type(vsdb[vsid])) { + report_debug(sprintf("snmpagent:DEB: add: %O->%O\n",vsid,roxen->configurations[vsid]->name)); + //report_debug(sprintf("snmpagent:DEB: %O\n",mkmapping(indices(roxen->configurations[vsid]), values(roxen->configurations[vsid])))); +  vsdb += ([vsid: roxen->configurations[vsid]]); +  } +     return(1);    }    -  int del_virtserv(int vs) { - report_debug(sprintf("snmpagent:DEB: del: %O->%O\n",vs,roxen->configurations[vs]->name)); +  //! Deletes virtual server's specific objects from DB +  int del_virtserv(int vsid) {    -  +  if(!zero_type(vsdb[vsid])) { + report_debug(sprintf("snmpagent:DEB: del: %O->%O\n",vsid,roxen->configurations[vsid]->name)); +  vsdb -= ([ vsid: 0 ]); +  } +     return(1);    }      } // end of SNMPagent object    -  + //! Removes first four octets from OID string, as internal table works + //! on such stripped OIDs. + private string|int oid_strip (string oid) { // note: this method must be public! +  +  array arr = oid / "."; +  if (sizeof(arr) < 7) // FIXME: exists oid with less octets? +  return 0; +  oid = arr[4..] * "."; +  return oid; + } +  + //! + //! Generic class for submib tree managers, or individual objects as well. + //! + class SubMIBManager { +  +  //! Name of object +  constant name = "generic skeleton"; +  +  //! OID number of the registered subtree +  constant tree = ""; +  +  //! Table of managed objects in the form: +  //! ([ string stripped_oid: function get_value ]) +  mapping submibtab = ([]); +  +  //! Table of registered subtree managers in the form: +  //! ([ string stripped_oid: object manager ]) +  mapping subtreeman = ([]); +  +  //! Checks existence of an managed object in the database +  private int|string oid_check(string oid) { +  +  if(!(oid = oid_strip(oid))) return 0; +  return zero_type(submibtab[oid]) ? 0 : oid; +  } +  +  //! Low level method for registering a new manager for object or the whole subtree. +  //! Note: If oid is ancessor of already existing oids, then autohiding of existing +  //! object's managers will be done. Unregistering reenabled such hided managers +  //! again. +  int register(string oid, object manager) { +  +  if(!(oid = oid_strip(oid))) return -1; // false => bad OID +  if(oid_check(oid)) +  return 0; // false => the OID is already registered. What about stackable organization ? +  if(subtreeman[oid]) +  return 0; // false => already registered +  subtreeman += ([oid: manager]); // FIXME: autohiding of subtree. Is it goood? +  return 1; // ok (registered) +  } +  +  void create() { +  +  report_error("SubMIBManager object [" + (string)name + "] hasn't replaced contructor!\n"); +  } // create +  +  //! Returns array. First element is type of second element. +  //! Is usable for very primitive managed objects, in which case the value +  //! is got by calling function from submibtab table. +  //array `[](string oid) { +  array get(string oid, mapping|void pkt) { +  +  function rval; +  string soid; +  +  SNMPAGENT_MSG(sprintf("GET(%s): %O", name, oid)); +  soid = oid_strip(oid); +  if (functionp(rval = submibtab[soid])) { +  SNMPAGENT_MSG("found MIB object."); +  return rval(); +  } +  +  // hmm, now we have to try some of the registered managers +  array s = soid/"."; +  for(int cnt = sizeof(s)-1; cnt>0; cnt--) +  if(subtreeman[s[..cnt]*"."]) { +  // good, subtree manager exists +  string manoid = s[..cnt]*"."; +  SNMPAGENT_MSG(sprintf("found subtree manager: %s(%O)", +  subtreeman[manoid]->name, manoid)); +  return subtreeman[manoid]->get(oid); +  } +  } +  +  //! Returns array ({ nextoid, type, val }) or 0 +  array|int getnext(string oid, mapping|void pkt) { +  +  array(string) idxnums = Array.sort(indices(submibtab)); +  int idx; +  string soid; +  array s; +  +  SNMPAGENT_MSG(sprintf("GETNEXT(%s): %O", name, oid)); +  if(!(soid = oid_strip(oid))) +  return 0; + SNMPAGENT_MSG(sprintf("DEB: %O", soid)); +  idx = search(idxnums, soid); + SNMPAGENT_MSG(sprintf("arr: %d, %O", idx, idxnums)); +  if(idx >= 0) { +  // good, we found equality +  SNMPAGENT_MSG(sprintf("%s: eq match: %O", tree, idx)); +  if(idx < sizeof(idxnums)-1) +  return (({ MIBTREE_BASE+"."+(string)idxnums[idx+1], +  @submibtab[idxnums[idx+1]]() })); +  else +  return 0; +  } else { +  + SNMPAGENT_MSG(sprintf("DEB: %O - %O", soid[..(sizeof(tree)-1)], tree)); +  int tlen = sizeof(tree/"."); +  array sarr = soid/"."; +  //if(soid[..(sizeof(tree)-1)] == tree) { // only inside owned subtree +  if(sizeof(sarr)>=tlen && (sarr[..tlen-1]*".") == tree) { +  SNMPAGENT_MSG(name+": owned subtree found."); +  // hmm, now we have to find nearest subtree +  for(idx = 0; idx < sizeof(idxnums); idx++) +  if (soid < idxnums[idx]) { + SNMPAGENT_MSG(sprintf("subtree match: %O", idxnums[idx])); +  return (({ MIBTREE_BASE+"."+(string)idxnums[idx], +  @submibtab[idxnums[idx]]() })); +  } +  } +  +  SNMPAGENT_MSG(name+": foreign object detected."); +  s = soid/"."; +  // hmm, now we have to try some of the registered managers +  for(int cnt = sizeof(s)-1; cnt>0; cnt--) { + SNMPAGENT_MSG(sprintf("DEB: %d: %O", cnt, s[..cnt]*".")); +  if(subtreeman[s[..cnt]*"."]) { +  // good, subtree manager exists +  string manoid = s[..cnt]*"."; +  SNMPAGENT_MSG(sprintf("found subtree manager: %s(%O)", +  subtreeman[manoid]->name, manoid)); +  return subtreeman[manoid]->getnext(oid, pkt); +  } +  } +  +  } +  +  return 0; +  } +  +  //! Tries to do SET operation. +  array set(string oid, mixed val, mapping|void pkt) { +  +  return ({ 0, 0}); +  } +  +  //! Tries to guess next OID. Usable to situation when GET_NEXT op +  //! contains OID without .0 +  string|int oid_guess_next(string oid) { +  +  if(oid_check(oid+".0")) +  return oid+".1"; +  return 0; +  } +  +  //! External function for MIB object returning nothing +  array get_null() { return OBJ_COUNT(0); } +  + } // SubMIBManager +  + // base external feeders +  + //! External function for MIB object 'system.sysDescr' + array get_description() { +  return OBJ_STR("Roxen Webserver SNMP agent v"+("$Revision: 1.5 $"/" ")[1]+" (devel. rel.)"); + } +  + //! External function for MIB object 'system.sysOID' + array get_sysoid() { +  return OBJ_OID(RISMIB_BASE_WEBSERVER); + } +  + //! External function for MIB object 'system.sysUpTime' + array get_uptime() { +  return OBJ_TICK((time(1) - roxen->start_time)*100); + } +  + //! External function for MIB object 'system.sysContact' + array get_syscontact() { +  return OBJ_STR(query("snmp_syscontact")); + } +  + //! External function for MIB object 'system.sysName' + array get_sysname() { +  return OBJ_STR(query("snmp_sysname")); + } +  + //! External function for MIB object 'system.sysLocation' + array get_syslocation() { +  return OBJ_STR(query("snmp_syslocation")); + } +  + //! External function for MIB object 'system.sysServices' + array get_sysservices() { +  return OBJ_INT(query("snmp_sysservices")); + } +  +  +  + //! system subtree manager + //! Manages the basic system.sys* submib tree. + class SubMIBsystem { +  +  inherit SubMIBManager; +  +  constant name = "system"; +  constant tree = "2.1.1"; +  +  void create() { +  +  submibtab = ([ +  // system "2.1.1" +  // system.sysDescr +  "2.1.1.1.0": get_description, +  // system.sysObjectID +  "2.1.1.2.0": get_sysoid, +  // system.sysUpTime +  "2.1.1.3.0": get_uptime, +  // system.sysContact +  "2.1.1.4.0": get_syscontact, +  // system.sysName +  "2.1.1.5.0": get_sysname, +  // system.sysLocation +  "2.1.1.6.0": get_syslocation, +  // system.sysServices +  "2.1.1.7.0": get_sysservices, +  ]); +  } // create +  + } // SubMIBsystem +  +  + //! snmp subtree manager + //! Manages the basic snmp.snmp* submib tree. + class SubMIBsnmp { +  +  inherit SubMIBManager; +  +  constant name = "snmp"; +  constant tree = "2.1.11"; +  +  void create(object agent) { +  +  submibtab = ([ +  // snmp +  //"2.1.11": ({ 0, get_null, "2.1.11.1.0" }), +  // snmp.snmpInPkts +  "2.1.11.1.0": agent->get_snmpinpkts, +  // snmp.snmpOutPkts +  "2.1.11.2.0": agent->get_snmpoutpkts, +  // snmp.snmpBadVers +  "2.1.11.3.0": agent->get_snmpbadver, +  // snmp.snmpInBadCommunityNames +  "2.1.11.4.0": agent->get_snmpbadcommnames, +  // snmp.snmpInBadCommunityUses +  "2.1.11.5.0": get_null, +  // snmp.snmpInASNParseErrs +  "2.1.11.6.0": get_null, +  // 7 is not used +  // snmp.snmpInTooBigs +  "2.1.11.8.0": get_null, +  // snmp.snmpInNoSuchNames +  "2.1.11.9.0": get_null, +  // snmp.snmpInBadValues +  "2.1.11.10.0": get_null, +  // snmp.snmpInReadOnlys +  "2.1.11.11.0": get_null, +  // snmp.snmpInGenErrs +  "2.1.11.12.0": get_null, +  // snmp.snmpInTotalReqVars +  "2.1.11.13.0": get_null, +  // snmp.snmpInTotalSetVars +  "2.1.11.14.0": get_null, +  // snmp.snmpInGetRequests +  "2.1.11.15.0": get_null, +  // snmp.snmpInGetNexts +  "2.1.11.16.0": get_null, +  // snmp.snmpInSetRequests +  "2.1.11.17.0": get_null, +  // snmp.snmpInGetResponses +  "2.1.11.18.0": get_null, +  // snmp.snmpInTraps +  "2.1.11.19.0": get_null, +  // snmp.snmpOutTooBigs +  "2.1.11.20.0": get_null, +  // snmp.snmpOutNoSuchNames +  "2.1.11.21.0": get_null, +  // snmp.snmpOutBadValues +  "2.1.11.22.0": get_null, +  // 23 is not used +  // snmp.snmpOutGenErrs +  "2.1.11.24.0": get_null, +  // snmp.snmpOutGetRequests +  "2.1.11.25.0": get_null, +  // snmp.snmpOutGetNexts +  "2.1.11.26.0": get_null, +  // snmp.snmpOutSetRequests +  "2.1.11.27.0": get_null, +  // snmp.snmpOutGetResponses +  "2.1.11.28.0": get_null, +  // snmp.snmpOutTraps +  "2.1.11.29.0": get_null, +  // snmp.snmpEnableAuthenTraps +  "2.1.11.30.0": agent->get_snmpenaauth, +  +  ]); +  +  } + } +  + /* +  // enterprises +  "4.1": ({ 0, get_null, "4.1.8614.1.1.999.1.0" }), +  // enterprises.roxenIS +  "4.1.8614": ({ 0, get_null, "4.1.8614.1.1.999.1.0" }), +  // enterprises.roxenIS.app +  "4.1.8614.1.1": ({ 0, get_null, "4.1.8614.1.1.999.1.0" }), +  // enterprises.roxenIS.app.webserver +  "4.1.8614.1.1": ({ 0, get_null, "4.1.8614.1.1.999.1.0" }), +  // HACK!! +  "4.1.8614.1.1.999.1.0": ({ 0, get_null, 0 }), +  +  // hack2 :) +  "4.1.8614.1.1.999.2.1.0": ({ "int", get_virtserv, "4.1.8614.1.1.999.2.2.0" }) +  + */ +  + /* +  switch (attrname) { +  case RISMIB_BASE_WEBSERVER+".1.0": +  // HACK! For testing purpose only! +  // Server restart = 1; server shutdown = 2 +  if(chk_access("rw", pdata[msgid])) { +  setflg = 1; +  rdata[attrname] += ({ "int", attrval }); +  rdata["1.3.6.1.2.1.1.3.0"] += ({"tick", get_uptime() }); +  if(attrval == 1 || attrval == 2) { +  report_warning("SNMPagent: Initiated " + ((attrval==1)?"restart":"shutdown") + " from snmp://" + pdata[msgid]->community + "@" + pdata[msgid]->ip + "/\n"); +  if (attrval == 1) roxen->restart(0.5); +  if (attrval == 2) roxen->shutdown(0.5); +  } +  } else +  snmpbadcommuses++; +  break; +  case MIBTREE_BASE+".2.1.11.30.0": +  // The standard-based (RFC1213) method of disabling auth. traps +  if(chk_access("rw", pdata[msgid])) { +  setflg = 1; +  rdata[attrname] += ({ "int", attrval }); +  rdata["1.3.6.1.2.1.1.3.0"] += ({"tick", get_uptime() }); +  if(attrval == 0 || attrval == 1) { +  report_warning("SNMPagent: Requested " + attrval?"en":"dis" + "abling of auth. traps from snmp://" + pdata[msgid]->community + "@" + pdata[msgid]->ip + "/\n"); +  // here will be ena/disabling of such traps +  } +  } else +  snmpbadcommuses++; +  break; + */ +    SNMPagent snmpagent;   //! Global SNMPagent object