| /* |
| * snmptest.c - send snmp requests to a network entity. |
| * |
| * Usage: snmptest -v 1 [-q] hostname community [objectID] |
| * |
| */ |
| /*********************************************************************** |
| Copyright 1988, 1989, 1991, 1992 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 <net-snmp/net-snmp-config.h> |
| |
| #if HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #if HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif |
| #if HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| #include <sys/types.h> |
| #if HAVE_NETINET_IN_H |
| #include <netinet/in.h> |
| #endif |
| #include <stdio.h> |
| #include <ctype.h> |
| #if TIME_WITH_SYS_TIME |
| # include <sys/time.h> |
| # include <time.h> |
| #else |
| # if HAVE_SYS_TIME_H |
| # include <sys/time.h> |
| # else |
| # include <time.h> |
| # endif |
| #endif |
| #if HAVE_SYS_SELECT_H |
| #include <sys/select.h> |
| #endif |
| #if HAVE_NETDB_H |
| #include <netdb.h> |
| #endif |
| #if HAVE_ARPA_INET_H |
| #include <arpa/inet.h> |
| #endif |
| |
| #include <net-snmp/net-snmp-includes.h> |
| |
| int command = SNMP_MSG_GET; |
| |
| int input_variable(netsnmp_variable_list *); |
| |
| void |
| usage(void) |
| { |
| fprintf(stderr, "USAGE: snmptest "); |
| snmp_parse_args_usage(stderr); |
| fprintf(stderr, "\n\n"); |
| snmp_parse_args_descriptions(stderr); |
| } |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| netsnmp_session session, *ss; |
| netsnmp_pdu *pdu = NULL, *response, *copy = NULL; |
| netsnmp_variable_list *vars, *vp; |
| netsnmp_transport *transport = NULL; |
| int ret; |
| int status, count; |
| char input[128]; |
| int varcount, nonRepeaters = -1, maxRepetitions; |
| |
| /* |
| * get the common command line arguments |
| */ |
| switch (snmp_parse_args(argc, argv, &session, NULL, NULL)) { |
| case NETSNMP_PARSE_ARGS_ERROR: |
| exit(1); |
| case NETSNMP_PARSE_ARGS_SUCCESS_EXIT: |
| exit(0); |
| case NETSNMP_PARSE_ARGS_ERROR_USAGE: |
| usage(); |
| exit(1); |
| default: |
| break; |
| } |
| |
| SOCK_STARTUP; |
| |
| /* |
| * open an SNMP session |
| */ |
| ss = snmp_open(&session); |
| if (ss == NULL) { |
| /* |
| * diagnose snmp_open errors with the input netsnmp_session pointer |
| */ |
| snmp_sess_perror("snmptest", &session); |
| SOCK_CLEANUP; |
| exit(1); |
| } |
| |
| varcount = 0; |
| for(;;) { |
| vars = NULL; |
| for (ret = 1; ret != 0;) { |
| vp = (netsnmp_variable_list *) |
| malloc(sizeof(netsnmp_variable_list)); |
| memset(vp, 0, sizeof(netsnmp_variable_list)); |
| |
| while ((ret = input_variable(vp)) == -1); |
| if (ret == 1) { |
| varcount++; |
| /* |
| * add it to the list |
| */ |
| if (vars == NULL) { |
| /* |
| * if first variable |
| */ |
| pdu = snmp_pdu_create(command); |
| pdu->variables = vp; |
| } else { |
| vars->next_variable = vp; |
| } |
| vars = vp; |
| } else { |
| /* |
| * free the last (unused) variable |
| */ |
| if (vp->name) |
| free((char *) vp->name); |
| if (vp->val.string) |
| free((char *) vp->val.string); |
| free((char *) vp); |
| |
| if (command == SNMP_MSG_GETBULK) { |
| if (nonRepeaters == -1) { |
| nonRepeaters = varcount; |
| ret = -1; /* so we collect more variables */ |
| printf("Now input the repeating variables\n"); |
| } else { |
| printf("What repeat count? "); |
| fflush(stdout); |
| if (!fgets(input, sizeof(input), stdin)) { |
| printf("Quitting, Goodbye\n"); |
| SOCK_CLEANUP; |
| exit(0); |
| } |
| maxRepetitions = atoi(input); |
| pdu->non_repeaters = nonRepeaters; |
| pdu->max_repetitions = maxRepetitions; |
| } |
| } |
| } |
| if (varcount == 0 && ret == 0) { |
| if (!copy) { |
| printf("No PDU to send.\n"); |
| ret = -1; |
| } else { |
| pdu = snmp_clone_pdu(copy); |
| printf("Resending last PDU.\n"); |
| } |
| } |
| } |
| copy = snmp_clone_pdu(pdu); |
| if (command == SNMP_MSG_TRAP2) { |
| /* |
| * No response needed |
| */ |
| if (!snmp_send(ss, pdu)) { |
| snmp_free_pdu(pdu); |
| snmp_sess_perror("snmptest", ss); |
| } |
| } else { |
| status = snmp_synch_response(ss, pdu, &response); |
| if (status == STAT_SUCCESS) { |
| if (command == SNMP_MSG_INFORM && |
| response->errstat == SNMP_ERR_NOERROR) { |
| printf("Inform Acknowledged\n"); |
| } else { |
| switch (response->command) { |
| case SNMP_MSG_GET: |
| printf("Received Get Request "); |
| break; |
| case SNMP_MSG_GETNEXT: |
| printf("Received Getnext Request "); |
| break; |
| case SNMP_MSG_RESPONSE: |
| printf("Received Get Response "); |
| break; |
| #ifndef NETSNMP_NO_WRITE_SUPPORT |
| case SNMP_MSG_SET: |
| printf("Received Set Request "); |
| break; |
| #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
| case SNMP_MSG_TRAP: |
| printf("Received Trap Request "); |
| break; |
| case SNMP_MSG_GETBULK: |
| printf("Received Bulk Request "); |
| break; |
| case SNMP_MSG_INFORM: |
| printf("Received Inform Request "); |
| break; |
| case SNMP_MSG_TRAP2: |
| printf("Received SNMPv2 Trap Request "); |
| break; |
| } |
| transport = snmp_sess_transport(snmp_sess_pointer(ss)); |
| if (transport != NULL && transport->f_fmtaddr != NULL) { |
| char *addr_string = transport->f_fmtaddr(transport, |
| response-> |
| transport_data, |
| response-> |
| transport_data_length); |
| if (addr_string != NULL) { |
| printf("from %s\n", addr_string); |
| free(addr_string); |
| } |
| } else { |
| printf("from <UNKNOWN>\n"); |
| } |
| printf |
| ("requestid 0x%lX errstat 0x%lX errindex 0x%lX\n", |
| response->reqid, response->errstat, |
| response->errindex); |
| if (response->errstat == SNMP_ERR_NOERROR) { |
| for (vars = response->variables; vars; |
| vars = vars->next_variable) |
| print_variable(vars->name, vars->name_length, |
| vars); |
| } else { |
| printf("Error in packet.\nReason: %s\n", |
| snmp_errstring(response->errstat)); |
| if (response->errindex != 0) { |
| for (count = 1, vars = response->variables; |
| vars && count != response->errindex; |
| vars = vars->next_variable, count++); |
| if (vars) { |
| printf("Failed object: "); |
| print_objid(vars->name, vars->name_length); |
| } |
| printf("\n"); |
| } |
| } |
| } |
| } else if (status == STAT_TIMEOUT) { |
| printf("Timeout: No Response from %s\n", session.peername); |
| } else { /* status == STAT_ERROR */ |
| snmp_sess_perror("snmptest", ss); |
| } |
| |
| if (response) |
| snmp_free_pdu(response); |
| } |
| varcount = 0; |
| nonRepeaters = -1; |
| } |
| /* NOTREACHED */ |
| } |
| |
| int |
| input_variable(netsnmp_variable_list * vp) |
| { |
| char buf[256]; |
| size_t val_len; |
| u_char ch; |
| |
| printf("Variable: "); |
| fflush(stdout); |
| if (!fgets(buf, sizeof(buf), stdin)) { |
| printf("Quitting, Goobye\n"); |
| SOCK_CLEANUP; |
| exit(0); |
| } |
| val_len = strlen(buf); |
| |
| if (val_len == 0 || *buf == '\n') { |
| vp->name_length = 0; |
| return 0; |
| } |
| if (buf[val_len - 1] == '\n') |
| buf[--val_len] = 0; |
| if (*buf == '$') { |
| switch (toupper((unsigned char)(buf[1]))) { |
| case 'G': |
| command = SNMP_MSG_GET; |
| printf("Request type is Get Request\n"); |
| break; |
| case 'N': |
| command = SNMP_MSG_GETNEXT; |
| printf("Request type is Getnext Request\n"); |
| break; |
| #ifndef NETSNMP_NO_WRITE_SUPPORT |
| case 'S': |
| command = SNMP_MSG_SET; |
| printf("Request type is Set Request\n"); |
| break; |
| #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
| case 'B': |
| command = SNMP_MSG_GETBULK; |
| printf("Request type is Bulk Request\n"); |
| printf |
| ("Enter a blank line to terminate the list of non-repeaters\n"); |
| printf("and to begin the repeating variables\n"); |
| break; |
| case 'I': |
| command = SNMP_MSG_INFORM; |
| printf("Request type is Inform Request\n"); |
| printf("(Are you sending to the right port?)\n"); |
| break; |
| case 'T': |
| command = SNMP_MSG_TRAP2; |
| printf("Request type is SNMPv2 Trap Request\n"); |
| printf("(Are you sending to the right port?)\n"); |
| break; |
| case 'D': |
| if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, |
| NETSNMP_DS_LIB_DUMP_PACKET)) { |
| netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, |
| NETSNMP_DS_LIB_DUMP_PACKET, 0); |
| printf("Turned packet dump off\n"); |
| } else { |
| netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, |
| NETSNMP_DS_LIB_DUMP_PACKET, 1); |
| printf("Turned packet dump on\n"); |
| } |
| break; |
| case 'Q': |
| switch ((toupper((unsigned char)(buf[2])))) { |
| case '\n': |
| case 0: |
| printf("Quitting, Goodbye\n"); |
| SOCK_CLEANUP; |
| exit(0); |
| break; |
| case 'P': |
| if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, |
| NETSNMP_DS_LIB_QUICK_PRINT)) { |
| netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, |
| NETSNMP_DS_LIB_QUICK_PRINT, 0); |
| printf("Turned quick printing off\n"); |
| } else { |
| netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, |
| NETSNMP_DS_LIB_QUICK_PRINT, 1); |
| printf("Turned quick printing on\n"); |
| } |
| break; |
| } |
| break; |
| default: |
| printf("Bad command\n"); |
| } |
| return -1; |
| } |
| { |
| oid name[MAX_OID_LEN]; |
| vp->name_length = MAX_OID_LEN; |
| if (!snmp_parse_oid(buf, name, &vp->name_length)) { |
| snmp_perror(buf); |
| return -1; |
| } |
| vp->name = snmp_duplicate_objid(name, vp->name_length); |
| } |
| |
| if (command == SNMP_MSG_INFORM |
| || command == SNMP_MSG_TRAP2 |
| #ifndef NETSNMP_NO_WRITE_SUPPORT |
| || command == SNMP_MSG_SET |
| #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
| ) { |
| printf("Type [i|u|s|x|d|n|o|t|a]: "); |
| fflush(stdout); |
| if (!fgets(buf, sizeof(buf), stdin)) { |
| printf("Quitting, Goodbye\n"); |
| SOCK_CLEANUP; |
| exit(0); |
| } |
| ch = *buf; |
| switch (ch) { |
| case 'i': |
| vp->type = ASN_INTEGER; |
| break; |
| case 'u': |
| vp->type = ASN_UNSIGNED; |
| break; |
| case 's': |
| vp->type = ASN_OCTET_STR; |
| break; |
| case 'x': |
| vp->type = ASN_OCTET_STR; |
| break; |
| case 'd': |
| vp->type = ASN_OCTET_STR; |
| break; |
| case 'n': |
| vp->type = ASN_NULL; |
| break; |
| case 'o': |
| vp->type = ASN_OBJECT_ID; |
| break; |
| case 't': |
| vp->type = ASN_TIMETICKS; |
| break; |
| case 'a': |
| vp->type = ASN_IPADDRESS; |
| break; |
| default: |
| printf |
| ("bad type \"%c\", use \"i\", \"u\", \"s\", \"x\", \"d\", \"n\", \"o\", \"t\", or \"a\".\n", |
| *buf); |
| return -1; |
| } |
| getValue: |
| printf("Value: "); |
| fflush(stdout); |
| if (!fgets(buf, sizeof(buf), stdin)) { |
| printf("Quitting, Goodbye\n"); |
| SOCK_CLEANUP; |
| exit(0); |
| } |
| switch (vp->type) { |
| case ASN_INTEGER: |
| vp->val.integer = (long *) malloc(sizeof(long)); |
| *(vp->val.integer) = atoi(buf); |
| vp->val_len = sizeof(long); |
| break; |
| case ASN_UNSIGNED: |
| vp->val.integer = (long *) malloc(sizeof(long)); |
| *(vp->val.integer) = strtoul(buf, NULL, 0); |
| vp->val_len = sizeof(long); |
| break; |
| case ASN_OCTET_STR: |
| if (ch == 'd') { |
| size_t buf_len = 256; |
| val_len = 0; |
| if ((vp->val.string = (u_char *) malloc(buf_len)) == NULL) { |
| printf("malloc failure\n"); |
| goto getValue; |
| } |
| if (!snmp_decimal_to_binary(&(vp->val.string), &buf_len, |
| &val_len, 1, buf)) { |
| printf("Bad value or no sub-identifier > 255\n"); |
| free(vp->val.string); |
| goto getValue; |
| } |
| vp->val_len = val_len; |
| } else if (ch == 's') { |
| /* |
| * -1 to omit trailing newline |
| */ |
| vp->val.string = (u_char *) malloc(strlen(buf) - 1); |
| if (vp->val.string == NULL) { |
| printf("malloc failure\n"); |
| goto getValue; |
| } |
| memcpy(vp->val.string, buf, strlen(buf) - 1); |
| vp->val.string[sizeof(vp->val.string)-1] = 0; |
| vp->val_len = strlen(buf) - 1; |
| } else if (ch == 'x') { |
| size_t buf_len = 256; |
| val_len = 0; |
| if ((vp->val.string = (u_char *) malloc(buf_len)) == NULL) { |
| printf("malloc failure\n"); |
| goto getValue; |
| } |
| if (!snmp_hex_to_binary(&(vp->val.string), &buf_len, |
| &val_len, 1, buf)) { |
| printf("Bad value (need pairs of hex digits)\n"); |
| free(vp->val.string); |
| goto getValue; |
| } |
| vp->val_len = val_len; |
| } |
| break; |
| case ASN_NULL: |
| vp->val_len = 0; |
| vp->val.string = NULL; |
| break; |
| case ASN_OBJECT_ID: |
| if ('\n' == buf[strlen(buf) - 1]) |
| buf[strlen(buf) - 1] = '\0'; |
| else { |
| oid value[MAX_OID_LEN]; |
| vp->val_len = MAX_OID_LEN; |
| if (0 == read_objid(buf, value, &vp->val_len)) { |
| printf("Unrecognised OID value\n"); |
| goto getValue; |
| } |
| vp->val.objid = snmp_duplicate_objid(value, vp->val_len); |
| vp->val_len *= sizeof(oid); |
| } |
| break; |
| case ASN_TIMETICKS: |
| vp->val.integer = (long *) malloc(sizeof(long)); |
| *(vp->val.integer) = atoi(buf); |
| vp->val_len = sizeof(long); |
| break; |
| case ASN_IPADDRESS: |
| vp->val.integer = (long *) malloc(sizeof(long)); |
| *(vp->val.integer) = inet_addr(buf); |
| vp->val_len = sizeof(long); |
| break; |
| default: |
| printf("Internal error\n"); |
| break; |
| } |
| } else { /* some form of get message */ |
| vp->type = ASN_NULL; |
| vp->val_len = 0; |
| } |
| return 1; |
| } |