snmp_pdu.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:16k
- /*
- * SNMP PDU Encoding
- *
- * Complies with:
- *
- * RFC 1902: Structure of Management Information for SNMPv2
- *
- */
- /**********************************************************************
- *
- * Copyright 1997 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.
- *
- * Author: Ryan Troll <ryan+@andrew.cmu.edu>
- *
- **********************************************************************/
- #include "config.h"
- #include <stdio.h>
- #if HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #if HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #if HAVE_SYS_TYPES_H
- #include <sys/types.h>
- #endif
- #if HAVE_CTYPE_H
- #include <ctype.h>
- #endif
- #if HAVE_GNUMALLOC_H
- #include <gnumalloc.h>
- #elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
- #include <malloc.h>
- #endif
- #if HAVE_MEMORY_H
- #include <memory.h>
- #endif
- #ifdef HAVE_STRING_H
- #include <string.h>
- #endif
- #ifdef HAVE_STRINGS_H
- #include <strings.h>
- #endif
- #if HAVE_BSTRING_H
- #include <bstring.h>
- #endif
- #if HAVE_SYS_SOCKET_H
- #include <sys/socket.h>
- #endif
- #if HAVE_NETINET_IN_H
- #include <netinet/in.h>
- #endif
- #if HAVE_ARPA_INET_H
- #include <arpa/inet.h>
- #endif
- #if HAVE_SYS_TIME_H
- #include <sys/time.h>
- #endif
- #if HAVE_NETDB_H
- #include <netdb.h>
- #endif
- #include "snmp.h"
- #include "asn1.h"
- #include "snmp_error.h"
- #include "snmp_vars.h"
- #include "snmp_pdu.h"
- #include "snmp_msg.h"
- #include "snmp_api_error.h"
- #include "util.h"
- /* #define DEBUG_PDU 1 */
- /* #define DEBUG_PDU_DECODE 1 */
- /* #define DEBUG_PDU_ENCODE 1 */
- #define ASN_PARSE_ERROR(x) { return(x); }
- /**********************************************************************/
- /* Create a PDU.
- */
- struct snmp_pdu *
- snmp_pdu_create(int command)
- {
- struct snmp_pdu *pdu;
- #ifdef DEBUG_PDU
- snmplib_debug(8, "PDU: Creatingn");
- #endif
- pdu = (struct snmp_pdu *) xmalloc(sizeof(struct snmp_pdu));
- if (pdu == NULL) {
- snmp_set_api_error(SNMPERR_OS_ERR);
- return (NULL);
- }
- memset((char *) pdu, ' ', sizeof(struct snmp_pdu));
- pdu->command = command;
- pdu->errstat = SNMP_DEFAULT_ERRSTAT;
- pdu->errindex = SNMP_DEFAULT_ERRINDEX;
- pdu->address.sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
- pdu->enterprise = NULL;
- pdu->enterprise_length = 0;
- pdu->variables = NULL;
- #ifdef DEBUG_PDU
- snmplib_debug(8, "PDU: Created %xn", (unsigned int) pdu);
- #endif
- return (pdu);
- }
- /**********************************************************************/
- /* Clone an existing PDU.
- */
- struct snmp_pdu *
- snmp_pdu_clone(struct snmp_pdu *Src)
- {
- struct snmp_pdu *Dest;
- #ifdef DEBUG_PDU
- snmplib_debug(8, "PDU %x: Cloningn", (unsigned int) Src);
- #endif
- Dest = (struct snmp_pdu *) xmalloc(sizeof(struct snmp_pdu));
- if (Dest == NULL) {
- snmp_set_api_error(SNMPERR_OS_ERR);
- return (NULL);
- }
- xmemcpy((char *) Dest, (char *) Src, sizeof(struct snmp_pdu));
- #ifdef DEBUG_PDU
- snmplib_debug(8, "PDU %x: Created %xn", (unsigned int) Src, (unsigned int) Dest);
- #endif
- return (Dest);
- }
- /**********************************************************************/
- /*
- * If there was an error in the input pdu, creates a clone of the pdu
- * that includes all the variables except the one marked by the errindex.
- * The command is set to the input command and the reqid, errstat, and
- * errindex are set to default values.
- * If the error status didn't indicate an error, the error index didn't
- * indicate a variable, the pdu wasn't a get response message, or there
- * would be no remaining variables, this function will return NULL.
- * If everything was successful, a pointer to the fixed cloned pdu will
- * be returned.
- */
- struct snmp_pdu *
- snmp_pdu_fix(struct snmp_pdu *pdu, int command)
- {
- return (snmp_fix_pdu(pdu, command));
- }
- struct snmp_pdu *
- snmp_fix_pdu(struct snmp_pdu *pdu, int command)
- {
- struct variable_list *var, *newvar;
- struct snmp_pdu *newpdu;
- int index;
- int copied = 0;
- #ifdef DEBUG_PDU
- snmplib_debug(8, "PDU %x: Fixing. Err index is %dn",
- (unsigned int) pdu, (unsigned int) pdu->errindex);
- #endif
- if (pdu->command != SNMP_PDU_RESPONSE ||
- pdu->errstat == SNMP_ERR_NOERROR ||
- pdu->errindex <= 0) {
- snmp_set_api_error(SNMPERR_UNABLE_TO_FIX);
- return (NULL);
- }
- /* clone the pdu */
- newpdu = snmp_pdu_clone(pdu);
- if (newpdu == NULL)
- return (NULL);
- newpdu->variables = 0;
- newpdu->command = command;
- newpdu->reqid = SNMP_DEFAULT_REQID;
- newpdu->errstat = SNMP_DEFAULT_ERRSTAT;
- newpdu->errindex = SNMP_DEFAULT_ERRINDEX;
- /* Loop through the variables, removing whatever isn't necessary */
- var = pdu->variables;
- index = 1;
- /* skip first variable if necessary */
- if (pdu->errindex == index) {
- var = var->next_variable;
- index++;
- }
- if (var != NULL) {
- /* VAR is the first uncopied variable */
- /* Clone this variable */
- newpdu->variables = snmp_var_clone(var);
- if (newpdu->variables == NULL) {
- snmp_pdu_free(newpdu);
- return (NULL);
- }
- copied++;
- newvar = newpdu->variables;
- /* VAR has been copied to NEWVAR. */
- while (var->next_variable) {
- /* Skip the item that was bad */
- if (++index == pdu->errindex) {
- var = var->next_variable;
- continue;
- }
- /* Copy this var */
- newvar->next_variable = snmp_var_clone(var->next_variable);
- if (newvar->next_variable == NULL) {
- snmp_pdu_free(newpdu);
- return (NULL);
- }
- /* Move to the next one */
- newvar = newvar->next_variable;
- var = var->next_variable;
- copied++;
- }
- newvar->next_variable = NULL;
- }
- /* If we didn't copy anything, free the new pdu. */
- if (index < pdu->errindex || copied == 0) {
- snmp_free_pdu(newpdu);
- snmp_set_api_error(SNMPERR_UNABLE_TO_FIX);
- return (NULL);
- }
- #ifdef DEBUG_PDU
- snmplib_debug(8, "PDU %x: Fixed PDU is %xn",
- (unsigned int) pdu, (unsigned int) newpdu);
- #endif
- return (newpdu);
- }
- /**********************************************************************/
- void
- snmp_pdu_free(struct snmp_pdu *pdu)
- {
- snmp_free_pdu(pdu);
- }
- /*
- * Frees the pdu and any xmalloc'd data associated with it.
- */
- void
- snmp_free_pdu(struct snmp_pdu *pdu)
- {
- struct variable_list *vp, *ovp;
- vp = pdu->variables;
- while (vp) {
- ovp = vp;
- vp = vp->next_variable;
- snmp_var_free(ovp);
- }
- if (pdu->enterprise)
- xfree((char *) pdu->enterprise);
- xfree((char *) pdu);
- }
- /**********************************************************************/
- /* Encode this PDU into DestBuf.
- *
- * Returns a pointer to the next byte in the buffer (where the Variable
- * Bindings belong.)
- */
- /*
- * RFC 1902: Structure of Management Information for SNMPv2
- *
- * PDU ::=
- * SEQUENCE {
- * request-id INTEGER32
- * error-status INTEGER
- * error-index INTEGER
- * Variable Bindings
- * }
- *
- * BulkPDU ::=
- * SEQUENCE {
- * request-id INTEGER32
- * non-repeaters INTEGER
- * max-repetitions INTEGER
- * Variable Bindings
- * }
- */
- /*
- * RFC 1157: A Simple Network Management Protocol (SNMP)
- *
- * PDU ::=
- * SEQUENCE {
- * request-id INTEGER
- * error-status INTEGER
- * error-index INTEGER
- * Variable Bindings
- * }
- *
- * TrapPDU ::=
- * SEQUENCE {
- * enterprise NetworkAddress
- * generic-trap INTEGER
- * specific-trap INTEGER
- * time-stamp TIMETICKS
- * Variable Bindings
- * }
- */
- u_char *
- snmp_pdu_encode(u_char * DestBuf, int *DestBufLen,
- struct snmp_pdu *PDU)
- {
- u_char *bufp;
- #ifdef DEBUG_PDU_ENCODE
- snmplib_debug(8, "PDU: Encoding %dn", PDU->command);
- #endif
- /* ASN.1 Header */
- switch (PDU->command) {
- /**********************************************************************/
- case TRP_REQ_MSG:
- /* SNMPv1 Trap */
- /* enterprise */
- bufp = asn_build_objid(DestBuf, DestBufLen,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
- (oid *) PDU->enterprise, PDU->enterprise_length);
- if (bufp == NULL)
- return (NULL);
- /* agent-addr */
- bufp = asn_build_string(bufp, DestBufLen,
- (u_char) (SMI_IPADDRESS | ASN_PRIMITIVE),
- (u_char *) & PDU->agent_addr.sin_addr.s_addr,
- sizeof(PDU->agent_addr.sin_addr.s_addr));
- if (bufp == NULL)
- return (NULL);
- /* generic trap */
- bufp = asn_build_int(bufp, DestBufLen,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (int *) &PDU->trap_type, sizeof(PDU->trap_type));
- if (bufp == NULL)
- return (NULL);
- /* specific trap */
- bufp = asn_build_int(bufp, DestBufLen,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (int *) &PDU->specific_type,
- sizeof(PDU->specific_type));
- if (bufp == NULL)
- return (NULL);
- /* timestamp */
- bufp = asn_build_unsigned_int(bufp, DestBufLen,
- (u_char) (SMI_TIMETICKS | ASN_PRIMITIVE),
- &PDU->time, sizeof(PDU->time));
- if (bufp == NULL)
- return (NULL);
- break;
- /**********************************************************************/
- case SNMP_PDU_GETBULK:
- /* SNMPv2 Bulk Request */
- /* request id */
- bufp = asn_build_int(DestBuf, DestBufLen,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &PDU->reqid, sizeof(PDU->reqid));
- if (bufp == NULL)
- return (NULL);
- /* non-repeaters */
- bufp = asn_build_int(bufp, DestBufLen,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &PDU->non_repeaters,
- sizeof(PDU->non_repeaters));
- if (bufp == NULL)
- return (NULL);
- /* max-repetitions */
- bufp = asn_build_int(bufp, DestBufLen,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &PDU->max_repetitions,
- sizeof(PDU->max_repetitions));
- if (bufp == NULL)
- return (NULL);
- break;
- /**********************************************************************/
- default:
- /* Normal PDU Encoding */
- /* request id */
- #ifdef DEBUG_PDU_ENCODE
- snmplib_debug(8, "PDU: Request ID %d (0x%x)n", PDU->reqid, DestBuf);
- #endif
- bufp = asn_build_int(DestBuf, DestBufLen,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &PDU->reqid, sizeof(PDU->reqid));
- if (bufp == NULL)
- return (NULL);
- /* error status */
- #ifdef DEBUG_PDU_ENCODE
- snmplib_debug(8, "PDU: Error Status %d (0x%x)n", PDU->errstat, bufp);
- #endif
- bufp = asn_build_int(bufp, DestBufLen,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &PDU->errstat, sizeof(PDU->errstat));
- if (bufp == NULL)
- return (NULL);
- /* error index */
- #ifdef DEBUG_PDU_ENCODE
- snmplib_debug(8, "PDU: Error index %d (0x%x)n", PDU->errindex, bufp);
- #endif
- bufp = asn_build_int(bufp, DestBufLen,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &PDU->errindex, sizeof(PDU->errindex));
- if (bufp == NULL)
- return (NULL);
- break;
- } /* End of encoding */
- return (bufp);
- }
- /**********************************************************************/
- /* Decodes PDU from Packet into PDU.
- *
- * Returns a pointer to the next byte of the packet, which is where the
- * Variable Bindings start.
- */
- u_char *
- snmp_pdu_decode(u_char * Packet, /* data */
- int *Length, /* &length */
- struct snmp_pdu * PDU)
- { /* pdu */
- u_char *bufp;
- u_char PDUType;
- int four;
- u_char ASNType;
- oid objid[MAX_NAME_LEN];
- bufp = asn_parse_header(Packet, Length, &PDUType);
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- #ifdef DEBUG_PDU_DECODE
- snmplib_debug(8, "PDU Type: %dn", PDUType);
- #endif
- PDU->command = PDUType;
- switch (PDUType) {
- case TRP_REQ_MSG:
- /* SNMPv1 Trap Message */
- /* enterprise */
- PDU->enterprise_length = MAX_NAME_LEN;
- bufp = asn_parse_objid(bufp, Length,
- &ASNType, objid, &PDU->enterprise_length);
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- PDU->enterprise = (oid *) xmalloc(PDU->enterprise_length * sizeof(oid));
- if (PDU->enterprise == NULL) {
- snmp_set_api_error(SNMPERR_OS_ERR);
- return (NULL);
- }
- xmemcpy((char *) PDU->enterprise, (char *) objid,
- PDU->enterprise_length * sizeof(oid));
- /* Agent-addr */
- four = 4;
- bufp = asn_parse_string(bufp, Length,
- &ASNType,
- (u_char *) & PDU->agent_addr.sin_addr.s_addr,
- &four);
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- /* Generic trap */
- bufp = asn_parse_int(bufp, Length,
- &ASNType,
- (int *) &PDU->trap_type,
- sizeof(PDU->trap_type));
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- /* Specific Trap */
- bufp = asn_parse_int(bufp, Length,
- &ASNType,
- (int *) &PDU->specific_type,
- sizeof(PDU->specific_type));
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- /* Timestamp */
- bufp = asn_parse_unsigned_int(bufp, Length,
- &ASNType,
- &PDU->time, sizeof(PDU->time));
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- break;
- /**********************************************************************/
- case SNMP_PDU_GETBULK:
- /* SNMPv2 Bulk Request */
- /* request id */
- bufp = asn_parse_int(bufp, Length,
- &ASNType,
- &PDU->reqid, sizeof(PDU->reqid));
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- /* non-repeaters */
- bufp = asn_parse_int(bufp, Length,
- &ASNType,
- &PDU->non_repeaters, sizeof(PDU->non_repeaters));
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- /* max-repetitions */
- bufp = asn_parse_int(bufp, Length,
- &ASNType,
- &PDU->max_repetitions, sizeof(PDU->max_repetitions));
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- break;
- /**********************************************************************/
- default:
- /* Normal PDU Encoding */
- /* request id */
- bufp = asn_parse_int(bufp, Length,
- &ASNType,
- &PDU->reqid, sizeof(PDU->reqid));
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- #ifdef DEBUG_PDU_DECODE
- snmplib_debug(8, "PDU Request ID: %dn", PDU->reqid);
- #endif
- /* error status */
- bufp = asn_parse_int(bufp, Length,
- &ASNType,
- &PDU->errstat, sizeof(PDU->errstat));
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- #ifdef DEBUG_PDU_DECODE
- snmplib_debug(8, "PDU Error Status: %dn", PDU->errstat);
- #endif
- /* error index */
- bufp = asn_parse_int(bufp, Length,
- &ASNType,
- &PDU->errindex, sizeof(PDU->errindex));
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- #ifdef DEBUG_PDU_DECODE
- snmplib_debug(8, "PDU Error Index: %dn", PDU->errindex);
- #endif
- break;
- }
- return (bufp);
- }
- char *
- snmp_pdu_type(struct snmp_pdu *PDU)
- {
- switch (PDU->command) {
- case SNMP_PDU_GET:
- return ("GET");
- break;
- case SNMP_PDU_GETNEXT:
- return ("GETNEXT");
- break;
- case SNMP_PDU_RESPONSE:
- return ("RESPONSE");
- break;
- case SNMP_PDU_SET:
- return ("SET");
- break;
- case SNMP_PDU_GETBULK:
- return ("GETBULK");
- break;
- case SNMP_PDU_INFORM:
- return ("INFORM");
- break;
- case SNMP_PDU_V2TRAP:
- return ("V2TRAP");
- break;
- case SNMP_PDU_REPORT:
- return ("REPORT");
- break;
- case TRP_REQ_MSG:
- return ("V1TRAP");
- break;
- default:
- return ("Unknown");
- break;
- }
- }
- /*
- * Add a null variable with the requested name to the end of the list of
- * variables for this pdu.
- */
- void
- snmp_add_null_var(struct snmp_pdu *pdu, oid * name, int name_length)
- {
- struct variable_list *vars;
- struct variable_list *ptr;
- vars = snmp_var_new(name, name_length);
- if (vars == NULL) {
- perror("snmp_add_null_var:xmalloc");
- return;
- }
- if (pdu->variables == NULL) {
- pdu->variables = vars;
- } else {
- /* Insert at the end */
- for (ptr = pdu->variables;
- ptr->next_variable;
- ptr = ptr->next_variable)
- /*EXIT */ ;
- ptr->next_variable = vars;
- }
- return;
- }