| /* Portions of this file are subject to the following copyright(s). See |
| * the Net-SNMP's COPYING file for more details and other copyrights |
| * that may apply: |
| */ |
| /* |
| * Portions of this file are copyrighted by: |
| * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. |
| * Use is subject to license terms specified in the COPYING file |
| * distributed with the Net-SNMP package. |
| */ |
| |
| #include <net-snmp/net-snmp-config.h> |
| |
| #include <stdio.h> |
| #include <errno.h> |
| #if HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #if HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| #if HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif |
| #include <sys/types.h> |
| #if TIME_WITH_SYS_TIME |
| # ifdef WIN32 |
| # include <sys/timeb.h> |
| # else |
| # include <sys/time.h> |
| # endif |
| # include <time.h> |
| #else |
| # if HAVE_SYS_TIME_H |
| # include <sys/time.h> |
| # else |
| # include <time.h> |
| # endif |
| #endif |
| #if HAVE_NETINET_IN_H |
| #include <netinet/in.h> |
| #endif |
| #if HAVE_ARPA_INET_H |
| #include <arpa/inet.h> |
| #endif |
| |
| #if HAVE_WINSOCK_H |
| #include <winsock.h> |
| #endif |
| |
| #include <net-snmp/net-snmp-includes.h> |
| |
| #include "agentx/protocol.h" |
| |
| const char * |
| agentx_cmd(u_char code) |
| { |
| switch (code) { |
| case AGENTX_MSG_OPEN: |
| return "Open"; |
| case AGENTX_MSG_CLOSE: |
| return "Close"; |
| case AGENTX_MSG_REGISTER: |
| return "Register"; |
| case AGENTX_MSG_UNREGISTER: |
| return "Unregister"; |
| case AGENTX_MSG_GET: |
| return "Get"; |
| case AGENTX_MSG_GETNEXT: |
| return "Get Next"; |
| case AGENTX_MSG_GETBULK: |
| return "Get Bulk"; |
| case AGENTX_MSG_TESTSET: |
| return "Test Set"; |
| case AGENTX_MSG_COMMITSET: |
| return "Commit Set"; |
| case AGENTX_MSG_UNDOSET: |
| return "Undo Set"; |
| case AGENTX_MSG_CLEANUPSET: |
| return "Cleanup Set"; |
| case AGENTX_MSG_NOTIFY: |
| return "Notify"; |
| case AGENTX_MSG_PING: |
| return "Ping"; |
| case AGENTX_MSG_INDEX_ALLOCATE: |
| return "Index Allocate"; |
| case AGENTX_MSG_INDEX_DEALLOCATE: |
| return "Index Deallocate"; |
| case AGENTX_MSG_ADD_AGENT_CAPS: |
| return "Add Agent Caps"; |
| case AGENTX_MSG_REMOVE_AGENT_CAPS: |
| return "Remove Agent Caps"; |
| case AGENTX_MSG_RESPONSE: |
| return "Response"; |
| default: |
| return "Unknown"; |
| } |
| } |
| |
| int |
| agentx_realloc_build_int(u_char ** buf, size_t * buf_len, size_t * out_len, |
| int allow_realloc, |
| unsigned int value, int network_order) |
| { |
| unsigned int ivalue = value; |
| size_t ilen = *out_len; |
| #ifdef WORDS_BIGENDIAN |
| unsigned int i = 0; |
| #endif |
| |
| while ((*out_len + 4) >= *buf_len) { |
| if (!(allow_realloc && snmp_realloc(buf, buf_len))) { |
| return 0; |
| } |
| } |
| |
| if (network_order) { |
| #ifndef WORDS_BIGENDIAN |
| value = ntohl(value); |
| #endif |
| memmove((*buf + *out_len), &value, 4); |
| *out_len += 4; |
| } else { |
| #ifndef WORDS_BIGENDIAN |
| memmove((*buf + *out_len), &value, 4); |
| *out_len += 4; |
| #else |
| for (i = 0; i < 4; i++) { |
| *(*buf + *out_len) = (u_char) value & 0xff; |
| (*out_len)++; |
| value >>= 8; |
| } |
| #endif |
| } |
| DEBUGDUMPSETUP("send", (*buf + ilen), 4); |
| DEBUGMSG(("dumpv_send", " Integer:\t%lu (0x%.2lX)\n", ivalue, |
| ivalue)); |
| return 1; |
| } |
| |
| void |
| agentx_build_int(u_char * bufp, u_int value, int network_byte_order) |
| { |
| u_char *orig_bufp = bufp; |
| u_int orig_val = value; |
| |
| if (network_byte_order) { |
| #ifndef WORDS_BIGENDIAN |
| value = ntohl(value); |
| #endif |
| memmove(bufp, &value, 4); |
| } else { |
| #ifndef WORDS_BIGENDIAN |
| memmove(bufp, &value, 4); |
| #else |
| *bufp = (u_char) value & 0xff; |
| value >>= 8; |
| bufp++; |
| *bufp = (u_char) value & 0xff; |
| value >>= 8; |
| bufp++; |
| *bufp = (u_char) value & 0xff; |
| value >>= 8; |
| bufp++; |
| *bufp = (u_char) value & 0xff; |
| #endif |
| } |
| DEBUGDUMPSETUP("send", orig_bufp, 4); |
| DEBUGMSG(("dumpv_send", " Integer:\t%ld (0x%.2X)\n", orig_val, |
| orig_val)); |
| } |
| |
| int |
| agentx_realloc_build_short(u_char ** buf, size_t * buf_len, |
| size_t * out_len, int allow_realloc, |
| unsigned short value, int network_order) |
| { |
| unsigned short ivalue = value; |
| size_t ilen = *out_len; |
| #ifdef WORDS_BIGENDIAN |
| unsigned short i = 0; |
| #endif |
| |
| while ((*out_len + 2) >= *buf_len) { |
| if (!(allow_realloc && snmp_realloc(buf, buf_len))) { |
| return 0; |
| } |
| } |
| |
| if (network_order) { |
| #ifndef WORDS_BIGENDIAN |
| value = ntohs(value); |
| #endif |
| memmove((*buf + *out_len), &value, 2); |
| *out_len += 2; |
| } else { |
| #ifndef WORDS_BIGENDIAN |
| memmove((*buf + *out_len), &value, 2); |
| *out_len += 2; |
| #else |
| for (i = 0; i < 2; i++) { |
| *(*buf + *out_len) = (u_char) value & 0xff; |
| (*out_len)++; |
| value >>= 8; |
| } |
| #endif |
| } |
| DEBUGDUMPSETUP("send", (*buf + ilen), 2); |
| DEBUGMSG(("dumpv_send", " Short:\t%hu (0x%.2hX)\n", ivalue, ivalue)); |
| return 1; |
| } |
| |
| int |
| agentx_realloc_build_oid(u_char ** buf, size_t * buf_len, size_t * out_len, |
| int allow_realloc, |
| int inclusive, oid * name, size_t name_len, |
| int network_order) |
| { |
| size_t ilen = *out_len, i = 0; |
| int prefix = 0; |
| |
| DEBUGPRINTINDENT("dumpv_send"); |
| DEBUGMSG(("dumpv_send", "OID: ")); |
| DEBUGMSGOID(("dumpv_send", name, name_len)); |
| DEBUGMSG(("dumpv_send", "\n")); |
| |
| /* |
| * Updated clarification from the AgentX mailing list. |
| * The "null Object Identifier" mentioned in RFC 2471, |
| * section 5.1 is a special placeholder value, and |
| * should only be used when explicitly mentioned in |
| * this RFC. In particular, it does *not* mean {0, 0} |
| */ |
| if (name_len == 0) |
| inclusive = 0; |
| |
| /* |
| * 'Compact' internet OIDs |
| */ |
| if (name_len >= 5 && (name[0] == 1 && name[1] == 3 && |
| name[2] == 6 && name[3] == 1 && |
| name[4] > 0 && name[4] < 256)) { |
| prefix = name[4]; |
| name += 5; |
| name_len -= 5; |
| } |
| |
| while ((*out_len + 4 + (4 * name_len)) >= *buf_len) { |
| if (!(allow_realloc && snmp_realloc(buf, buf_len))) { |
| return 0; |
| } |
| } |
| |
| *(*buf + *out_len) = (u_char) name_len; |
| (*out_len)++; |
| *(*buf + *out_len) = (u_char) prefix; |
| (*out_len)++; |
| *(*buf + *out_len) = (u_char) inclusive; |
| (*out_len)++; |
| *(*buf + *out_len) = (u_char) 0x00; |
| (*out_len)++; |
| |
| DEBUGDUMPHEADER("send", "OID Header"); |
| DEBUGDUMPSETUP("send", (*buf + ilen), 4); |
| DEBUGMSG(("dumpv_send", " # subids:\t%d (0x%.2X)\n", name_len, |
| name_len)); |
| DEBUGPRINTINDENT("dumpv_send"); |
| DEBUGMSG(("dumpv_send", " prefix:\t%d (0x%.2X)\n", prefix, prefix)); |
| DEBUGPRINTINDENT("dumpv_send"); |
| DEBUGMSG(("dumpv_send", " inclusive:\t%d (0x%.2X)\n", inclusive, |
| inclusive)); |
| DEBUGINDENTLESS(); |
| DEBUGDUMPHEADER("send", "OID Segments"); |
| |
| for (i = 0; i < name_len; i++) { |
| if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc, |
| name[i], network_order)) { |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| } |
| DEBUGINDENTLESS(); |
| |
| return 1; |
| } |
| |
| int |
| agentx_realloc_build_string(u_char ** buf, size_t * buf_len, |
| size_t * out_len, int allow_realloc, |
| u_char * string, size_t string_len, |
| int network_order) |
| { |
| size_t ilen = *out_len, i = 0; |
| |
| while ((*out_len + 4 + (4 * ((string_len + 3) / 4))) >= *buf_len) { |
| if (!(allow_realloc && snmp_realloc(buf, buf_len))) { |
| return 0; |
| } |
| } |
| |
| DEBUGDUMPHEADER("send", "Build String"); |
| DEBUGDUMPHEADER("send", "length"); |
| if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc, |
| string_len, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| |
| if (string_len == 0) { |
| DEBUGMSG(("dumpv_send", " String: <empty>\n")); |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 1; |
| } |
| |
| memmove((*buf + *out_len), string, string_len); |
| *out_len += string_len; |
| |
| /* |
| * Pad to a multiple of 4 bytes if necessary (per RFC 2741). |
| */ |
| |
| if (string_len % 4 != 0) { |
| for (i = 0; i < 4 - (string_len % 4); i++) { |
| *(*buf + *out_len) = 0; |
| (*out_len)++; |
| } |
| } |
| |
| DEBUGDUMPSETUP("send", (*buf + ilen + 4), ((string_len + 3) / 4) * 4); |
| DEBUGMSG(("dumpv_send", " String:\t%s\n", string)); |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 1; |
| } |
| |
| #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES |
| int |
| agentx_realloc_build_double(u_char ** buf, size_t * buf_len, |
| size_t * out_len, int allow_realloc, |
| double double_val, int network_order) |
| { |
| union { |
| double doubleVal; |
| int intVal[2]; |
| char c[sizeof(double)]; |
| } du; |
| int tmp; |
| u_char opaque_buffer[3 + sizeof(double)]; |
| |
| opaque_buffer[0] = ASN_OPAQUE_TAG1; |
| opaque_buffer[1] = ASN_OPAQUE_DOUBLE; |
| opaque_buffer[2] = sizeof(double); |
| |
| du.doubleVal = double_val; |
| tmp = htonl(du.intVal[0]); |
| du.intVal[0] = htonl(du.intVal[1]); |
| du.intVal[1] = tmp; |
| memcpy(&opaque_buffer[3], &du.c[0], sizeof(double)); |
| |
| return agentx_realloc_build_string(buf, buf_len, out_len, |
| allow_realloc, opaque_buffer, |
| 3 + sizeof(double), network_order); |
| } |
| |
| int |
| agentx_realloc_build_float(u_char ** buf, size_t * buf_len, |
| size_t * out_len, int allow_realloc, |
| float float_val, int network_order) |
| { |
| union { |
| float floatVal; |
| int intVal; |
| char c[sizeof(float)]; |
| } fu; |
| u_char opaque_buffer[3 + sizeof(float)]; |
| |
| opaque_buffer[0] = ASN_OPAQUE_TAG1; |
| opaque_buffer[1] = ASN_OPAQUE_FLOAT; |
| opaque_buffer[2] = sizeof(float); |
| |
| fu.floatVal = float_val; |
| fu.intVal = htonl(fu.intVal); |
| memcpy(&opaque_buffer[3], &fu.c[0], sizeof(float)); |
| |
| return agentx_realloc_build_string(buf, buf_len, out_len, |
| allow_realloc, opaque_buffer, |
| 3 + sizeof(float), network_order); |
| } |
| #endif |
| |
| int |
| agentx_realloc_build_varbind(u_char ** buf, size_t * buf_len, |
| size_t * out_len, int allow_realloc, |
| netsnmp_variable_list * vp, int network_order) |
| { |
| DEBUGDUMPHEADER("send", "VarBind"); |
| DEBUGDUMPHEADER("send", "type"); |
| #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES |
| if ((vp->type == ASN_OPAQUE_FLOAT) || (vp->type == ASN_OPAQUE_DOUBLE) |
| || (vp->type == ASN_OPAQUE_I64) || (vp->type == ASN_OPAQUE_U64) |
| || (vp->type == ASN_OPAQUE_COUNTER64)) { |
| if (!agentx_realloc_build_short |
| (buf, buf_len, out_len, allow_realloc, |
| (unsigned short) ASN_OPAQUE, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| } else |
| #endif |
| if (vp->type == ASN_PRIV_INCL_RANGE || vp->type == ASN_PRIV_EXCL_RANGE) { |
| if (!agentx_realloc_build_short |
| (buf, buf_len, out_len, allow_realloc, |
| (unsigned short) ASN_OBJECT_ID, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| } else { |
| if (!agentx_realloc_build_short |
| (buf, buf_len, out_len, allow_realloc, |
| (unsigned short) vp->type, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| } |
| |
| while ((*out_len + 2) >= *buf_len) { |
| if (!(allow_realloc && snmp_realloc(buf, buf_len))) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| } |
| |
| *(*buf + *out_len) = 0; |
| (*out_len)++; |
| *(*buf + *out_len) = 0; |
| (*out_len)++; |
| DEBUGINDENTLESS(); |
| |
| DEBUGDUMPHEADER("send", "name"); |
| if (!agentx_realloc_build_oid(buf, buf_len, out_len, allow_realloc, 0, |
| vp->name, vp->name_length, |
| network_order)) { |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| |
| DEBUGDUMPHEADER("send", "value"); |
| switch (vp->type) { |
| |
| case ASN_INTEGER: |
| case ASN_COUNTER: |
| case ASN_GAUGE: |
| case ASN_TIMETICKS: |
| case ASN_UINTEGER: |
| if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc, |
| *(vp->val.integer), network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| break; |
| |
| #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES |
| case ASN_OPAQUE_FLOAT: |
| DEBUGDUMPHEADER("send", "Build Opaque Float"); |
| DEBUGPRINTINDENT("dumpv_send"); |
| DEBUGMSG(("dumpv_send", " Float:\t%f\n", *(vp->val.floatVal))); |
| if (!agentx_realloc_build_float |
| (buf, buf_len, out_len, allow_realloc, *(vp->val.floatVal), |
| network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| break; |
| |
| case ASN_OPAQUE_DOUBLE: |
| DEBUGDUMPHEADER("send", "Build Opaque Double"); |
| DEBUGPRINTINDENT("dumpv_send"); |
| DEBUGMSG(("dumpv_send", " Double:\t%lf\n", *(vp->val.doubleVal))); |
| if (!agentx_realloc_build_double |
| (buf, buf_len, out_len, allow_realloc, *(vp->val.doubleVal), |
| network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| break; |
| |
| case ASN_OPAQUE_I64: |
| case ASN_OPAQUE_U64: |
| case ASN_OPAQUE_COUNTER64: |
| /* |
| * XXX - TODO - encode as raw OPAQUE for now (so fall through |
| * here). |
| */ |
| #endif |
| |
| case ASN_OCTET_STR: |
| case ASN_IPADDRESS: |
| case ASN_OPAQUE: |
| if (!agentx_realloc_build_string |
| (buf, buf_len, out_len, allow_realloc, vp->val.string, |
| vp->val_len, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| break; |
| |
| case ASN_OBJECT_ID: |
| case ASN_PRIV_EXCL_RANGE: |
| case ASN_PRIV_INCL_RANGE: |
| if (!agentx_realloc_build_oid |
| (buf, buf_len, out_len, allow_realloc, 1, vp->val.objid, |
| vp->val_len / sizeof(oid), network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| break; |
| |
| case ASN_COUNTER64: |
| if (network_order) { |
| DEBUGDUMPHEADER("send", "Build Counter64 (high, low)"); |
| if (!agentx_realloc_build_int |
| (buf, buf_len, out_len, allow_realloc, |
| vp->val.counter64->high, network_order) |
| || !agentx_realloc_build_int(buf, buf_len, out_len, |
| allow_realloc, |
| vp->val.counter64->low, |
| network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| } else { |
| DEBUGDUMPHEADER("send", "Build Counter64 (low, high)"); |
| if (!agentx_realloc_build_int |
| (buf, buf_len, out_len, allow_realloc, |
| vp->val.counter64->low, network_order) |
| || !agentx_realloc_build_int(buf, buf_len, out_len, |
| allow_realloc, |
| vp->val.counter64->high, |
| network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| } |
| break; |
| |
| case ASN_NULL: |
| case SNMP_NOSUCHOBJECT: |
| case SNMP_NOSUCHINSTANCE: |
| case SNMP_ENDOFMIBVIEW: |
| break; |
| |
| default: |
| DEBUGMSGTL(("agentx_build_varbind", "unknown type %d (0x%02x)\n", |
| vp->type, vp->type)); |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 1; |
| } |
| |
| int |
| agentx_realloc_build_header(u_char ** buf, size_t * buf_len, |
| size_t * out_len, int allow_realloc, |
| netsnmp_pdu *pdu) |
| { |
| size_t ilen = *out_len; |
| const int network_order = |
| pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER; |
| |
| while ((*out_len + 4) >= *buf_len) { |
| if (!(allow_realloc && snmp_realloc(buf, buf_len))) { |
| return 0; |
| } |
| } |
| |
| /* |
| * First 4 bytes are version, pdu type, flags, and a 0 reserved byte. |
| */ |
| |
| *(*buf + *out_len) = 1; |
| (*out_len)++; |
| *(*buf + *out_len) = pdu->command; |
| (*out_len)++; |
| *(*buf + *out_len) = (u_char) (pdu->flags & AGENTX_MSG_FLAGS_MASK); |
| (*out_len)++; |
| *(*buf + *out_len) = 0; |
| (*out_len)++; |
| |
| DEBUGDUMPHEADER("send", "AgentX Header"); |
| DEBUGDUMPSETUP("send", (*buf + ilen), 4); |
| DEBUGMSG(("dumpv_send", " Version:\t%d\n", (int) *(*buf + ilen))); |
| DEBUGPRINTINDENT("dumpv_send"); |
| DEBUGMSG(("dumpv_send", " Command:\t%d (%s)\n", pdu->command, |
| agentx_cmd((u_char)pdu->command))); |
| DEBUGPRINTINDENT("dumpv_send"); |
| DEBUGMSG(("dumpv_send", " Flags:\t%02x\n", (int) *(*buf + ilen + 2))); |
| |
| DEBUGDUMPHEADER("send", "Session ID"); |
| if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc, |
| pdu->sessid, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| |
| DEBUGDUMPHEADER("send", "Transaction ID"); |
| if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc, |
| pdu->transid, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| |
| DEBUGDUMPHEADER("send", "Request ID"); |
| if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc, |
| pdu->reqid, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| |
| DEBUGDUMPHEADER("send", "Dummy Length :-("); |
| if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc, |
| 0, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| |
| if (pdu->flags & AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT) { |
| DEBUGDUMPHEADER("send", "Community"); |
| if (!agentx_realloc_build_string |
| (buf, buf_len, out_len, allow_realloc, pdu->community, |
| pdu->community_len, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| } |
| |
| DEBUGINDENTLESS(); |
| return 1; |
| } |
| |
| static int |
| _agentx_realloc_build(u_char ** buf, size_t * buf_len, size_t * out_len, |
| int allow_realloc, |
| netsnmp_session * session, netsnmp_pdu *pdu) |
| { |
| size_t ilen = *out_len; |
| netsnmp_variable_list *vp; |
| int inc, i = 0; |
| const int network_order = |
| pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER; |
| |
| session->s_snmp_errno = 0; |
| session->s_errno = 0; |
| |
| /* |
| * Various PDU types don't include context information (RFC 2741, p. 20). |
| */ |
| switch (pdu->command) { |
| case AGENTX_MSG_OPEN: |
| case AGENTX_MSG_CLOSE: |
| case AGENTX_MSG_RESPONSE: |
| case AGENTX_MSG_COMMITSET: |
| case AGENTX_MSG_UNDOSET: |
| case AGENTX_MSG_CLEANUPSET: |
| pdu->flags &= ~(AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT); |
| } |
| |
| /* |
| * Build the header (and context if appropriate). |
| */ |
| if (!agentx_realloc_build_header |
| (buf, buf_len, out_len, allow_realloc, pdu)) { |
| return 0; |
| } |
| |
| /* |
| * Everything causes a response, except for agentx-Response-PDU and |
| * agentx-CleanupSet-PDU. |
| */ |
| |
| pdu->flags |= UCD_MSG_FLAG_EXPECT_RESPONSE; |
| |
| DEBUGDUMPHEADER("send", "AgentX Payload"); |
| switch (pdu->command) { |
| |
| case AGENTX_MSG_OPEN: |
| /* |
| * Timeout |
| */ |
| while ((*out_len + 4) >= *buf_len) { |
| if (!(allow_realloc && snmp_realloc(buf, buf_len))) { |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| } |
| *(*buf + *out_len) = (u_char) pdu->time; |
| (*out_len)++; |
| for (i = 0; i < 3; i++) { |
| *(*buf + *out_len) = 0; |
| (*out_len)++; |
| } |
| DEBUGDUMPHEADER("send", "Open Timeout"); |
| DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4); |
| DEBUGMSG(("dumpv_send", " Timeout:\t%d\n", |
| (int) *(*buf + *out_len - 4))); |
| DEBUGINDENTLESS(); |
| |
| DEBUGDUMPHEADER("send", "Open ID"); |
| if (!agentx_realloc_build_oid |
| (buf, buf_len, out_len, allow_realloc, 0, pdu->variables->name, |
| pdu->variables->name_length, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| DEBUGDUMPHEADER("send", "Open Description"); |
| if (!agentx_realloc_build_string |
| (buf, buf_len, out_len, allow_realloc, |
| pdu->variables->val.string, pdu->variables->val_len, |
| network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| break; |
| |
| case AGENTX_MSG_CLOSE: |
| /* |
| * Reason |
| */ |
| while ((*out_len + 4) >= *buf_len) { |
| if (!(allow_realloc && snmp_realloc(buf, buf_len))) { |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| } |
| *(*buf + *out_len) = (u_char) pdu->errstat; |
| (*out_len)++; |
| for (i = 0; i < 3; i++) { |
| *(*buf + *out_len) = 0; |
| (*out_len)++; |
| } |
| DEBUGDUMPHEADER("send", "Close Reason"); |
| DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4); |
| DEBUGMSG(("dumpv_send", " Reason:\t%d\n", |
| (int) *(*buf + *out_len - 4))); |
| DEBUGINDENTLESS(); |
| break; |
| |
| case AGENTX_MSG_REGISTER: |
| case AGENTX_MSG_UNREGISTER: |
| while ((*out_len + 4) >= *buf_len) { |
| if (!(allow_realloc && snmp_realloc(buf, buf_len))) { |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| } |
| if (pdu->command == AGENTX_MSG_REGISTER) { |
| *(*buf + *out_len) = (u_char) pdu->time; |
| } else { |
| *(*buf + *out_len) = 0; |
| } |
| (*out_len)++; |
| *(*buf + *out_len) = (u_char) pdu->priority; |
| (*out_len)++; |
| *(*buf + *out_len) = (u_char) pdu->range_subid; |
| (*out_len)++; |
| *(*buf + *out_len) = (u_char) 0; |
| (*out_len)++; |
| |
| DEBUGDUMPHEADER("send", "(Un)Register Header"); |
| DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4); |
| if (pdu->command == AGENTX_MSG_REGISTER) { |
| DEBUGMSG(("dumpv_send", " Timeout:\t%d\n", |
| (int) *(*buf + *out_len - 4))); |
| DEBUGPRINTINDENT("dumpv_send"); |
| } |
| DEBUGMSG(("dumpv_send", " Priority:\t%d\n", |
| (int) *(*buf + *out_len - 3))); |
| DEBUGPRINTINDENT("dumpv_send"); |
| DEBUGMSG(("dumpv_send", " Range SubID:\t%d\n", |
| (int) *(*buf + *out_len - 2))); |
| DEBUGINDENTLESS(); |
| |
| vp = pdu->variables; |
| DEBUGDUMPHEADER("send", "(Un)Register Prefix"); |
| if (!agentx_realloc_build_oid |
| (buf, buf_len, out_len, allow_realloc, 0, vp->name, |
| vp->name_length, network_order)) { |
| |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| |
| if (pdu->range_subid) { |
| DEBUGDUMPHEADER("send", "(Un)Register Range"); |
| if (!agentx_realloc_build_int |
| (buf, buf_len, out_len, allow_realloc, |
| vp->val.objid[pdu->range_subid - 1], network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| } |
| break; |
| |
| case AGENTX_MSG_GETBULK: |
| DEBUGDUMPHEADER("send", "GetBulk Non-Repeaters"); |
| if (!agentx_realloc_build_short |
| (buf, buf_len, out_len, allow_realloc, |
| (u_short)pdu->non_repeaters, |
| network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| |
| DEBUGDUMPHEADER("send", "GetBulk Max-Repetitions"); |
| if (!agentx_realloc_build_short |
| (buf, buf_len, out_len, allow_realloc, |
| (u_short)pdu->max_repetitions, |
| network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| |
| /* |
| * Fallthrough |
| */ |
| |
| case AGENTX_MSG_GET: |
| case AGENTX_MSG_GETNEXT: |
| DEBUGDUMPHEADER("send", "Get* Variable List"); |
| for (vp = pdu->variables; vp != NULL; vp = vp->next_variable) { |
| inc = (vp->type == ASN_PRIV_INCL_RANGE); |
| if (!agentx_realloc_build_oid |
| (buf, buf_len, out_len, allow_realloc, inc, vp->name, |
| vp->name_length, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| if (!agentx_realloc_build_oid |
| (buf, buf_len, out_len, allow_realloc, 0, vp->val.objid, |
| vp->val_len / sizeof(oid), network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| } |
| DEBUGINDENTLESS(); |
| break; |
| |
| case AGENTX_MSG_RESPONSE: |
| pdu->flags &= ~(UCD_MSG_FLAG_EXPECT_RESPONSE); |
| if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc, |
| pdu->time, network_order)) { |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGDUMPHEADER("send", "Response"); |
| DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4); |
| DEBUGMSG(("dumpv_send", " sysUpTime:\t%d\n", pdu->time)); |
| DEBUGINDENTLESS(); |
| |
| if (!agentx_realloc_build_short |
| (buf, buf_len, out_len, allow_realloc, |
| (u_short)pdu->errstat, |
| network_order) |
| || !agentx_realloc_build_short(buf, buf_len, out_len, |
| allow_realloc, |
| (u_short)pdu->errindex, |
| network_order)) { |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGDUMPHEADER("send", "Response errors"); |
| DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4); |
| DEBUGMSG(("dumpv_send", " errstat:\t%d\n", pdu->errstat)); |
| DEBUGPRINTINDENT("dumpv_send"); |
| DEBUGMSG(("dumpv_send", " errindex:\t%d\n", pdu->errindex)); |
| DEBUGINDENTLESS(); |
| |
| /* |
| * Fallthrough |
| */ |
| |
| case AGENTX_MSG_INDEX_ALLOCATE: |
| case AGENTX_MSG_INDEX_DEALLOCATE: |
| case AGENTX_MSG_NOTIFY: |
| case AGENTX_MSG_TESTSET: |
| DEBUGDUMPHEADER("send", "Get* Variable List"); |
| for (vp = pdu->variables; vp != NULL; vp = vp->next_variable) { |
| if (!agentx_realloc_build_varbind |
| (buf, buf_len, out_len, allow_realloc, vp, |
| network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| } |
| DEBUGINDENTLESS(); |
| break; |
| |
| case AGENTX_MSG_COMMITSET: |
| case AGENTX_MSG_UNDOSET: |
| case AGENTX_MSG_PING: |
| /* |
| * "Empty" packet. |
| */ |
| break; |
| |
| case AGENTX_MSG_CLEANUPSET: |
| pdu->flags &= ~(UCD_MSG_FLAG_EXPECT_RESPONSE); |
| break; |
| |
| case AGENTX_MSG_ADD_AGENT_CAPS: |
| DEBUGDUMPHEADER("send", "AgentCaps OID"); |
| if (!agentx_realloc_build_oid |
| (buf, buf_len, out_len, allow_realloc, 0, pdu->variables->name, |
| pdu->variables->name_length, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| |
| DEBUGDUMPHEADER("send", "AgentCaps Description"); |
| if (!agentx_realloc_build_string |
| (buf, buf_len, out_len, allow_realloc, |
| pdu->variables->val.string, pdu->variables->val_len, |
| network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| break; |
| |
| case AGENTX_MSG_REMOVE_AGENT_CAPS: |
| DEBUGDUMPHEADER("send", "AgentCaps OID"); |
| if (!agentx_realloc_build_oid |
| (buf, buf_len, out_len, allow_realloc, 0, pdu->variables->name, |
| pdu->variables->name_length, network_order)) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| break; |
| |
| default: |
| session->s_snmp_errno = SNMPERR_UNKNOWN_PDU; |
| return 0; |
| } |
| DEBUGINDENTLESS(); |
| |
| /* |
| * Fix the payload length (ignoring the 20-byte header). |
| */ |
| |
| agentx_build_int((*buf + 16), (*out_len - ilen) - 20, network_order); |
| |
| DEBUGMSGTL(("agentx_build", "packet built okay\n")); |
| return 1; |
| } |
| |
| int |
| agentx_realloc_build(netsnmp_session * session, netsnmp_pdu *pdu, |
| u_char ** buf, size_t * buf_len, size_t * out_len) |
| { |
| if (session == NULL || buf_len == NULL || |
| out_len == NULL || pdu == NULL || buf == NULL) { |
| return -1; |
| } |
| if (!_agentx_realloc_build(buf, buf_len, out_len, 1, session, pdu)) { |
| if (session->s_snmp_errno == 0) { |
| session->s_snmp_errno = SNMPERR_BAD_ASN1_BUILD; |
| } |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /*********************** |
| * |
| * Utility functions for parsing an AgentX packet |
| * |
| ***********************/ |
| |
| int |
| agentx_parse_int(u_char * data, u_int network_byte_order) |
| { |
| u_int value = 0; |
| |
| /* |
| * Note - this doesn't handle 'PDP_ENDIAN' systems |
| * If anyone needs this added, contact the coders list |
| */ |
| DEBUGDUMPSETUP("recv", data, 4); |
| if (network_byte_order) { |
| memmove(&value, data, 4); |
| #ifndef WORDS_BIGENDIAN |
| value = ntohl(value); |
| #endif |
| } else { |
| #ifndef WORDS_BIGENDIAN |
| memmove(&value, data, 4); |
| #else |
| /* |
| * The equivalent of the 'ntohl()' macro, |
| * except this macro is null on big-endian systems |
| */ |
| value += data[3]; |
| value <<= 8; |
| value += data[2]; |
| value <<= 8; |
| value += data[1]; |
| value <<= 8; |
| value += data[0]; |
| #endif |
| } |
| DEBUGMSG(("dumpv_recv", " Integer:\t%ld (0x%.2X)\n", value, value)); |
| |
| return value; |
| } |
| |
| |
| int |
| agentx_parse_short(u_char * data, u_int network_byte_order) |
| { |
| u_short value = 0; |
| |
| if (network_byte_order) { |
| memmove(&value, data, 2); |
| #ifndef WORDS_BIGENDIAN |
| value = ntohs(value); |
| #endif |
| } else { |
| #ifndef WORDS_BIGENDIAN |
| memmove(&value, data, 2); |
| #else |
| /* |
| * The equivalent of the 'ntohs()' macro, |
| * except this macro is null on big-endian systems |
| */ |
| value += data[1]; |
| value <<= 8; |
| value += data[0]; |
| #endif |
| } |
| |
| DEBUGDUMPSETUP("recv", data, 2); |
| DEBUGMSG(("dumpv_recv", " Short:\t%ld (0x%.2X)\n", value, value)); |
| return value; |
| } |
| |
| |
| u_char * |
| agentx_parse_oid(u_char * data, size_t * length, int *inc, |
| oid * oid_buf, size_t * oid_len, u_int network_byte_order) |
| { |
| u_int n_subid; |
| u_int prefix; |
| u_int tmp_oid_len; |
| int i; |
| int int_offset; |
| u_int *int_ptr = (u_int *)oid_buf; |
| u_char *buf_ptr = data; |
| |
| if (*length < 4) { |
| DEBUGMSGTL(("agentx", "Incomplete Object ID\n")); |
| return NULL; |
| } |
| |
| DEBUGDUMPHEADER("recv", "OID Header"); |
| DEBUGDUMPSETUP("recv", data, 4); |
| DEBUGMSG(("dumpv_recv", " # subids:\t%d (0x%.2X)\n", data[0], |
| data[0])); |
| DEBUGPRINTINDENT("dumpv_recv"); |
| DEBUGMSG(("dumpv_recv", " prefix: \t%d (0x%.2X)\n", data[1], |
| data[1])); |
| DEBUGPRINTINDENT("dumpv_recv"); |
| DEBUGMSG(("dumpv_recv", " inclusive:\t%d (0x%.2X)\n", data[2], |
| data[2])); |
| |
| DEBUGINDENTLESS(); |
| DEBUGDUMPHEADER("recv", "OID Segments"); |
| |
| n_subid = data[0]; |
| prefix = data[1]; |
| if (inc) |
| *inc = data[2]; |
| int_offset = sizeof(oid)/4; |
| |
| buf_ptr += 4; |
| *length -= 4; |
| |
| DEBUGMSG(("djp", " parse_oid\n")); |
| DEBUGMSG(("djp", " sizeof(oid) = %d\n", sizeof(oid))); |
| if (n_subid == 0 && prefix == 0) { |
| /* |
| * Null OID |
| */ |
| memset(int_ptr, 0, 2 * sizeof(oid)); |
| *oid_len = 2; |
| DEBUGPRINTINDENT("dumpv_recv"); |
| DEBUGMSG(("dumpv_recv", "OID: NULL (0.0)\n")); |
| DEBUGINDENTLESS(); |
| return buf_ptr; |
| } |
| |
| /* |
| * Check that the expanded OID will fit in the buffer provided |
| */ |
| tmp_oid_len = (prefix ? n_subid + 5 : n_subid); |
| if (*oid_len < tmp_oid_len) { |
| DEBUGMSGTL(("agentx", "Oversized Object ID\n")); |
| return NULL; |
| } |
| |
| #ifdef WORDS_BIGENDIAN |
| # define endianoff 1 |
| #else |
| # define endianoff 0 |
| #endif |
| if (*length < 4 * n_subid) { |
| DEBUGMSGTL(("agentx", "Incomplete Object ID\n")); |
| return NULL; |
| } |
| |
| if (prefix) { |
| if (int_offset == 2) { /* align OID values in 64 bit agent */ |
| memset(int_ptr, 0, 10*sizeof(int_ptr[0])); |
| int_ptr[0+endianoff] = 1; |
| int_ptr[2+endianoff] = 3; |
| int_ptr[4+endianoff] = 6; |
| int_ptr[6+endianoff] = 1; |
| int_ptr[8+endianoff] = prefix; |
| } else { /* assume int_offset == 1 */ |
| int_ptr[0] = 1; |
| int_ptr[1] = 3; |
| int_ptr[2] = 6; |
| int_ptr[3] = 1; |
| int_ptr[4] = prefix; |
| } |
| int_ptr = int_ptr + (int_offset * 5); |
| } |
| |
| for (i = 0; i < (int) (int_offset * n_subid); i = i + int_offset) { |
| int x; |
| |
| x = agentx_parse_int(buf_ptr, network_byte_order); |
| if (int_offset == 2) { |
| int_ptr[i+0] = 0; |
| int_ptr[i+1] = 0; |
| int_ptr[i+endianoff]=x; |
| } else { |
| int_ptr[i] = x; |
| } |
| buf_ptr += 4; |
| *length -= 4; |
| } |
| |
| *oid_len = tmp_oid_len; |
| |
| DEBUGINDENTLESS(); |
| DEBUGPRINTINDENT("dumpv_recv"); |
| DEBUGMSG(("dumpv_recv", "OID: ")); |
| DEBUGMSGOID(("dumpv_recv", oid_buf, *oid_len)); |
| DEBUGMSG(("dumpv_recv", "\n")); |
| |
| return buf_ptr; |
| } |
| |
| |
| |
| u_char * |
| agentx_parse_string(u_char * data, size_t * length, |
| u_char * string, size_t * str_len, |
| u_int network_byte_order) |
| { |
| u_int len; |
| |
| if (*length < 4) { |
| DEBUGMSGTL(("agentx", "Incomplete string (too short: %d)\n", |
| *length)); |
| return NULL; |
| } |
| |
| len = agentx_parse_int(data, network_byte_order); |
| if (*length < len + 4) { |
| DEBUGMSGTL(("agentx", "Incomplete string (still too short: %d)\n", |
| *length)); |
| return NULL; |
| } |
| if (len > *str_len) { |
| DEBUGMSGTL(("agentx", "String too long (too long)\n")); |
| return NULL; |
| } |
| memmove(string, data + 4, len); |
| string[len] = '\0'; |
| *str_len = len; |
| |
| len += 3; /* Extend the string length to include the padding */ |
| len >>= 2; |
| len <<= 2; |
| |
| *length -= (len + 4); |
| DEBUGDUMPSETUP("recv", data, (len + 4)); |
| DEBUGIF("dumpv_recv") { |
| u_char *buf = NULL; |
| size_t buf_len = 0, out_len = 0; |
| |
| if (sprint_realloc_asciistring(&buf, &buf_len, &out_len, 1, |
| string, len)) { |
| DEBUGMSG(("dumpv_recv", "String: %s\n", buf)); |
| } else { |
| DEBUGMSG(("dumpv_recv", "String: %s [TRUNCATED]\n", buf)); |
| } |
| if (buf != NULL) { |
| free(buf); |
| } |
| } |
| return data + (len + 4); |
| } |
| |
| u_char * |
| agentx_parse_opaque(u_char * data, size_t * length, int *type, |
| u_char * opaque_buf, size_t * opaque_len, |
| u_int network_byte_order) |
| { |
| #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES |
| union { |
| float floatVal; |
| double doubleVal; |
| int intVal[2]; |
| char c[sizeof(double)]; |
| } fu; |
| int tmp; |
| u_char *buf; |
| #endif |
| u_char *const cp = |
| agentx_parse_string(data, length, |
| opaque_buf, opaque_len, network_byte_order); |
| |
| #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES |
| if (cp == NULL) |
| return NULL; |
| |
| buf = opaque_buf; |
| |
| if ((*opaque_len <= 3) || (buf[0] != ASN_OPAQUE_TAG1)) |
| return cp; /* Unrecognised opaque type */ |
| |
| switch (buf[1]) { |
| case ASN_OPAQUE_FLOAT: |
| if ((*opaque_len != (3 + sizeof(float))) || |
| (buf[2] != sizeof(float))) |
| return cp; /* Encoding isn't right for FLOAT */ |
| |
| memcpy(&fu.c[0], &buf[3], sizeof(float)); |
| fu.intVal[0] = ntohl(fu.intVal[0]); |
| *opaque_len = sizeof(float); |
| memcpy(opaque_buf, &fu.c[0], sizeof(float)); |
| *type = ASN_OPAQUE_FLOAT; |
| DEBUGMSG(("dumpv_recv", "Float: %f\n", fu.floatVal)); |
| return cp; |
| |
| case ASN_OPAQUE_DOUBLE: |
| if ((*opaque_len != (3 + sizeof(double))) || |
| (buf[2] != sizeof(double))) |
| return cp; /* Encoding isn't right for DOUBLE */ |
| |
| memcpy(&fu.c[0], &buf[3], sizeof(double)); |
| tmp = ntohl(fu.intVal[1]); |
| fu.intVal[1] = ntohl(fu.intVal[0]); |
| fu.intVal[0] = tmp; |
| *opaque_len = sizeof(double); |
| memcpy(opaque_buf, &fu.c[0], sizeof(double)); |
| *type = ASN_OPAQUE_DOUBLE; |
| DEBUGMSG(("dumpv_recv", "Double: %lf\n", fu.doubleVal)); |
| return cp; |
| |
| case ASN_OPAQUE_I64: |
| case ASN_OPAQUE_U64: |
| case ASN_OPAQUE_COUNTER64: |
| default: |
| return cp; /* Unrecognised opaque sub-type */ |
| } |
| #else |
| return cp; |
| #endif |
| } |
| |
| |
| u_char * |
| agentx_parse_varbind(u_char * data, size_t * length, int *type, |
| oid * oid_buf, size_t * oid_len, |
| u_char * data_buf, size_t * data_len, |
| u_int network_byte_order) |
| { |
| u_char *bufp = data; |
| u_int int_val; |
| int int_offset; |
| u_int *int_ptr = (u_int *) data_buf; |
| struct counter64 tmp64; |
| |
| DEBUGDUMPHEADER("recv", "VarBind:"); |
| DEBUGDUMPHEADER("recv", "Type"); |
| *type = agentx_parse_short(bufp, network_byte_order); |
| DEBUGINDENTLESS(); |
| bufp += 4; |
| *length -= 4; |
| |
| bufp = agentx_parse_oid(bufp, length, NULL, oid_buf, oid_len, |
| network_byte_order); |
| if (bufp == NULL) { |
| DEBUGINDENTLESS(); |
| return NULL; |
| } |
| |
| switch (*type) { |
| case ASN_INTEGER: |
| case ASN_COUNTER: |
| case ASN_GAUGE: |
| case ASN_TIMETICKS: |
| case ASN_UINTEGER: |
| int_val = agentx_parse_int(bufp, network_byte_order); |
| memmove(data_buf, &int_val, 4); |
| *data_len = 4; |
| bufp += 4; |
| *length -= 4; |
| break; |
| |
| case ASN_OCTET_STR: |
| case ASN_IPADDRESS: |
| bufp = agentx_parse_string(bufp, length, data_buf, data_len, |
| network_byte_order); |
| break; |
| |
| case ASN_OPAQUE: |
| bufp = agentx_parse_opaque(bufp, length, type, data_buf, data_len, |
| network_byte_order); |
| break; |
| |
| case ASN_PRIV_INCL_RANGE: |
| case ASN_PRIV_EXCL_RANGE: |
| case ASN_OBJECT_ID: |
| bufp = |
| agentx_parse_oid(bufp, length, NULL, (oid *) data_buf, |
| data_len, network_byte_order); |
| *data_len *= sizeof(oid); |
| /* |
| * 'agentx_parse_oid()' returns the number of sub_ids |
| */ |
| break; |
| |
| case ASN_COUNTER64: |
| memset(&tmp64, 0, sizeof(tmp64)); |
| if (network_byte_order) { |
| tmp64.high = agentx_parse_int(bufp, network_byte_order); |
| tmp64.low = agentx_parse_int(bufp+4, network_byte_order); |
| } else { |
| tmp64.high = agentx_parse_int(bufp+4, network_byte_order); |
| tmp64.low = agentx_parse_int(bufp, network_byte_order); |
| } |
| |
| memcpy(data_buf, &tmp64, sizeof(tmp64)); |
| *data_len = sizeof(tmp64); |
| bufp += 8; |
| *length -= 8; |
| break; |
| |
| case ASN_NULL: |
| case SNMP_NOSUCHOBJECT: |
| case SNMP_NOSUCHINSTANCE: |
| case SNMP_ENDOFMIBVIEW: |
| /* |
| * No data associated with these types. |
| */ |
| *data_len = 0; |
| break; |
| |
| default: |
| DEBUGMSG(("recv", "Can not parse type %x", *type)); |
| DEBUGINDENTLESS(); |
| return NULL; |
| } |
| DEBUGINDENTLESS(); |
| return bufp; |
| } |
| |
| /* |
| * AgentX header: |
| * |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | h.version | h.type | h.flags | <reserved> | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | h.sessionID | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | h.transactionID | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | h.packetID | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | h.payload_length | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * |
| * Total length = 20 bytes |
| * |
| * If we don't seem to have the full packet, return NULL |
| * and let the driving code go back for the rest. |
| * Don't report this as an error, as it's quite "normal" |
| * with a connection-oriented service. |
| * |
| * Note that once the header has been successfully processed |
| * (and hence we should have the full packet), any subsequent |
| * "running out of room" is indeed an error. |
| */ |
| u_char * |
| agentx_parse_header(netsnmp_pdu *pdu, u_char * data, size_t * length) |
| { |
| register u_char *bufp = data; |
| size_t payload; |
| |
| if (*length < 20) { /* Incomplete header */ |
| return NULL; |
| } |
| |
| DEBUGDUMPHEADER("recv", "AgentX Header"); |
| DEBUGDUMPHEADER("recv", "Version"); |
| DEBUGDUMPSETUP("recv", bufp, 1); |
| pdu->version = AGENTX_VERSION_BASE | *bufp; |
| DEBUGMSG(("dumpv_recv", " Version:\t%d\n", *bufp)); |
| DEBUGINDENTLESS(); |
| bufp++; |
| |
| DEBUGDUMPHEADER("recv", "Command"); |
| DEBUGDUMPSETUP("recv", bufp, 1); |
| pdu->command = *bufp; |
| DEBUGMSG(("dumpv_recv", " Command:\t%d (%s)\n", *bufp, |
| agentx_cmd(*bufp))); |
| DEBUGINDENTLESS(); |
| bufp++; |
| |
| DEBUGDUMPHEADER("recv", "Flags"); |
| DEBUGDUMPSETUP("recv", bufp, 1); |
| pdu->flags |= *bufp; |
| DEBUGMSG(("dumpv_recv", " Flags:\t0x%x\n", *bufp)); |
| DEBUGINDENTLESS(); |
| bufp++; |
| |
| DEBUGDUMPHEADER("recv", "Reserved Byte"); |
| DEBUGDUMPSETUP("recv", bufp, 1); |
| DEBUGMSG(("dumpv_recv", " Reserved:\t0x%x\n", *bufp)); |
| DEBUGINDENTLESS(); |
| bufp++; |
| |
| DEBUGDUMPHEADER("recv", "Session ID"); |
| pdu->sessid = agentx_parse_int(bufp, |
| pdu-> |
| flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| DEBUGINDENTLESS(); |
| bufp += 4; |
| |
| DEBUGDUMPHEADER("recv", "Transaction ID"); |
| pdu->transid = agentx_parse_int(bufp, |
| pdu-> |
| flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| DEBUGINDENTLESS(); |
| bufp += 4; |
| |
| DEBUGDUMPHEADER("recv", "Packet ID"); |
| pdu->reqid = agentx_parse_int(bufp, |
| pdu-> |
| flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| DEBUGINDENTLESS(); |
| bufp += 4; |
| |
| DEBUGDUMPHEADER("recv", "Payload Length"); |
| payload = agentx_parse_int(bufp, |
| pdu-> |
| flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| DEBUGINDENTLESS(); |
| bufp += 4; |
| |
| *length -= 20; |
| if (*length != payload) { /* Short payload */ |
| return NULL; |
| } |
| return bufp; |
| } |
| |
| |
| int |
| agentx_parse(netsnmp_session * session, netsnmp_pdu *pdu, u_char * data, |
| size_t len) |
| { |
| register u_char *bufp = data; |
| u_char buffer[SNMP_MAX_MSG_SIZE]; |
| oid oid_buffer[MAX_OID_LEN], end_oid_buf[MAX_OID_LEN]; |
| size_t buf_len = sizeof(buffer); |
| size_t oid_buf_len = MAX_OID_LEN; |
| size_t end_oid_buf_len = MAX_OID_LEN; |
| |
| int range_bound; /* OID-range upper bound */ |
| int inc; /* Inclusive SearchRange flag */ |
| int type; /* VarBind data type */ |
| size_t *length = &len; |
| |
| if (pdu == NULL) |
| return (0); |
| |
| if (!IS_AGENTX_VERSION(session->version)) |
| return SNMPERR_BAD_VERSION; |
| |
| #ifndef SNMPERR_INCOMPLETE_PACKET |
| /* |
| * Ideally, "short" packets on stream connections should |
| * be handled specially, and the driving code set up to |
| * keep reading until the full packet is received. |
| * |
| * For now, lets assume that all packets are read in one go. |
| * I've probably inflicted enough damage on the UCD library |
| * for one week! |
| * |
| * I'll come back to this once Wes is speaking to me again. |
| */ |
| #define SNMPERR_INCOMPLETE_PACKET SNMPERR_ASN_PARSE_ERR |
| #endif |
| |
| |
| /* |
| * Handle (common) header .... |
| */ |
| bufp = agentx_parse_header(pdu, bufp, length); |
| if (bufp == NULL) |
| return SNMPERR_INCOMPLETE_PACKET; /* i.e. wait for the rest */ |
| |
| /* |
| * Control PDU handling |
| */ |
| pdu->flags |= UCD_MSG_FLAG_ALWAYS_IN_VIEW; |
| pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY; |
| pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU); |
| |
| /* |
| * ... and (not-un-common) context |
| */ |
| if (pdu->flags & AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT) { |
| DEBUGDUMPHEADER("recv", "Context"); |
| bufp = agentx_parse_string(bufp, length, buffer, &buf_len, |
| pdu->flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| DEBUGINDENTLESS(); |
| if (bufp == NULL) |
| return SNMPERR_ASN_PARSE_ERR; |
| |
| pdu->community_len = buf_len; |
| snmp_clone_mem((void **) &pdu->community, |
| (void *) buffer, (unsigned) buf_len); |
| buf_len = sizeof(buffer); |
| } |
| |
| DEBUGDUMPHEADER("recv", "PDU"); |
| DEBUGINDENTMORE(); |
| switch (pdu->command) { |
| case AGENTX_MSG_OPEN: |
| pdu->time = *bufp; /* Timeout */ |
| bufp += 4; |
| *length -= 4; |
| |
| /* |
| * Store subagent OID & description in a VarBind |
| */ |
| DEBUGDUMPHEADER("recv", "Subagent OID"); |
| bufp = agentx_parse_oid(bufp, length, NULL, |
| oid_buffer, &oid_buf_len, |
| pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| DEBUGINDENTLESS(); |
| if (bufp == NULL) { |
| DEBUGINDENTLESS(); |
| return SNMPERR_ASN_PARSE_ERR; |
| } |
| DEBUGDUMPHEADER("recv", "Subagent Description"); |
| bufp = agentx_parse_string(bufp, length, buffer, &buf_len, |
| pdu->flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| DEBUGINDENTLESS(); |
| if (bufp == NULL) { |
| DEBUGINDENTLESS(); |
| return SNMPERR_ASN_PARSE_ERR; |
| } |
| snmp_pdu_add_variable(pdu, oid_buffer, oid_buf_len, |
| ASN_OCTET_STR, buffer, buf_len); |
| |
| oid_buf_len = MAX_OID_LEN; |
| buf_len = sizeof(buffer); |
| break; |
| |
| case AGENTX_MSG_CLOSE: |
| pdu->errstat = *bufp; /* Reason */ |
| bufp += 4; |
| *length -= 4; |
| |
| break; |
| |
| case AGENTX_MSG_UNREGISTER: |
| case AGENTX_MSG_REGISTER: |
| DEBUGDUMPHEADER("recv", "Registration Header"); |
| if (pdu->command == AGENTX_MSG_REGISTER) { |
| pdu->time = *bufp; /* Timeout (Register only) */ |
| DEBUGDUMPSETUP("recv", bufp, 1); |
| DEBUGMSG(("dumpv_recv", " Timeout: \t%d\n", *bufp)); |
| } |
| bufp++; |
| pdu->priority = *bufp; |
| DEBUGDUMPSETUP("recv", bufp, 1); |
| DEBUGMSG(("dumpv_recv", " Priority: \t%d\n", *bufp)); |
| bufp++; |
| pdu->range_subid = *bufp; |
| DEBUGDUMPSETUP("recv", bufp, 1); |
| DEBUGMSG(("dumpv_recv", " Range Sub-Id:\t%d\n", *bufp)); |
| bufp++; |
| bufp++; |
| *length -= 4; |
| DEBUGINDENTLESS(); |
| |
| DEBUGDUMPHEADER("recv", "Registration OID"); |
| bufp = agentx_parse_oid(bufp, length, NULL, |
| oid_buffer, &oid_buf_len, |
| pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| DEBUGINDENTLESS(); |
| if (bufp == NULL) { |
| DEBUGINDENTLESS(); |
| return SNMPERR_ASN_PARSE_ERR; |
| } |
| |
| if (pdu->range_subid) { |
| range_bound = agentx_parse_int(bufp, pdu->flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| bufp += 4; |
| *length -= 4; |
| |
| /* |
| * Construct the end-OID. |
| */ |
| end_oid_buf_len = oid_buf_len * sizeof(oid); |
| memcpy(end_oid_buf, oid_buffer, end_oid_buf_len); |
| end_oid_buf[pdu->range_subid - 1] = range_bound; |
| |
| snmp_pdu_add_variable(pdu, oid_buffer, oid_buf_len, |
| ASN_PRIV_INCL_RANGE, |
| (u_char *) end_oid_buf, end_oid_buf_len); |
| } else { |
| snmp_add_null_var(pdu, oid_buffer, oid_buf_len); |
| } |
| |
| oid_buf_len = MAX_OID_LEN; |
| break; |
| |
| case AGENTX_MSG_GETBULK: |
| DEBUGDUMPHEADER("recv", "Non-repeaters"); |
| pdu->non_repeaters = agentx_parse_short(bufp, pdu->flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| DEBUGINDENTLESS(); |
| DEBUGDUMPHEADER("recv", "Max-repeaters"); |
| pdu->max_repetitions = agentx_parse_short(bufp + 2, pdu->flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| DEBUGINDENTLESS(); |
| bufp += 4; |
| *length -= 4; |
| /* |
| * Fallthrough - SearchRange handling is the same |
| */ |
| |
| case AGENTX_MSG_GETNEXT: |
| case AGENTX_MSG_GET: |
| |
| /* |
| * * SearchRange List |
| * * Keep going while we have data left |
| */ |
| DEBUGDUMPHEADER("recv", "Search Range"); |
| while (*length > 0) { |
| bufp = agentx_parse_oid(bufp, length, &inc, |
| oid_buffer, &oid_buf_len, |
| pdu->flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| if (bufp == NULL) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return SNMPERR_ASN_PARSE_ERR; |
| } |
| bufp = agentx_parse_oid(bufp, length, NULL, |
| end_oid_buf, &end_oid_buf_len, |
| pdu->flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| if (bufp == NULL) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return SNMPERR_ASN_PARSE_ERR; |
| } |
| end_oid_buf_len *= sizeof(oid); |
| /* |
| * 'agentx_parse_oid()' returns the number of sub_ids |
| */ |
| |
| if (inc) { |
| snmp_pdu_add_variable(pdu, oid_buffer, oid_buf_len, |
| ASN_PRIV_INCL_RANGE, |
| (u_char *) end_oid_buf, |
| end_oid_buf_len); |
| } else { |
| snmp_pdu_add_variable(pdu, oid_buffer, oid_buf_len, |
| ASN_PRIV_EXCL_RANGE, |
| (u_char *) end_oid_buf, |
| end_oid_buf_len); |
| } |
| oid_buf_len = MAX_OID_LEN; |
| end_oid_buf_len = MAX_OID_LEN; |
| } |
| |
| DEBUGINDENTLESS(); |
| break; |
| |
| |
| case AGENTX_MSG_RESPONSE: |
| |
| pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU; |
| |
| /* |
| * sysUpTime |
| */ |
| pdu->time = agentx_parse_int(bufp, pdu->flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| bufp += 4; |
| *length -= 4; |
| |
| pdu->errstat = agentx_parse_short(bufp, pdu->flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| pdu->errindex = |
| agentx_parse_short(bufp + 2, |
| pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| bufp += 4; |
| *length -= 4; |
| /* |
| * Fallthrough - VarBind handling is the same |
| */ |
| |
| case AGENTX_MSG_INDEX_ALLOCATE: |
| case AGENTX_MSG_INDEX_DEALLOCATE: |
| case AGENTX_MSG_NOTIFY: |
| case AGENTX_MSG_TESTSET: |
| |
| /* |
| * * VarBind List |
| * * Keep going while we have data left |
| */ |
| |
| DEBUGDUMPHEADER("recv", "VarBindList"); |
| while (*length > 0) { |
| bufp = agentx_parse_varbind(bufp, length, &type, |
| oid_buffer, &oid_buf_len, |
| buffer, &buf_len, |
| pdu->flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| if (bufp == NULL) { |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return SNMPERR_ASN_PARSE_ERR; |
| } |
| snmp_pdu_add_variable(pdu, oid_buffer, oid_buf_len, |
| (u_char) type, buffer, buf_len); |
| |
| oid_buf_len = MAX_OID_LEN; |
| buf_len = sizeof(buffer); |
| } |
| DEBUGINDENTLESS(); |
| break; |
| |
| case AGENTX_MSG_COMMITSET: |
| case AGENTX_MSG_UNDOSET: |
| case AGENTX_MSG_CLEANUPSET: |
| case AGENTX_MSG_PING: |
| |
| /* |
| * "Empty" packet |
| */ |
| break; |
| |
| |
| case AGENTX_MSG_ADD_AGENT_CAPS: |
| /* |
| * Store AgentCap OID & description in a VarBind |
| */ |
| bufp = agentx_parse_oid(bufp, length, NULL, |
| oid_buffer, &oid_buf_len, |
| pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| if (bufp == NULL) |
| return SNMPERR_ASN_PARSE_ERR; |
| bufp = agentx_parse_string(bufp, length, buffer, &buf_len, |
| pdu->flags & |
| AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| if (bufp == NULL) |
| return SNMPERR_ASN_PARSE_ERR; |
| snmp_pdu_add_variable(pdu, oid_buffer, oid_buf_len, |
| ASN_OCTET_STR, buffer, buf_len); |
| |
| oid_buf_len = MAX_OID_LEN; |
| buf_len = sizeof(buffer); |
| break; |
| |
| case AGENTX_MSG_REMOVE_AGENT_CAPS: |
| /* |
| * Store AgentCap OID & description in a VarBind |
| */ |
| bufp = agentx_parse_oid(bufp, length, NULL, |
| oid_buffer, &oid_buf_len, |
| pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER); |
| if (bufp == NULL) |
| return SNMPERR_ASN_PARSE_ERR; |
| snmp_add_null_var(pdu, oid_buffer, oid_buf_len); |
| |
| oid_buf_len = MAX_OID_LEN; |
| break; |
| |
| default: |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| DEBUGMSGTL(("agentx", "Unrecognised PDU type: %d\n", |
| pdu->command)); |
| return SNMPERR_UNKNOWN_PDU; |
| } |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| DEBUGINDENTLESS(); |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| |
| #ifdef TESTING |
| |
| testit(netsnmp_pdu *pdu1) |
| { |
| char packet1[BUFSIZ]; |
| char packet2[BUFSIZ]; |
| int len1, len2; |
| netsnmp_pdu pdu2; |
| netsnmp_session sess; |
| |
| memset(&pdu2, 0, sizeof(netsnmp_pdu)); |
| memset(packet1, 0, BUFSIZ); |
| memset(packet2, 0, BUFSIZ); |
| |
| /* |
| * Encode this into a "packet" |
| */ |
| len1 = BUFSIZ; |
| if (agentx_build(&sess, pdu1, packet1, &len1) < 0) { |
| DEBUGMSGTL(("agentx", "First build failed\n")); |
| exit(1); |
| } |
| |
| DEBUGMSGTL(("agentx", "First build succeeded:\n")); |
| xdump(packet1, len1, "Ax1> "); |
| |
| /* |
| * Unpack this into a PDU |
| */ |
| len2 = len1; |
| if (agentx_parse(&pdu2, packet1, &len2, (u_char **) NULL) < 0) { |
| DEBUGMSGTL(("agentx", "First parse failed\n")); |
| exit(1); |
| } |
| DEBUGMSGTL(("agentx", "First parse succeeded:\n")); |
| if (len2 != 0) |
| DEBUGMSGTL(("agentx", |
| "Warning - parsed packet has %d bytes left\n", len2)); |
| |
| /* |
| * Encode this into another "packet" |
| */ |
| len2 = BUFSIZ; |
| if (agentx_build(&sess, &pdu2, packet2, &len2) < 0) { |
| DEBUGMSGTL(("agentx", "Second build failed\n")); |
| exit(1); |
| } |
| |
| DEBUGMSGTL(("agentx", "Second build succeeded:\n")); |
| xdump(packet2, len2, "Ax2> "); |
| |
| /* |
| * Compare the results |
| */ |
| if (len1 != len2) { |
| DEBUGMSGTL(("agentx", |
| "Error: first build (%d) is different to second (%d)\n", |
| len1, len2)); |
| exit(1); |
| } |
| if (memcmp(packet1, packet2, len1) != 0) { |
| DEBUGMSGTL(("agentx", |
| "Error: first build data is different to second\n")); |
| exit(1); |
| } |
| |
| DEBUGMSGTL(("agentx", "OK\n")); |
| } |
| |
| |
| |
| main() |
| { |
| netsnmp_pdu pdu1; |
| oid oid_buf[] = { 1, 3, 6, 1, 2, 1, 10 }; |
| oid oid_buf2[] = { 1, 3, 6, 1, 2, 1, 20 }; |
| oid null_oid[] = { 0, 0 }; |
| char *string = "Example string"; |
| char *context = "LUCS"; |
| |
| |
| /* |
| * Create an example AgentX pdu structure |
| */ |
| |
| memset(&pdu1, 0, sizeof(netsnmp_pdu)); |
| pdu1.command = AGENTX_MSG_TESTSET; |
| pdu1.flags = 0; |
| pdu1.sessid = 16; |
| pdu1.transid = 24; |
| pdu1.reqid = 132; |
| |
| pdu1.time = 10; |
| pdu1.non_repeaters = 3; |
| pdu1.max_repetitions = 32; |
| pdu1.priority = 5; |
| pdu1.range_subid = 0; |
| |
| snmp_pdu_add_variable(&pdu1, oid_buf, sizeof(oid_buf) / sizeof(oid), |
| ASN_OBJECT_ID, (char *) oid_buf2, |
| sizeof(oid_buf2)); |
| snmp_pdu_add_variable(&pdu1, oid_buf, sizeof(oid_buf) / sizeof(oid), |
| ASN_INTEGER, (char *) &pdu1.reqid, |
| sizeof(pdu1.reqid)); |
| snmp_pdu_add_variable(&pdu1, oid_buf, sizeof(oid_buf) / sizeof(oid), |
| ASN_OCTET_STR, (char *) string, strlen(string)); |
| |
| printf("Test with non-network order.....\n"); |
| testit(&pdu1); |
| |
| printf("\nTest with network order.....\n"); |
| pdu1.flags |= AGENTX_FLAGS_NETWORK_BYTE_ORDER; |
| testit(&pdu1); |
| |
| pdu1.community = context; |
| pdu1.community_len = strlen(context); |
| pdu1.flags |= AGENTX_FLAGS_NON_DEFAULT_CONTEXT; |
| printf("Test with non-default context.....\n"); |
| testit(&pdu1); |
| |
| |
| } |
| #endif |
| |
| /* |
| * returns the proper length of an incoming agentx packet. |
| */ |
| /* |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | h.version | h.type | h.flags | <reserved> | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | h.sessionID | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | h.transactionID | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | h.packetID | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | h.payload_length | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * 20 bytes in header |
| */ |
| |
| int |
| agentx_check_packet(u_char * packet, size_t packet_len) |
| { |
| |
| if (packet_len < 20) |
| return 0; /* minimum header length == 20 */ |
| |
| return agentx_parse_int(packet + 16, |
| *(packet + |
| 2) & AGENTX_FLAGS_NETWORK_BYTE_ORDER) + 20; |
| } |