]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Updated to cmu v1.8 + coded almost from scratch
authorkostas <>
Sun, 22 Feb 1998 18:57:16 +0000 (18:57 +0000)
committerkostas <>
Sun, 22 Feb 1998 18:57:16 +0000 (18:57 +0000)
src/snmp_agent.cc

index f9e7dd1d729f2edc3aca035987b2d72ff70a2e0a..e0af9bff94edef3a7cae56fc425951d6ac27a98b 100644 (file)
@@ -1,29 +1,3 @@
-/*
- * Simple Network Management Protocol (RFC 1067).
- *
- */
-/***********************************************************
-       Copyright 1988, 1989 by Carnegie Mellon University
-
-                      All Rights Reserved
-
-Permission to use, copy, modify, and distribute this software and its 
-documentation for any purpose and without fee is hereby granted, 
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in 
-supporting documentation, and that the name of CMU not be
-used in advertising or publicity pertaining to distribution of the
-software without specific, written prior permission.  
-
-CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
-CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
-ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
-SOFTWARE.
-******************************************************************/
-
 #include "squid.h"
 
 #include "snmp.h"
@@ -31,953 +5,769 @@ SOFTWARE.
 #include "asn1.h"
 #include "snmp_api.h"
 #include "snmp_client.h"
+#include "snmp_vars.h"
+#include "snmp_oidlist.h"
+#include "cache_snmp.h"
 
 #include "mib.h"
 
-#include "snmp_groupvars.h"
-
-void snmp_input();
-void snmp_trap();
-int create_identical();
-int parse_var_op_list();
-
-struct pbuf *definitelyGetBuf();
-int get_community();
-
-extern communityEntry *communities;
-extern usecEntry *users;
-extern viewEntry *views;
-extern int maintenanceView;
-
-/* these can't be global in a multi-process router */
-u_char sid[SID_MAX_LEN + 1];
-int sidlen;
-u_char *packet_end;
-
-struct snmp_session _session;
-struct snmp_session *session = &_session;
-
-u_char _agentID[12] =
-{0};
-u_long _agentBoots;
-u_long _agentStartTime;
-u_long _agentSize;
-
-
-/* fwd: */
-static int check_auth(struct snmp_session *, u_char *, int, u_char *, int, usecEntry **);
-static int bulk_var_op_list(u_char *, int, u_char *, int, int, int, long *);
-static int goodValue(u_char, int, u_char, int);
-static void setVariable(u_char *, u_char, int, u_char *, int);
-/* from usec.c: */
-extern void increment_stat();
-extern void create_report();
-extern void md5Digest();
-extern int parse_parameters();
-
-int
-init_agent_auth(void)
-{
-    char hostname[256];
-    struct hostent *hp;
-    FILE *f;
-    /* comes from snmpd.c: */
-
-    /* agentID is based on enterprise number and local IP address */
-    /* not "settable, thus, if agentBoots=0xffffffff, then all keys should be changed */
-    if (gethostname(hostname, sizeof(hostname)) != 0) {
-       fatal("snmpd: cannot get hostname");
-       return -1;
-    }
-    if ((hp = gethostbyname(hostname)) == NULL) {
-       fatal("snmpd: cannot determine local hostname");
-       return -1;
-    }
-    _agentID[3] = 35;          /* BNR private enterprise number */
-    xmemcpy(&_agentID[4], hp->h_addr, hp->h_length);
-
-    if (Config.Snmp.agentInfo == NULL) {
-       debug(49, 1) ("init_agent_auth: WARNING: Config.Snmp.agentInfo == NULL\n");
-       return -1;
-    }
-    if ((f = fopen(Config.Snmp.agentInfo, "r+")) == NULL) {
-       debug(49, 5) ("init_agent_auth: Agent not installed properly, cannot open '%s'\n",
-           Config.Snmp.agentInfo);
-       debug(49, 5) ("init_agent_auth: Create a empty file '%s'. This is used for\n",
-           Config.Snmp.agentInfo);
-       debug(49, 5) ("NV store of the agentBoots object.\n");
-       return -1;
-    }
-    fscanf(f, "%ld", &_agentBoots);
-    _agentBoots++;
-    fseek(f, 0, 0);
-    fprintf(f, "%ld\n", _agentBoots);
-    fclose(f);
+enum { HTTP_SVC, ICP_SVC, DNS_SVC };
 
+static struct snmp_pdu *snmp_agent_response(struct snmp_pdu *PDU);
+struct snmp_session *Session;
+extern StatCounters *CountHist;
+extern int get_median_svc(int,int);
 
-    _agentStartTime = -time(NULL);
+/* returns: 
+       2: no such object in this mib
+        1: ok
+       0: failed */
 
-    _agentSize = SNMP_MAX_LEN;
-
-    return 0;
-}
-
-int
-snmp_agent_parse(u_char * sn_data,
-    int length,
-    u_char * out_sn_data,
-    int *out_length,
-    u_long sourceip,           /* possibly for authentication */
-    long *ireqid)
+int snmp_agent_parse(u_char *buf, int len, u_char *outbuf, int *outlen,
+        u_long from_addr, long * this_reqid)
 {
-    u_char msgtype, type;
-    long zero = 0;
-    long reqid, errstat, errindex, dummyindex;
-    u_char *out_auth, *out_header, *out_reqid;
-    u_char *startData = sn_data;
-    int startLength = length;
-    long version;
-    u_char *origsn_data = sn_data;
-    int origlen = length;
-    usecEntry *ue;
-    int ret = 0, packet_len;
-
-    sidlen = SID_MAX_LEN;
-    sn_data = snmp_auth_parse(sn_data, &length, sid, &sidlen, &version);
-    if (sn_data == NULL) {
-       increment_stat(SNMP_STAT_ENCODING_ERRORS);
-       debug(49, 5) ("snmp_agent_parse: bad auth encoding\n");
-       return 0;
-    }
-    if (version != SNMP_VERSION_1 && version != SNMP_VERSION_2C && version != SNMP_VERSION_2) {
-       increment_stat(SNMP_STAT_ENCODING_ERRORS);
-       debug(49, 5) ("snmp_agent_parse: wrong version\n");
-#ifdef linux
-       snmp_inbadversions++;
-#endif
-       return 0;
-    }
-    if (version == SNMP_VERSION_2C || version == SNMP_VERSION_2) {
-       if (version == SNMP_VERSION_2) {
-           ret = check_auth(session, origsn_data, origlen, sn_data - sidlen, sidlen, &ue);
-           *out_length = (SNMP_MAX_LEN < session->MMS) ? SNMP_MAX_LEN : session->MMS;
-           session->MMS = SNMP_MAX_LEN;
-
-       } else if (version == SNMP_VERSION_2C) {
-           ret = get_community(sid);
-           session->version = SNMP_VERSION_2C;
-       }
-       if (ret < 0) {
-           increment_stat(-ret);
-           if ((sn_data = asn_parse_header(sn_data, &length, &msgtype)) != NULL
-               && asn_parse_int(sn_data, &length, &type, &reqid, sizeof(reqid))) {
-               if (msgtype == REPORT_MSG)
-                   return 0;
-               if (!(session->qoS & USEC_QOS_GENREPORT))
-                   return 0;
-               session->agentBoots = _agentBoots;
-               session->agentClock = _agentStartTime;
-               xmemcpy(session->agentID, _agentID, 12);
-               session->MMS = SNMP_MAX_LEN;
-               create_report(session, out_sn_data, out_length, -ret, reqid);
-               return 1;
-           } else {
-               debug(49, 5) ("snmp_agent_parse: asn_parse failed\n");
-               return 0;
-           }
-       } else if (ret > 0) {
-           increment_stat(ret);
-           debug(49, 5) ("snmp_agent_parse: authorization failed ret=%d\n", ret);
-           return 0;
-       }
-    } else if (version == SNMP_VERSION_1) {
-       if ((ret = get_community(sid)) != 0) {
-           increment_stat(ret);
-           debug(49, 5) ("snmp_agent_parse: get_community failed\n");
-           return 0;
-       }
-       session->version = SNMP_VERSION_1;
-    } else {
-       increment_stat(SNMP_STAT_ENCODING_ERRORS);
-       debug(49, 5) ("snmp_agent_parse : wrong version\n");
-#ifdef linux
-       snmp_inbadversions++;
+   struct snmp_pdu *PDU, *RespPDU;
+   u_char *Community;
+   int ret;
+   /* Now that we have the data, turn it into a PDU */
+   PDU = snmp_pdu_create(0);
+   Community = snmp_parse(Session, PDU, buf, len);
+   if (Community == NULL) {
+     debug(49,8)("snmp_agent_parse: Community == NULL\n");
+
+     snmp_free_pdu(PDU);
+     return 0;
+   }
+#if 0
+  if (!community_check(Community)) {
+    xfree(Community);
+    /* Wrong community! XXXXX */
+  }
 #endif
-       return 0;
-    }
 
-    sn_data = asn_parse_header(sn_data, &length, &msgtype);
-    if (sn_data == NULL) {
-       increment_stat(SNMP_STAT_ENCODING_ERRORS);
-       debug(49, 5) ("snmp_agent_parse: bad header\n");
-       return 0;
-    }
-#ifdef linux
-    /* XXX: increment by total number of vars at correct place: */
-    snmp_intotalreqvars++;
-    if (msgtype == GET_REQ_MSG)
-       snmp_ingetrequests++;
-    if (msgtype == GETNEXT_REQ_MSG)
-       snmp_ingetnexts++;
-    if (msgtype == SET_REQ_MSG)
-       snmp_insetrequests++;
+  xfree(Community);
+  debug(49,5)("snmp_agent_parse: reqid=%d\n",PDU->reqid);
+  RespPDU = snmp_agent_response(PDU);
+  snmp_free_pdu(PDU);
+  if (RespPDU == NULL) {
+     debug(49,8)("snmp_agent_parse: RespPDU == NULL\n");
+    return 2;
+  }
+  debug(49,8)("snmp_agent_parse: Response pdu (%x) errstat=%d reqid=%d.\n", 
+               RespPDU,RespPDU->errstat,RespPDU->reqid);
+#if 0
+  if (RespPDU->variables) {
+       debug(49,8)("snmp_agent_parse: len=%d\n", RespPDU->variables->val_len);
+  }
 #endif
+  /* Encode it */
+  ret = snmp_build(Session, RespPDU, outbuf, outlen);
+  /* XXXXX Handle failure */
+  snmp_free_pdu(RespPDU);
+  return 1;
+}
 
-    if (msgtype == GETBULK_REQ_MSG) {
-       if (session->version == SNMP_VERSION_1) {
-           debug(49, 5) ("snmp_agent_parse: getbulk but version 1\n");
-           return 0;
-       }
-    } else if (msgtype != GET_REQ_MSG && msgtype != GETNEXT_REQ_MSG && msgtype != SET_REQ_MSG) {
-       debug(49, 5) ("snmp_agent_parse: unknown request type\n");
-       return 0;
-    }
-    sn_data = asn_parse_int(sn_data, &length, &type, &reqid, sizeof(reqid));
-    if (sn_data == NULL) {
-       increment_stat(SNMP_STAT_ENCODING_ERRORS);
-       debug(49, 5) ("snmp_agent_parse: bad parse of reqid\n");
-       return 0;
-    }
-    sn_data = asn_parse_int(sn_data, &length, &type, &errstat, sizeof(errstat));
-    if (sn_data == NULL) {
-       increment_stat(SNMP_STAT_ENCODING_ERRORS);
-       debug(49, 5) ("snmp_agent_parse: bad parse of errstat\n");
-#ifdef linux
-       snmp_inasnparseerrors++;
-#endif
-       return 0;
-    }
-    sn_data = asn_parse_int(sn_data, &length, &type, &errindex, sizeof(errindex));
-    if (sn_data == NULL) {
-       increment_stat(SNMP_STAT_ENCODING_ERRORS);
-       debug(49, 5) ("bad parse of errindex\n");
-       return 0;
-    }
-    /*
-     * Now start cobbling together what is known about the output packet.
-     * The final lengths are not known now, so they will have to be recomputed
-     * later.
-     */
-
-    /* setup for response */
-    time((time_t *) & session->agentTime);
-    session->agentClock = _agentStartTime;
-    session->agentBoots = _agentBoots;
-    xmemcpy(session->agentID, _agentID, 12);
-
-    out_auth = out_sn_data;
-    out_header = snmp_auth_build(out_auth, out_length, session, 1, 0);
-    if (out_header == NULL) {
-       debug(49, 5) ("snmp_agent_parse: snmp_auth_build failed\n");
-#ifdef linux
-       snmp_inasnparseerrors++;
-#endif
-       return 0;
-    }
-    out_reqid = asn_build_sequence(out_header, out_length, (u_char) GET_RSP_MSG, 0);
-    if (out_reqid == NULL) {
-       debug(49, 5) ("snmp_agent_parse; out_reqid == NULL\n");
-       return 0;
-    }
-    type = (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
-    /* return identical request id */
-    out_sn_data = asn_build_int(out_reqid, out_length, type, &reqid, sizeof(reqid));
-    if (out_sn_data == NULL) {
-       debug(49, 5) ("snmp_agent_parse; build reqid failed\n");
-       return 0;
-    }
-    /* assume that error status will be zero */
-    out_sn_data = asn_build_int(out_sn_data, out_length, type, &zero, sizeof(zero));
-    if (out_sn_data == NULL) {
-       debug(49, 5) ("snmp_agent_parse: build errstat failed\n");
-       return 0;
-    }
-    /* assume that error index will be zero */
-    out_sn_data = asn_build_int(out_sn_data, out_length, type, &zero, sizeof(zero));
-    if (out_sn_data == NULL) {
-       debug(49, 5) ("snmp_agent_parse: build errindex failed\n");
-       return 0;
-    }
-    if (msgtype == GETBULK_REQ_MSG)
-       errstat = bulk_var_op_list(sn_data, length, out_sn_data, *out_length,
-           errstat, errindex, &errindex);
-    else
-       errstat = parse_var_op_list(sn_data, length, out_sn_data, *out_length,
-           &errindex, msgtype, SNM_RESERVE1);
-
-    if (errstat == SNMP_ERR_NOSUCHNAME) {
-       /* see if we have forwarding turned on */
-       if (Config.Snmp.localPort != 0) {
-           *ireqid = reqid;
-           return 2;
-       }
-    }
-    if (msgtype == SET_REQ_MSG) {
-       if (errstat == SNMP_ERR_NOERROR)
-           errstat = parse_var_op_list(sn_data, length, out_sn_data, *out_length,
-               &errindex, msgtype, SNM_RESERVE2);
-       if (errstat == SNMP_ERR_NOERROR) {
-           /*
-            * SETS require 3-4 passes through the var_op_list.  The first two
-            * passes verify that all types, lengths, and values are valid
-            * and may reserve resources and the third does the set and a
-            * fourth executes any actions.  Then the identical GET RESPONSE
-            * packet is returned.
-            * If either of the first two passes returns an error, another
-            * pass is made so that any reserved resources can be freed.
-            */
-           parse_var_op_list(sn_data, length, out_sn_data, *out_length,
-               &dummyindex, msgtype, SNM_COMMIT);
-           parse_var_op_list(sn_data, length, out_sn_data, *out_length,
-               &dummyindex, msgtype, SNM_ACTION);
-           if (create_identical(startData, out_auth, startLength, 0L, 0L)) {
-               *out_length = packet_end - out_auth;
-               return 1;
-           }
-           debug(49, 5) ("snmp_agent_parse: problem in ERR_NOERROR\n");
-           return 0;
-       } else {
-           parse_var_op_list(sn_data, length, out_sn_data, *out_length,
-               &dummyindex, msgtype, SNM_FREE);
-       }
-    }
-    switch ((short) errstat) {
-    case SNMP_ERR_NOERROR:
-       /* re-encode the headers with the real lengths */
-       *out_length = packet_end - out_header;
-       packet_len = *out_length;
-       out_sn_data = asn_build_sequence(out_header, out_length, GET_RSP_MSG,
-           packet_end - out_reqid);
-       if (out_sn_data != out_reqid) {
-           debug(49, 5) ("snmp_agent_parse: internal error: header\n");
-           return 0;
-       }
-       *out_length = packet_end - out_auth;
-       out_sn_data = snmp_auth_build(out_auth, out_length, session, 1, packet_end - out_header);
 
-       *out_length = packet_end - out_auth;
-#if 0
-       /* packet_end is correct for old SNMP.  This dichotomy needs
-        * to be fixed. */
-       if (session->version == SNMP_VERSION_2)
-           packet_end = out_auth + packet_len;
+
+static struct snmp_pdu *snmp_agent_response(struct snmp_pdu *PDU)
+{
+  struct snmp_pdu *Answer = NULL;
+  variable_list *VarPtr, *VarNew = NULL;
+  variable_list **VarPtrP, **RespVars;
+  int index = 0;
+  oid_ParseFn *ParseFn;
+
+#ifdef DEBUG_SNMP
+  printf("Received a %d PDU\n", PDU->command);
 #endif
-       break;
-    case SNMP_ERR_TOOBIG:
-       snmp_intoobigs++;
-#ifdef NOT_DONE
-       if (session->version == SNMP_VERSION_2) {
-           create_toobig(out_auth, *out_length, reqid, pi);
-           break;
-       }
-       /* else FALLTHRU */
+
+  /* Create a response */
+  Answer = snmp_pdu_create(SNMP_PDU_RESPONSE);
+  if (Answer == NULL)
+    return(NULL);
+  Answer->reqid = PDU->reqid;
+  Answer->errindex = 0;
+
+  if (PDU->command == SNMP_PDU_GET) {
+
+    RespVars = &(Answer->variables);
+    /* Loop through all variables */
+    for (VarPtrP = &(PDU->variables); 
+       *VarPtrP; 
+       VarPtrP = &((*VarPtrP)->next_variable)) {
+      VarPtr = *VarPtrP;
+
+      index++;
+
+      /* Find the parsing function for this variable */
+      ParseFn = oidlist_Find(VarPtr->name, VarPtr->name_length);
+
+      if (ParseFn == NULL) {
+      Answer->errstat = SNMP_ERR_NOSUCHNAME;
+      debug(49,5)("snmp_agent_response: No such oid. ");
+      } else
+      VarNew = (*ParseFn)(VarPtr, (long *)&(Answer->errstat));
+
+      /* Was there an error? */
+      if ((Answer->errstat != SNMP_ERR_NOERROR) ||
+        (VarNew == NULL)) {
+      Answer->errindex = index;
+       debug(49,5)("snmp_agent_parse: successful.\n");
+      /* Just copy the rest of the variables.  Quickly. */
+      *RespVars = VarPtr;
+      *VarPtrP = NULL;
+      return(Answer);
+      }
+
+      /* No error.  Insert this var at the end, and move on to the next.
+       */
+      *RespVars = VarNew;
+      RespVars = &(VarNew->next_variable);
+    }
+
+    return(Answer);
+  }
+
+  else if (PDU->command == SNMP_PDU_GETNEXT) {
+    oid *TmpOidName;
+    int TmpOidNameLen = 0;
+
+    /* Find the next OID. */
+    VarPtr = PDU->variables;
+
+    ParseFn = oidlist_Next(VarPtr->name, VarPtr->name_length,
+                         &(TmpOidName), (long *)&(TmpOidNameLen));
+
+    if (ParseFn == NULL) {
+      Answer->errstat = SNMP_ERR_NOSUCHNAME;
+#ifdef DEBUG_SNMP
+      printf("No such oid: ");
+      print_oid(VarPtr->name, VarPtr->name_length);
 #endif
-    case SNMP_ERR_NOACCESS:
-    case SNMP_ERR_WRONGTYPE:
-    case SNMP_ERR_WRONGLENGTH:
-    case SNMP_ERR_WRONGENCODING:
-    case SNMP_ERR_WRONGVALUE:
-    case SNMP_ERR_NOCREATION:
-    case SNMP_ERR_INCONSISTENTVALUE:
-    case SNMP_ERR_RESOURCEUNAVAILABLE:
-    case SNMP_ERR_COMMITFAILED:
-    case SNMP_ERR_UNDOFAILED:
-    case SNMP_ERR_AUTHORIZATIONERROR:
-    case SNMP_ERR_NOTWRITABLE:
-    case SNMP_ERR_INCONSISTENTNAME:
-    case SNMP_ERR_NOSUCHNAME:
-    case SNMP_ERR_BADVALUE:
-    case SNMP_ERR_READONLY:
-    case SNMP_ERR_GENERR:
-       if (create_identical(startData, out_auth, startLength, errstat,
-               errindex)) {
-           *out_length = packet_end - out_auth;
-           return 1;
-       }
-       debug(49, 5) ("snmp_agent_parse: create_identical failed\n");
-       return 0;
-    default:
-       debug(49, 5) ("snmp_agent_parse: hey, something's wrong\n");
-       return 0;
+    } else {
+      xfree(VarPtr->name);
+      VarPtr->name = TmpOidName;
+      VarPtr->name_length = TmpOidNameLen;      
+      VarNew = (*ParseFn)(VarPtr, (long *)&(Answer->errstat));
     }
 
-    if (session->qoS & USEC_QOS_AUTH) {
-       md5Digest(out_auth, *out_length, out_sn_data - (session->contextLen + 16),
-           out_sn_data - (session->contextLen + 16));
-    }
-    return 1;
-}
+    /* Was there an error? */
+    if (Answer->errstat != SNMP_ERR_NOERROR) {
+      Answer->errindex = 1;
 
-/*
- * Parse_var_op_list goes through the list of variables and retrieves each one,
- * placing it's value in the output packet.  In the case of a set request,
- * if action is RESERVE, the value is just checked for correct type and
- * value, and resources may need to be reserved.  If the action is COMMIT,
- * the variable is set.  If the action is FREE, an error was discovered
- * somewhere in the previous RESERVE pass, so any reserved resources
- * should be FREE'd.
- * If any error occurs, an error code is returned.
- */
-int
-parse_var_op_list(u_char * sn_data,
-    int length,
-    u_char * out_sn_data,
-    int out_length,
-    long *index,
-    int msgtype,
-    int action)
-{
-    u_char type;
-    oid var_name[MAX_NAME_LEN];
-    int var_name_len, var_val_len;
-    u_char var_val_type, *var_val, statType;
-    u_char *statP;
-    int statLen = 0;
-    u_short acl;
-    int rw, exact, err;
-    int (*write_method) ();
-    u_char *headerP, *var_list_start;
-    int dummyLen;
-    u_char *getStatPtr();
-    int noSuchObject;
-
-    if (msgtype == SET_REQ_MSG)
-       rw = WRITE;
-    else
-       rw = READ;
-    if (msgtype == GETNEXT_REQ_MSG) {
-       exact = FALSE;
+      /* Just copy this variable */
+      Answer->variables = VarPtr;
+      PDU->variables = NULL;
     } else {
-       exact = TRUE;
-    }
-    sn_data = asn_parse_header(sn_data, &length, &type);
-    if (sn_data == NULL) {
-       debug(49, 5) ("parse_var_op_list: not enough space for varlist\n");
-       return PARSE_ERROR;
-    }
-    if (type != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
-       debug(49, 5) ("parse_var_op_list: wrong type\n");
-       return PARSE_ERROR;
-    }
-    headerP = out_sn_data;
-    out_sn_data = asn_build_sequence(out_sn_data, &out_length,
-       (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
-    if (out_sn_data == (u_char *) NULL) {
-       debug(49, 5) ("parse_var_op_list: not enough space in output packet\n");
-       return BUILD_ERROR;
+      Answer->variables = VarNew;
     }
-    var_list_start = out_sn_data;
-
-    *index = 1;
-    while ((int) length > 0) {
-       /* parse the name, value pair */
-       var_name_len = MAX_NAME_LEN;
-       sn_data = snmp_parse_var_op(sn_data, var_name, &var_name_len, &var_val_type,
-           &var_val_len, &var_val, (int *) &length);
-       if (sn_data == NULL)
-           return PARSE_ERROR;
-       /* now attempt to retrieve the variable on the local entity */
-       debug(49, 5) ("snmp:before getStatPtr...\n");
-       statP = getStatPtr(var_name, &var_name_len, &statType, &statLen, &acl,
-           exact, &write_method, session->version, &noSuchObject,
-           msgtype == SET_REQ_MSG ? session->writeView : session->readView);
-       if (session->version == SNMP_VERSION_1 && statP == NULL
-           && (msgtype != SET_REQ_MSG || !write_method)) {
-           debug(49, 5) ("parse_var_op_list: internal v1_error\n");
-           return SNMP_ERR_NOSUCHNAME;
-       }
-       /* check if this variable is read-write (in the MIB sense). */
-       if (msgtype == SET_REQ_MSG && acl != RWRITE)
-           return session->version == SNMP_VERSION_1 ? SNMP_ERR_NOSUCHNAME : SNMP_ERR_NOTWRITABLE;
-
-       /* Its bogus to check here on getnexts - the whole packet shouldn't
-        * be dumped - this should should be the loop in getStatPtr
-        * luckily no objects are set unreadable.  This can still be
-        * useful for sets to determine which are intrinsically writable */
-
-       if (msgtype == SET_REQ_MSG) {
-           if (write_method == NULL) {
-               if (statP != NULL) {
-                   /* see if the type and value is consistent with this
-                    * entity's variable */
-                   if (!goodValue(var_val_type, var_val_len, statType,
-                           statLen)) {
-                       if (session->version != SNMP_VERSION_1)
-                           return SNMP_ERR_WRONGTYPE;  /* poor approximation */
-                       else {
-                           snmp_inbadvalues++;
-                           return SNMP_ERR_BADVALUE;
-                       }
-                   }
-                   /* actually do the set if necessary */
-                   if (action == SNM_COMMIT)
-                       setVariable(var_val, var_val_type, var_val_len,
-                           statP, statLen);
-               } else {
-                   if (session->version != SNMP_VERSION_1)
-                       return SNMP_ERR_NOCREATION;
-                   else
-                       return SNMP_ERR_NOSUCHNAME;
-               }
-           } else {
-               err = (*write_method) (action, var_val, var_val_type,
-                   var_val_len, statP, var_name,
-                   var_name_len);
-
-               /*
-                * Map the SNMPv2 error codes to SNMPv1 error codes (RFC 2089).
-                */
-
-               if (session->version == SNMP_VERSION_1) {
-                   switch (err) {
-                   case SNMP_ERR_NOERROR:
-                       /* keep the no-error error: */
-                       break;
-                   case SNMP_ERR_WRONGVALUE:
-                   case SNMP_ERR_WRONGENCODING:
-                   case SNMP_ERR_WRONGTYPE:
-                   case SNMP_ERR_WRONGLENGTH:
-                   case SNMP_ERR_INCONSISTENTVALUE:
-                       err = SNMP_ERR_BADVALUE;
-                       break;
-                   case SNMP_ERR_NOACCESS:
-                   case SNMP_ERR_NOTWRITABLE:
-                   case SNMP_ERR_NOCREATION:
-                   case SNMP_ERR_INCONSISTENTNAME:
-                   case SNMP_ERR_AUTHORIZATIONERROR:
-                       err = SNMP_ERR_NOSUCHNAME;
-                       break;
-                   default:
-                       err = SNMP_ERR_GENERR;
-                       break;
-                   }
-               }
-               if (err != SNMP_ERR_NOERROR) {
-                   if (session->version == SNMP_VERSION_1) {
-                       snmp_inbadvalues++;
-                   }
-                   return err;
-               }
-           }
-       } else {
-           /* retrieve the value of the variable and place it into the
-            * outgoing packet */
-           if (statP == NULL) {
-               statLen = 0;
-               if (exact) {
-                   if (noSuchObject == TRUE) {
-                       statType = SNMP_NOSUCHOBJECT;
-                   } else {
-                       statType = SNMP_NOSUCHINSTANCE;
-                   }
-               } else {
-                   statType = SNMP_ENDOFMIBVIEW;
-               }
-           }
-           out_sn_data = snmp_build_var_op(out_sn_data, var_name, &var_name_len,
-               statType, statLen, statP,
-               &out_length);
-           if (out_sn_data == NULL) {
-               return SNMP_ERR_TOOBIG;
-           }
-       }
 
-       (*index)++;
-    }
-    if (msgtype != SET_REQ_MSG) {
-       /* save a pointer to the end of the packet */
-       packet_end = out_sn_data;
-
-       /* Now rebuild header with the actual lengths */
-       dummyLen = packet_end - var_list_start;
-       if (asn_build_sequence(headerP, &dummyLen,
-               (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
-               dummyLen) == NULL) {
-           return SNMP_ERR_TOOBIG;     /* bogus error ???? */
-       }
-    }
-    *index = 0;
-    return SNMP_ERR_NOERROR;
+    /* Done.  Return this PDU */
+    return(Answer);
+  } /* end SNMP_PDU_GETNEXT */
+  
+#ifdef DEBUG_SNMP
+  printf("Ignoring PDU %d\n", PDU->command);
+#endif
+  snmp_free_pdu(Answer);
+  return(NULL);
 }
 
-/*
- * create a packet identical to the input packet, except for the error status
- * and the error index which are set according to the input variables.
- * Returns 1 upon success and 0 upon failure.
- */
-int
-create_identical(u_char * snmp_in,
-    u_char * snmp_out,
-    int snmp_length,
-    long errstat,
-    long errindex)
+char private_community[]= "public";
+
+int community_check(char *b)
 {
-    u_char *sn_data;
-    u_char type;
-    u_long dummy;
-    int length, headerLength;
-    u_char *headerPtr, *reqidPtr, *errstatPtr, *errindexPtr, *varListPtr;
-
-    memcpy((char *) snmp_out, (char *) snmp_in, snmp_length);
-    length = snmp_length;
-    headerPtr = snmp_auth_parse(snmp_out, &length, sid, &sidlen, (long *) &dummy);
-    sid[sidlen] = 0;
-    if (headerPtr == NULL)
-       return 0;
-    reqidPtr = asn_parse_header(headerPtr, &length, (u_char *) & dummy);
-    if (reqidPtr == NULL)
-       return 0;
-    headerLength = length;
-    errstatPtr = asn_parse_int(reqidPtr, &length, &type, (long *) &dummy, sizeof dummy);       /* request id */
-    if (errstatPtr == NULL)
-       return 0;
-    errindexPtr = asn_parse_int(errstatPtr, &length, &type, (long *) &dummy, sizeof dummy);    /* error status */
-    if (errindexPtr == NULL)
-       return 0;
-    varListPtr = asn_parse_int(errindexPtr, &length, &type, (long *) &dummy, sizeof dummy);    /* error index */
-    if (varListPtr == NULL)
-       return 0;
-
-    sn_data = asn_build_header(headerPtr, &headerLength, GET_RSP_MSG, headerLength);
-    if (sn_data != reqidPtr)
-       return 0;
-    length = snmp_length;
-    type = (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
-    sn_data = asn_build_int(errstatPtr, &length, type, &errstat, sizeof errstat);
-    if (sn_data != errindexPtr)
-       return 0;
-    sn_data = asn_build_int(errindexPtr, &length, type, &errindex, sizeof errindex);
-    if (sn_data != varListPtr)
-       return 0;
-    packet_end = snmp_out + snmp_length;
-    return 1;
+  return(!strcmp(b, private_community));
 }
 
-static int
-check_auth(struct snmp_session *session,
-    u_char * sn_data,
-    int length,
-    u_char * pp,
-    int plen,
-    usecEntry ** ueret)
+int init_agent_auth()
 {
-    usecEntry *ue;
-    Parameters params;
-    int ret;
-
-    memset(session, 0, sizeof(*session));
-
-    *ueret = NULL;
-
-    session->version = SNMP_VERSION_2;
-
-    if ((ret = parse_parameters(pp, plen, &params)))
-       return ret;
-
-    /* setup session record for this packet */
-    /* setup before any error detection so report may be generated if required */
-    session->qoS = params.qoS;
-    xmemcpy(session->userName, params.userName, params.userLen);
-    session->userLen = params.userLen;
-    session->MMS = params.MMS;
-    session->contextLen = params.contextLen;
-    xmemcpy(session->contextSelector, params.contextSelector, params.contextLen);
-
-    /* agentID must be my agentID */
-    if (memcmp(_agentID, params.agentID, 12) != 0)
-       return -USEC_STAT_UNKNOWN_CONTEXT_SELECTORS;
-
-    /* only support the contextSelector of "" */
-    if (params.contextLen != 0)
-       return -USEC_STAT_UNKNOWN_CONTEXT_SELECTORS;
-
-    /* lookup the user in my local configuration sn_datastore (LCD) */
-    for (ue = users; ue; ue = ue->next) {
-       if (ue->userLen != params.userLen)
-           continue;
-       if (memcmp(ue->userName, params.userName, params.userLen) == 0)
-           break;
-    }
-
-    /* if reached end of sn_datastore, user not found */
-    if (ue == NULL)
-       return -USEC_STAT_UNKNOWN_USERNAMES;
-
-
-    /* verify that the requested qoS is supported by the userName */
-    if ((u_char) (params.qoS & USEC_QOS_AUTHPRIV) > ue->qoS)
-       return -USEC_STAT_UNSUPPORTED_QOS;
-
-    xmemcpy(session->authKey, ue->authKey, 16);
-
-    /* check digest and timeliness if this is an auth message */
-    if (params.qoS & USEC_QOS_AUTH) {
-       int upper, lower, agentTime;
+  Session = (struct snmp_session *)xmalloc(sizeof(struct snmp_session));
+  if (Session == NULL) {
+    perror("malloc");
+    return 3;
+  }
+
+  Session->Version=SNMP_VERSION_1;     
+  Session->authenticator = NULL;
+  Session->community = (u_char *)xstrdup("public");
+  Session->community_len = 6;
+       return 1;
+}
 
-       /* check the digest */
-       xmemcpy(params.authDigestPtr, ue->authKey, 16);
-       md5Digest(sn_data, length, ue->authKey, params.authDigestPtr);
-       if (memcmp(params.authDigest, params.authDigestPtr, 16) != 0)
-           return -USEC_STAT_WRONG_DIGEST_VALUES;
+/************************************************************************
 
-       /* check timeliness */
-       if (_agentBoots == 0xffffffff || _agentBoots != params.agentBoots)
-           return -USEC_STAT_NOT_IN_WINDOWS;
+ SQUID MIB Implementation
 
-       agentTime = _agentStartTime + time(NULL);
-       upper = agentTime + SNMP_MESSAGE_LIFETIME;
-       lower = agentTime - SNMP_MESSAGE_LIFETIME;
-       if (lower < 0)
-           lower = 0;
-       if (params.agentTime < lower || params.agentTime > upper)
-           return -USEC_STAT_NOT_IN_WINDOWS;
+ ************************************************************************/
 
-       session->readView = ue->authReadView;
-       session->writeView = ue->authWriteView;
-    } else {
-       session->readView = ue->noauthReadView;
-       session->writeView = ue->noauthWriteView;
-    }
+variable_list *snmp_basicFn(variable_list *Var, long *ErrP)
+{
+  variable_list *Answer;
+  char *pp;
+
+  debug(49,5)("snmp_basicFn: Processing request with magic %d!\n",Var->name[7]);
+
+  Answer = snmp_var_new(Var->name, Var->name_length);
+  *ErrP = SNMP_ERR_NOERROR;
+
+  switch (Var->name[7]) {
+    case VERSION_DESCR:
+    case VERSION_ID:
+     pp = SQUID_VERSION;
+     Answer->type = ASN_OCTET_STR;
+     Answer->val_len=strlen(pp);
+     Answer->val.string= (u_char *)xstrdup(pp);
+     break;
+    case UPTIME:
+    case SYSORLASTCHANGE:
+     Answer->val_len = sizeof(long);
+     Answer->val.integer = xmalloc(Answer->val_len);
+     Answer->type = ASN_INTEGER;
+     *(Answer->val.integer) = tvSubDsec(squid_start, current_time);
+     break;
+    case SYSCONTACT:
+     Answer->type = ASN_OCTET_STR;
+     Answer->val_len=strlen(Config.adminEmail);
+     Answer->val.string= (u_char *)xstrdup(Config.adminEmail);
+    case SYSYSNAME:
+     if (( pp= Config.visibleHostname) == NULL) 
+                pp=(char *)getMyHostname();
+     Answer->type = ASN_OCTET_STR;
+     Answer->val_len=strlen(pp);
+     Answer->val.string= (u_char *)xstrdup(pp);
+     break;
+    case SYSLOCATION:
+     pp = "Cyberspace";
+     Answer->type = ASN_OCTET_STR;
+     Answer->val_len=strlen(pp);
+     Answer->val.string= (u_char *)xstrdup(pp);
+     break;
+    case SYSSERVICES:
+     Answer->val_len = sizeof(long);
+     Answer->val.integer = xmalloc(Answer->val_len);
+     Answer->type = ASN_INTEGER;
+     *(Answer->val.integer) = 72;
+     break;
+  default:
+    *ErrP = SNMP_ERR_NOSUCHNAME;
+    snmp_var_free(Answer);
+    return(NULL);
+  }
+  debug(49,5)("snmp_basicFn: Done. returning a real value!\n");
+
+  return(Answer);
+}
 
-    return 0;
+variable_list *snmp_sysFn(variable_list *Var, long *ErrP)
+{
+  variable_list *Answer;
+  static fde *f=NULL;
+  int num=1,cnt=0;
+  static struct in_addr addr;
+  static long long_return;
+
+  debug(49,5)("snmp_sysFn: Processing request with magic %d: \n",Var->name[8]);
+  print_oid(Var->name, Var->name_length);
+
+  Answer = snmp_var_new(Var->name, Var->name_length);
+  *ErrP = SNMP_ERR_NOERROR;
+
+  switch(Var->name[8]) {
+  case SYSVMSIZ:
+     Answer->val_len = sizeof(long);
+     Answer->val.integer = xmalloc(Answer->val_len);
+     Answer->type = ASN_INTEGER;
+     *(Answer->val.integer) = store_mem_size;
+     break;
+  case SYSSTOR:
+     Answer->val_len = sizeof(long);
+     Answer->val.integer = xmalloc(Answer->val_len);
+     Answer->type = ASN_INTEGER;
+     *(Answer->val.integer) = store_swap_size;
+     break;
+  case SYSFDTBL:
+       num=Var->name[11];
+       debug(49,9)("snmp_sysFn: num=%d\n",num);
+        while (num && cnt < Squid_MaxFD) {
+            f = &fd_table[cnt++];
+            if (!f->open)
+                continue;
+            num--;
+       }
+       if (num!=0 || !f) {
+             debug(49,9)("snmp_sysFn: no such name. %x\n",f);
+              *ErrP = SNMP_ERR_NOSUCHNAME;
+              snmp_var_free(Answer);
+              return(NULL);
+       }
+       switch (Var->name[10]) {
+       case SYS_FD_NUMBER:
+              Answer->val_len = sizeof(long);
+              Answer->val.integer = xmalloc(Answer->val_len);
+              Answer->type = ASN_INTEGER;
+              *(Answer->val.integer)= Var->name[11];           
+              break;
+        case SYS_FD_TYPE:
+              Answer->val_len = sizeof(long);
+              Answer->val.integer = xmalloc(Answer->val_len);
+              Answer->type = ASN_INTEGER;
+              *(Answer->val.integer)= f->type;
+              break;
+        case SYS_FD_TOUT:
+              Answer->val_len = sizeof(long);
+              Answer->val.integer = xmalloc(Answer->val_len);
+              Answer->type = ASN_INTEGER;
+              *(Answer->val.integer)= (long) (f->timeout_handler ? (f->timeout - squid_curtime)/ 60 : 0);
+              break;
+        case SYS_FD_NREAD:
+              Answer->val_len = sizeof(long);
+              Answer->val.integer = xmalloc(Answer->val_len);
+              Answer->type = ASN_INTEGER;
+              *(Answer->val.integer)= (long) f->bytes_read;
+              break;
+        case SYS_FD_NWRITE:
+              Answer->val_len = sizeof(long);
+              Answer->val.integer = xmalloc(Answer->val_len);
+              Answer->type = ASN_INTEGER;
+              *(Answer->val.integer)= (long) f->bytes_written;
+              break;
+        case SYS_FD_ADDR:
+              if (f->type != FD_SOCKET)
+                       long_return = (long) 0;
+               else {
+                       safe_inet_addr(f->ipaddr, &addr);
+                       long_return = (long) addr.s_addr;
+               }
+               Answer->val_len = sizeof(long);
+               Answer->val.integer = xmalloc(Answer->val_len);
+               Answer->type = SMI_IPADDRESS;
+               *(Answer->val.integer)= (long) long_return;
+              break;
+        case SYS_FD_NAME:
+              Answer->type = ASN_OCTET_STR;
+              Answer->val_len=strlen(f->desc);
+              Answer->val.string= (u_char *)xstrdup(f->desc);
+              break;
+       default:
+               *ErrP = SNMP_ERR_NOSUCHNAME;
+               snmp_var_free(Answer);
+               return(NULL);
+       }
+       break;
+   default:
+     *ErrP = SNMP_ERR_NOSUCHNAME;
+     snmp_var_free(Answer);
+     return(NULL);
+  }
+  debug(49,5)("snmp_sysFn: Done. returning a real value!\n");
+  return Answer;
 }
 
-int
-get_community(char *sessionid)
+variable_list *snmp_confFn(variable_list *Var, long *ErrP)
 {
-    communityEntry *cp;
-    debug(49, 5) ("get_community: %s\n", sessionid);
-    for (cp = Config.Snmp.communities; cp; cp = cp->next) {
-       debug(49, 5) ("get_community: %s\n", cp->name);
-       if (!strcmp(cp->name, sessionid))
-           break;
+  variable_list *Answer;
+  char *cp=NULL;
+
+  debug(49,5)("snmp_confFn: Processing request with magic %d!\n",Var->name[8]);
+
+  Answer = snmp_var_new(Var->name, Var->name_length);
+  *ErrP = SNMP_ERR_NOERROR;
+
+  switch(Var->name[8]) {
+    case CONF_ADMIN:
+     Answer->type = ASN_OCTET_STR;
+     Answer->val_len=strlen(Config.adminEmail);
+     Answer->val.string= (u_char *)xstrdup(Config.adminEmail);
+     break;
+    case CONF_UPTIME:
+     Answer->val_len = sizeof(long);
+     Answer->val.integer = xmalloc(Answer->val_len);
+     Answer->type = ASN_INTEGER;
+     *(Answer->val.integer) = tvSubDsec(squid_start, current_time);
+     break;
+    case CONF_STORAGE:
+     switch (Var->name[9]) {
+       case CONF_ST_MMAXSZ:
+               Answer->val_len = sizeof(long);
+               Answer->val.integer = xmalloc(Answer->val_len);
+               Answer->type = ASN_INTEGER;
+               *(Answer->val.integer) = (long) Config.Mem.maxSize;
+               break;
+       case CONF_ST_MHIWM:
+               Answer->val_len = sizeof(long);
+               Answer->val.integer = xmalloc(Answer->val_len);
+               Answer->type = ASN_INTEGER;
+               *(Answer->val.integer) = (long) Config.Mem.highWaterMark;
+               break;
+       case CONF_ST_MLOWM:
+               Answer->val_len = sizeof(long);
+               Answer->val.integer = xmalloc(Answer->val_len);
+               Answer->type = ASN_INTEGER;
+               *(Answer->val.integer) = (long) Config.Mem.lowWaterMark;
+               break;
+       case CONF_ST_SWMAXSZ:
+               Answer->val_len = sizeof(long);
+               Answer->val.integer = xmalloc(Answer->val_len);
+               Answer->type = ASN_INTEGER;
+               *(Answer->val.integer) = (long) Config.Swap.maxSize;
+               break;
+       case CONF_ST_SWHIWM:
+               Answer->val_len = sizeof(long);
+               Answer->val.integer = xmalloc(Answer->val_len);
+               Answer->type = ASN_INTEGER;
+               *(Answer->val.integer) = (long) Config.Swap.highWaterMark;
+               break;
+       case CONF_ST_SWLOWM:
+               Answer->val_len = sizeof(long);
+               Answer->val.integer = xmalloc(Answer->val_len);
+                       Answer->type = ASN_INTEGER;
+               *(Answer->val.integer) = (long) Config.Swap.lowWaterMark;
+               break;
+       default:
+               *ErrP = SNMP_ERR_NOSUCHNAME;
+               snmp_var_free(Answer);
+               return(NULL);
+       }
+       break;
+      case CONF_WAIS_RHOST:
+        if (Config.Wais.relayHost)
+            cp = Config.Wais.relayHost;
+        else
+            cp = "None";
+        Answer->type = ASN_OCTET_STR;
+        Answer->val_len=strlen(cp);
+        Answer->val.string= (u_char *)xstrdup(cp);
+        break;
+    case CONF_WAIS_RPORT:
+        Answer->val_len = sizeof(long);
+        Answer->val.integer = xmalloc(Answer->val_len);
+        Answer->type = ASN_INTEGER;
+        *(Answer->val.integer) = (long) Config.Wais.relayPort;
+       break;
+    case CONF_TIO:
+       switch (Var->name[9]) {
+       case CONF_TIO_RD:
+                Answer->val_len = sizeof(long);
+                Answer->val.integer = xmalloc(Answer->val_len);
+                Answer->type = ASN_INTEGER;
+                *(Answer->val.integer) = (long) Config.Timeout.read;
+               break;
+       case CONF_TIO_CON:
+                Answer->val_len = sizeof(long);
+                Answer->val.integer = xmalloc(Answer->val_len);
+                Answer->type = ASN_INTEGER;
+                *(Answer->val.integer) = (long) Config.Timeout.connect;
+               break;
+       case CONF_TIO_REQ:
+                Answer->val_len = sizeof(long);
+                Answer->val.integer = xmalloc(Answer->val_len);
+                Answer->type = ASN_INTEGER;
+                *(Answer->val.integer) = (long) Config.Timeout.request;
+               break;
+       default:
+               *ErrP = SNMP_ERR_NOSUCHNAME;
+               snmp_var_free(Answer);
+               return(NULL);
+       }
+    case CONF_LOG_LVL:
+        if (!(cp = Config.debugOptions))
+            cp = "None";
+        Answer->type = ASN_OCTET_STR;
+        Answer->val_len=strlen(cp);
+        Answer->val.string= (u_char *)xstrdup(cp);
+        break;
+    default:
+       *ErrP = SNMP_ERR_NOSUCHNAME;
+       snmp_var_free(Answer);
+       return(NULL);
     }
+    return Answer;
+}
 
-    if (cp == NULL) {
-       snmp_inbadcommunitynames++;
-       return SNMP_STAT_V1_BAD_COMMUNITY_NAMES;
-    }
-    memset(session, 0, sizeof(*session));
-    session->community = (unsigned char *)sessionid;
-    session->community_len = strlen(sessionid);
-    session->readView = cp->readView;
-    session->writeView = cp->writeView;
+variable_list *snmp_confPtblFn(variable_list *Var, long *ErrP)
+{
+  variable_list *Answer;
+  char *cp=NULL;
+  peer *p=NULL;
+  int cnt;
+  debug(49,5)("snmp_confPtblFn: peer %d requested!\n",Var->name[11]);
+
+  Answer = snmp_var_new(Var->name, Var->name_length);
+  *ErrP = SNMP_ERR_NOERROR;
+  
+  p=Config.peers; 
+  cnt=Var->name[11];
+  debug(49,5)("snmp_confPtblFn: we want .x.%d\n",Var->name[10]);
+  while (--cnt) if (!(p=p->next));
+  if (p==NULL) {
+        *ErrP = SNMP_ERR_NOSUCHNAME;
+        snmp_var_free(Answer);
+        return(NULL);
+  }
+
+  switch (Var->name[10]) {
+    case CONF_PTBL_ID:
+        Answer->val_len = sizeof(long);
+        Answer->val.integer = xmalloc(Answer->val_len);
+        Answer->type = ASN_INTEGER;
+        *(Answer->val.integer) = (long) Var->name[10];
+       break;
+    case CONF_PTBL_NAME:
+        cp = p->host;
+        Answer->type = ASN_OCTET_STR;
+        Answer->val_len=strlen(cp);
+        Answer->val.string= (u_char *)xstrdup(cp);
+        break;
+    case CONF_PTBL_IP:
+        Answer->type = SMI_IPADDRESS;
+        Answer->val.integer = xmalloc(Answer->val_len);
+        Answer->val_len = sizeof(long);
+        *(Answer->val.integer) = (long) (p->in_addr.sin_addr.s_addr);
+        break;
+    case CONF_PTBL_HTTP:
+        Answer->val_len = sizeof(long);
+        Answer->val.integer = xmalloc(Answer->val_len);
+        Answer->type = ASN_INTEGER;
+        *(Answer->val.integer) = (long) p->http_port;
+       break;
+    case CONF_PTBL_ICP:
+        Answer->val_len = sizeof(long);
+        Answer->val.integer = xmalloc(Answer->val_len);
+        Answer->type = ASN_INTEGER;
+        *(Answer->val.integer) = (long) p->icp_port;
+       break;
+    case CONF_PTBL_TYPE:
+        Answer->val_len = sizeof(long);
+        Answer->val.integer = xmalloc(Answer->val_len);
+        Answer->type = ASN_INTEGER;
+        *(Answer->val.integer) = (long) p->type;
+       break;
+    case CONF_PTBL_STATE:
+        Answer->val_len = sizeof(long);
+        Answer->val.integer = xmalloc(Answer->val_len);
+        Answer->type = ASN_INTEGER;
+        *(Answer->val.integer) = (long) neighborUp(p);
+       break;
+    default:
+       *ErrP = SNMP_ERR_NOSUCHNAME;
+       snmp_var_free(Answer);
+       return(NULL);
+  } 
+  return Answer;
+}
 
-    return 0;
+variable_list *snmp_prfSysFn(variable_list *Var, long *ErrP)
+{
+  variable_list *Answer;
+  static struct rusage rusage;
+
+  debug(49,5)("snmp_prfSysFn: Processing request with magic %d!\n",Var->name[9]);
+
+  Answer = snmp_var_new(Var->name, Var->name_length);
+  *ErrP = SNMP_ERR_NOERROR;
+  Answer->val_len = sizeof(long);
+  Answer->val.integer = xmalloc(Answer->val_len);
+  Answer->type = ASN_INTEGER;
+
+  switch(Var->name[9]) {
+    case PERF_SYS_PF:
+     squid_getrusage(&rusage);
+     *(Answer->val.integer) = rusage_pagefaults(&rusage);
+     break;
+    case PERF_SYS_NUMR:
+     *(Answer->val.integer) = IOStats.Http.reads;
+     break; 
+    case PERF_SYS_DEFR:
+     *(Answer->val.integer) = IOStats.Http.reads_deferred;
+     break;
+    case PERF_SYS_MEMUSAGE:
+     *(Answer->val.integer) = (long) statMemoryAccounted() >> 10;
+     break;
+    case PERF_SYS_CPUUSAGE:
+     squid_getrusage(&rusage);
+     *(Answer->val.integer) = (long) rusage_cputime(&rusage);
+     break;
+    case PERF_SYS_MAXRESSZ:
+     squid_getrusage(&rusage);
+     *(Answer->val.integer) = (long) rusage_maxrss(&rusage);
+     break;
+    case PERF_SYS_CURLRUEXP:
+     Answer->type=SMI_TIMETICKS;
+     *(Answer->val.integer) = (long) ((double) storeExpiredReferenceAge() / 86400.0);
+     break;
+    case PERF_SYS_CURUNLREQ:
+     *(Answer->val.integer) = (long) Counter.unlink.requests;
+     break;
+    case PERF_SYS_CURUNUSED_FD:
+     *(Answer->val.integer) = (long) Squid_MaxFD - Number_FD;
+     break;
+    case PERF_SYS_CURRESERVED_FD:
+     *(Answer->val.integer) = (long) Number_FD;
+     break;
+    case PERF_SYS_NUMOBJCNT:
+     *(Answer->val.integer) = (long) memInUse(MEM_STOREENTRY);
+     break;
+    default:
+        *ErrP = SNMP_ERR_NOSUCHNAME;
+        snmp_var_free(Answer);
+        return(NULL);
+  } 
+  return Answer;
 }
 
-static int
-goodValue(u_char inType, int inLen, u_char actualType, int actualLen)
+variable_list *snmp_prfPeerFn(variable_list *Var, long *ErrP)
 {
-    if (inLen > actualLen)
-       return FALSE;
-    return (inType == actualType);
+  variable_list *Answer;
+  peer *p=NULL;
+  int cnt;
+  debug(49,5)("snmp_prfPeerFn: Processing request with magic %d!\n",Var->name[9]);
+
+  Answer = snmp_var_new(Var->name, Var->name_length);
+  *ErrP = SNMP_ERR_NOERROR;
+
+  p=Config.peers; 
+  cnt=Var->name[12];
+  debug(49,5)("snmp_prfPeerFn: we want .%d.%d\n",Var->name[11],cnt);
+  while (--cnt) if (!(p=p->next));
+  if (p==NULL) {
+        *ErrP = SNMP_ERR_NOSUCHNAME;
+        snmp_var_free(Answer);
+        return(NULL);
+  }
+
+   Answer->type = SMI_COUNTER32;
+   Answer->val_len = sizeof(long);
+   Answer->val.integer = xmalloc(Answer->val_len);
+
+  switch(Var->name[11]) {
+    case PERF_PEERSTAT_ID:
+       Answer->type= ASN_INTEGER;
+        *(Answer->val.integer) = Var->name[11];
+       break;
+    case PERF_PEERSTAT_SENT:
+        *(Answer->val.integer) = p->stats.pings_sent;
+       break;
+    case PERF_PEERSTAT_PACKED:
+        *(Answer->val.integer) = p->stats.pings_acked;
+       break;
+    case PERF_PEERSTAT_FETCHES:
+        *(Answer->val.integer) = p->stats.fetches;
+       break;
+    case PERF_PEERSTAT_RTT:
+       Answer->type= ASN_INTEGER;
+        *(Answer->val.integer) = p->stats.rtt;
+       break;
+    case PERF_PEERSTAT_IGN:
+        *(Answer->val.integer) = p->stats.ignored_replies;
+       break;
+    case PERF_PEERSTAT_KEEPAL_S:
+        *(Answer->val.integer) = p->stats.n_keepalives_sent;
+       break;
+    case PERF_PEERSTAT_KEEPAL_R:
+        *(Answer->val.integer) = p->stats.n_keepalives_recv;
+       break;
+    default:
+        *ErrP = SNMP_ERR_NOSUCHNAME;
+        snmp_var_free(Answer);
+       xfree(Answer->val.integer);
+        return(NULL);
+  } 
+  return Answer;
 }
 
 
-static void
-setVariable(u_char * var_val,
-    u_char var_val_type,
-    int var_val_len,
-    u_char * statP,
-    int statLen)
+variable_list *snmp_prfProtoFn(variable_list *Var, long *ErrP)
 {
-    int buffersize = 1000;
-
-    switch (var_val_type) {
-    case ASN_INTEGER:
-    case COUNTER:
-    case GAUGE:
-    case TIMETICKS:
-       asn_parse_int(var_val, &buffersize, &var_val_type, (long *) statP, statLen);
+  variable_list *Answer;
+
+  debug(49,5)("snmp_prfProtoFn: Processing request with magic %d!\n",Var->name[8]);
+
+  Answer = snmp_var_new(Var->name, Var->name_length);
+  *ErrP = SNMP_ERR_NOERROR;
+
+  if (Var->name[9]==1) {   /* cacheProtoAggregateStats */
+   Answer->type = SMI_COUNTER32;
+   Answer->val_len = sizeof(long);
+   Answer->val.integer = xmalloc(Answer->val_len);
+   switch(Var->name[10]) {
+    case PERF_PROTOSTAT_AGGR_HTTP_REQ:
+        *(Answer->val.integer) = (long) Counter.client_http.requests;
        break;
-    case ASN_OCTET_STR:
-    case IPADDRESS:
-    case OPAQUE:
-       asn_parse_string(var_val, &buffersize, &var_val_type, statP, &statLen);
+    case PERF_PROTOSTAT_AGGR_HTTP_HITS:
+        *(Answer->val.integer) = (long) Counter.client_http.hits;
        break;
-    case ASN_OBJECT_ID:
-       asn_parse_objid(var_val, &buffersize, &var_val_type, (oid *) statP, &statLen);
+    case PERF_PROTOSTAT_AGGR_HTTP_ERRORS:
+        *(Answer->val.integer) = (long) Counter.client_http.errors;
        break;
-    }
+    case PERF_PROTOSTAT_AGGR_ICP_S:
+        *(Answer->val.integer) = (long) Counter.icp.pkts_sent;
+       break;
+    case PERF_PROTOSTAT_AGGR_ICP_R:
+        *(Answer->val.integer)  = (long) Counter.icp.pkts_recv;
+       break;
+    case PERF_PROTOSTAT_AGGR_ICP_SKB:
+        *(Answer->val.integer) = (long) Counter.icp.kbytes_sent.kb;
+       break;
+    case PERF_PROTOSTAT_AGGR_ICP_RKB:
+        *(Answer->val.integer) = (long) Counter.icp.kbytes_recv.kb;
+       break;
+    case PERF_PROTOSTAT_AGGR_KBYTES_IN:
+        *(Answer->val.integer) = (long) Counter.client_http.kbytes_in.kb;
+       break;
+    case PERF_PROTOSTAT_AGGR_KBYTES_OUT:
+        *(Answer->val.integer) = (long) Counter.client_http.kbytes_out.kb;
+       break;
+    case PERF_PROTOSTAT_AGGR_CURSWAP:
+        *(Answer->val.integer) = (long) store_swap_size;
+       break;
+    case PERF_PROTOSTAT_AGGR_HTTP_SVC_5:
+       Answer->type = ASN_INTEGER;
+        *(Answer->val.integer) = (long) get_median_svc(5, HTTP_SVC);
+       break;
+    case PERF_PROTOSTAT_AGGR_ICP_SVC_5:
+       Answer->type = ASN_INTEGER;
+        *(Answer->val.integer) = (long) get_median_svc(5, ICP_SVC);
+       break;
+    case PERF_PROTOSTAT_AGGR_DNS_SVC_5:
+       Answer->type = ASN_INTEGER;
+        *(Answer->val.integer) = (long) get_median_svc(5, DNS_SVC);
+       break;
+    case PERF_PROTOSTAT_AGGR_HTTP_SVC_60:
+        Answer->type = ASN_INTEGER;
+        *(Answer->val.integer) = (long) get_median_svc(60, HTTP_SVC);
+        break;
+    case PERF_PROTOSTAT_AGGR_ICP_SVC_60:
+        Answer->type = ASN_INTEGER;
+        *(Answer->val.integer) = (long) get_median_svc(60, ICP_SVC);
+        break;
+    case PERF_PROTOSTAT_AGGR_DNS_SVC_60:
+        Answer->type = ASN_INTEGER;
+        *(Answer->val.integer) = (long) get_median_svc(60, DNS_SVC);
+        break;
+    default:
+       xfree(Answer->val.integer);
+        *ErrP = SNMP_ERR_NOSUCHNAME;
+        snmp_var_free(Answer);
+        return(NULL);
+  } 
+ }
+ else {
+        *ErrP = SNMP_ERR_NOSUCHNAME;
+        snmp_var_free(Answer);
+        return(NULL);
+ }
+ return Answer;
 }
 
-struct repeater {
-    oid name[MAX_NAME_LEN];
-    int length;
-} repeaterList[20];
-
 
-static int
-bulk_var_op_list(u_char * sn_data,
-    int length,
-    u_char * out_sn_data,
-    int out_length,
-    int non_repeaters,
-    int max_repetitions,
-    long *index)
+variable_list *snmp_dnsFn(variable_list *Var, long *ErrP)
 {
-    u_char type;
-    oid var_name[MAX_NAME_LEN];
-    int var_name_len, var_val_len;
-    u_char var_val_type, *var_val, statType;
-    u_char *statP;
-    int statLen;
-    u_short acl;
-    int (*write_method) ();
-    u_char *headerP, *var_list_start;
-    int dummyLen;
-    u_char *getStatPtr();
-    u_char *repeaterStart, *out_sn_data_save;
-    int repeatCount, repeaterLength, indexStart, out_length_save;
-    int full = FALSE;
-    int noSuchObject, useful;
-    int repeaterIndex, repeaterCount;
-    struct repeater *rl;
-
-    if (non_repeaters < 0)
-       non_repeaters = 0;
-    max_repetitions = *index;
-    if (max_repetitions < 0)
-       max_repetitions = 0;
-
-    sn_data = asn_parse_header(sn_data, &length, &type);
-    if (sn_data == NULL) {
-       debug(49, 5) ("bulk_var_op_list: not enough space for varlist\n");
-       snmp_inasnparseerrors++;
-       return PARSE_ERROR;
-    }
-    if (type != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
-       debug(49, 5) ("bulk_var_op_list: wrong type\n");
-       snmp_inasnparseerrors++;
-       return PARSE_ERROR;
-    }
-    headerP = out_sn_data;
-    out_sn_data = asn_build_sequence(out_sn_data, &out_length,
-       (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
-    if (out_sn_data == NULL) {
-       debug(49, 5) ("bulk_var_op_list: not enough space in output packet\n");
-       return BUILD_ERROR;
-    }
-    var_list_start = out_sn_data;
-
-    out_length -= 32;          /* slop factor */
-    *index = 1;
-    while ((int) length > 0 && non_repeaters > 0) {
-       /* parse the name, value pair */
-
-       var_name_len = MAX_NAME_LEN;
-       sn_data = snmp_parse_var_op(sn_data, var_name, &var_name_len, &var_val_type,
-           &var_val_len, &var_val, (int *) &length);
-       if (sn_data == NULL)
-           return PARSE_ERROR;
-       /* now attempt to retrieve the variable on the local entity */
-       statP = getStatPtr(var_name, &var_name_len, &statType, &statLen, &acl,
-           FALSE, &write_method, session->version, &noSuchObject, session->readView);
-
-       if (statP == NULL)
-           statType = SNMP_ENDOFMIBVIEW;
-
-       /* save out_sn_data so this varbind can be removed if it goes over
-        * the limit for this packet */
-
-       /* retrieve the value of the variable and place it into the outgoing packet */
-       out_sn_data = snmp_build_var_op(out_sn_data, var_name, &var_name_len,
-           statType, statLen, statP,
-           &out_length);
-       if (out_sn_data == NULL) {
-           return SNMP_ERR_TOOBIG;     /* ??? */
-       }
-       (*index)++;
-       non_repeaters--;
-    }
-
-    repeaterStart = out_sn_data;
-    indexStart = *index;       /* index on input packet */
-
-    repeaterCount = 0;
-    rl = repeaterList;
-    useful = FALSE;
-    while ((int) length > 0) {
-       /* parse the name, value pair */
-       rl->length = MAX_NAME_LEN;
-       sn_data = snmp_parse_var_op(sn_data, rl->name, &rl->length,
-           &var_val_type, &var_val_len, &var_val,
-           (int *) &length);
-       if (sn_data == NULL) {
-           snmp_inasnparseerrors++;
-           return PARSE_ERROR;
-       }
-       /* now attempt to retrieve the variable on the local entity */
-       statP = getStatPtr(rl->name, &rl->length, &statType, &statLen,
-           &acl, FALSE, &write_method, session->version, &noSuchObject, session->readView);
-       if (statP == NULL)
-           statType = SNMP_ENDOFMIBVIEW;
-       else
-           useful = TRUE;
-
-       out_sn_data_save = out_sn_data;
-       out_length_save = out_length;
-       /* retrieve the value of the variable and place it into the
-        * outgoing packet */
-       out_sn_data = snmp_build_var_op(out_sn_data, rl->name, &rl->length,
-           statType, statLen, statP,
-           &out_length);
-       if (out_sn_data == NULL) {
-           out_sn_data = out_sn_data_save;
-           out_length = out_length_save;
-           full = TRUE;
-       }
-       (*index)++;
-       repeaterCount++;
-       rl++;
-    }
-    repeaterLength = out_sn_data - repeaterStart;
-    if (!useful)
-       full = TRUE;
-
-    for (repeatCount = 1; repeatCount < max_repetitions; repeatCount++) {
-       sn_data = repeaterStart;
-       length = repeaterLength;
-       *index = indexStart;
-       repeaterStart = out_sn_data;
-       useful = FALSE;
-       repeaterIndex = 0;
-       rl = repeaterList;
-       while ((repeaterIndex++ < repeaterCount) > 0 && !full) {
-           /* now attempt to retrieve the variable on the local entity */
-           statP = getStatPtr(rl->name, &rl->length, &statType, &statLen,
-               &acl, FALSE, &write_method, session->version, &noSuchObject, session->readView);
-           if (statP == NULL)
-               statType = SNMP_ENDOFMIBVIEW;
-           else
-               useful = TRUE;
-
-           out_sn_data_save = out_sn_data;
-           out_length_save = out_length;
-           /* retrieve the value of the variable and place it into the
-            * Outgoing packet */
-           out_sn_data = snmp_build_var_op(out_sn_data, rl->name, &rl->length, statType, statLen, statP, &out_length);
-           if (out_sn_data == NULL) {
-               out_sn_data = out_sn_data_save;
-               out_length = out_length_save;
-               full = TRUE;
-               repeatCount = max_repetitions;
-           }
-           (*index)++;
-           rl++;
-       }
-       repeaterLength = out_sn_data - repeaterStart;
-       if (!useful)
-           full = TRUE;
-    }
-    packet_end = out_sn_data;
+  debug(49,5)("snmp_dnsFn: Processing request with magic %d!\n",Var->name[9]);
+  if (Var->name[9] == NET_DNS_IPCACHE)
+       return snmp_ipcacheFn(Var,ErrP);
+  if (Var->name[9] == NET_DNS_FQDNCACHE)
+        return snmp_fqdncacheFn(Var,ErrP);
 
-    /* Now rebuild header with the actual lengths */
-    dummyLen = out_sn_data - var_list_start;
-    if (asn_build_sequence(headerP, &dummyLen, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), dummyLen) == NULL) {
-       return SNMP_ERR_TOOBIG; /* bogus error ???? */
-    }
-    *index = 0;
-    return SNMP_ERR_NOERROR;
+  return NULL;
 }