📄 protocol.c
字号:
* | 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(struct snmp_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;}intagentx_parse(struct snmp_session *session, struct snmp_pdu *pdu, u_char *data, size_t len){ register u_char *bufp = data; u_char buffer[BUFSIZ]; u_char *prefix_ptr; oid oid_buffer[MAX_OID_LEN], end_oid_buf[MAX_OID_LEN]; size_t buf_len = BUFSIZ; 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 ) { /* Dump the packet in a formatted style */ pdu = (struct snmp_pdu *)malloc( sizeof( struct snmp_pdu )); free( pdu ); 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 = BUFSIZ; } 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 = BUFSIZ; break; case AGENTX_MSG_CLOSE: pdu->errstat = *bufp; /* Reason */ bufp += 4; *length -= 4; break; case AGENTX_MSG_UNREGISTER: case AGENTX_MSG_REGISTER: pdu->time = *bufp; /* Timeout (Register only) */ bufp++; pdu->priority = *bufp; bufp++; pdu->range_subid = *bufp; bufp++; bufp++; *length -= 4; prefix_ptr = bufp+1; 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 ) { if ( *prefix_ptr ) { pdu->range_subid += 5; } 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); memmove( &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); } DEBUGINDENTLESS(); oid_buf_len = MAX_OID_LEN; end_oid_buf_len = MAX_OID_LEN; 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 = BUFSIZ; } 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 = BUFSIZ; 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")); return SNMPERR_UNKNOWN_PDU; } DEBUGINDENTLESS(); DEBUGINDENTLESS(); DEBUGINDENTLESS(); return SNMP_ERR_NOERROR;}#ifdef TESTINGtestit( struct snmp_pdu *pdu1){ char packet1[BUFSIZ]; char packet2[BUFSIZ]; int len1, len2; struct snmp_pdu pdu2; struct snmp_session sess; memset( &pdu2, 0, sizeof(struct snmp_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")); 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 (){ struct snmp_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(struct snmp_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 */intagentx_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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -