diff options
author | Hideki Yamane <henrich@debian.org> | 2014-03-30 19:38:48 +0900 |
---|---|---|
committer | Hideki Yamane <henrich@debian.org> | 2014-03-30 19:38:48 +0900 |
commit | 7769a9595c3da9a35f31b42451b1f6c3ed4004fa (patch) | |
tree | 009bf8fd68af6bb1129e07dd8c1ed205010d81f8 /apps/snmpwalk.c | |
parent | 2e7891b0311204e0ecd5dc4a4334df01f3a6a1b4 (diff) | |
download | pkg-net-snmp-7769a9595c3da9a35f31b42451b1f6c3ed4004fa.tar.gz |
Imported Upstream version 5.7.2~dfsg
Diffstat (limited to 'apps/snmpwalk.c')
-rw-r--r-- | apps/snmpwalk.c | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/apps/snmpwalk.c b/apps/snmpwalk.c new file mode 100644 index 0000000..659d7de --- /dev/null +++ b/apps/snmpwalk.c @@ -0,0 +1,432 @@ +/* + * snmpwalk.c - send snmp GETNEXT requests to a network entity, walking a + * subtree. + * + */ +/********************************************************************** + 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 +#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 +#include <stdio.h> +#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> + +#define NETSNMP_DS_WALK_INCLUDE_REQUESTED 1 +#define NETSNMP_DS_WALK_PRINT_STATISTICS 2 +#define NETSNMP_DS_WALK_DONT_CHECK_LEXICOGRAPHIC 3 +#define NETSNMP_DS_WALK_TIME_RESULTS 4 +#define NETSNMP_DS_WALK_DONT_GET_REQUESTED 5 +#define NETSNMP_DS_WALK_TIME_RESULTS_SINGLE 6 + +oid objid_mib[] = { 1, 3, 6, 1, 2, 1 }; +int numprinted = 0; + +char *end_name = NULL; + +void +usage(void) +{ + fprintf(stderr, "USAGE: snmpwalk "); + snmp_parse_args_usage(stderr); + fprintf(stderr, " [OID]\n\n"); + snmp_parse_args_descriptions(stderr); + fprintf(stderr, + " -C APPOPTS\t\tSet various application specific behaviours:\n"); + fprintf(stderr, "\t\t\t p: print the number of variables found\n"); + fprintf(stderr, "\t\t\t i: include given OID in the search range\n"); + fprintf(stderr, "\t\t\t I: don't include the given OID, even if no results are returned\n"); + fprintf(stderr, + "\t\t\t c: do not check returned OIDs are increasing\n"); + fprintf(stderr, + "\t\t\t t: Display wall-clock time to complete the walk\n"); + fprintf(stderr, + "\t\t\t T: Display wall-clock time to complete each request\n"); + fprintf(stderr, "\t\t\t E {OID}: End the walk at the specified OID\n"); +} + +void +snmp_get_and_print(netsnmp_session * ss, oid * theoid, size_t theoid_len) +{ + netsnmp_pdu *pdu, *response; + netsnmp_variable_list *vars; + int status; + + pdu = snmp_pdu_create(SNMP_MSG_GET); + snmp_add_null_var(pdu, theoid, theoid_len); + + status = snmp_synch_response(ss, pdu, &response); + if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) { + for (vars = response->variables; vars; vars = vars->next_variable) { + numprinted++; + print_variable(vars->name, vars->name_length, vars); + } + } + if (response) { + snmp_free_pdu(response); + } +} + +static void +optProc(int argc, char *const *argv, int opt) +{ + switch (opt) { + case 'C': + while (*optarg) { + switch (*optarg++) { + case 'i': + netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_INCLUDE_REQUESTED); + break; + + case 'I': + netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_DONT_GET_REQUESTED); + break; + + case 'p': + netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_PRINT_STATISTICS); + break; + + case 'c': + netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_DONT_CHECK_LEXICOGRAPHIC); + break; + + case 't': + netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_TIME_RESULTS); + break; + + case 'E': + end_name = argv[optind++]; + break; + + case 'T': + netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_TIME_RESULTS_SINGLE); + break; + + default: + fprintf(stderr, "Unknown flag passed to -C: %c\n", + optarg[-1]); + exit(1); + } + } + break; + } +} + +int +main(int argc, char *argv[]) +{ + netsnmp_session session, *ss; + netsnmp_pdu *pdu, *response; + netsnmp_variable_list *vars; + int arg; + oid name[MAX_OID_LEN]; + size_t name_length; + oid root[MAX_OID_LEN]; + size_t rootlen; + oid end_oid[MAX_OID_LEN]; + size_t end_len = 0; + int count; + int running; + int status = STAT_ERROR; + int check; + int exitval = 0; + struct timeval tv1, tv2, tv_a, tv_b; + + netsnmp_ds_register_config(ASN_BOOLEAN, "snmpwalk", "includeRequested", + NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_INCLUDE_REQUESTED); + + netsnmp_ds_register_config(ASN_BOOLEAN, "snmpwalk", "excludeRequested", + NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_DONT_GET_REQUESTED); + + netsnmp_ds_register_config(ASN_BOOLEAN, "snmpwalk", "printStatistics", + NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_PRINT_STATISTICS); + + netsnmp_ds_register_config(ASN_BOOLEAN, "snmpwalk", "dontCheckOrdering", + NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_DONT_CHECK_LEXICOGRAPHIC); + + netsnmp_ds_register_config(ASN_BOOLEAN, "snmpwalk", "timeResults", + NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_TIME_RESULTS); + + netsnmp_ds_register_config(ASN_BOOLEAN, "snmpwalk", "timeResultsSingle", + NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_TIME_RESULTS_SINGLE); + + /* + * get the common command line arguments + */ + switch (arg = snmp_parse_args(argc, argv, &session, "C:", optProc)) { + 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; + } + + /* + * get the initial object and subtree + */ + if (arg < argc) { + /* + * specified on the command line + */ + rootlen = MAX_OID_LEN; + if (snmp_parse_oid(argv[arg], root, &rootlen) == NULL) { + snmp_perror(argv[arg]); + exit(1); + } + } else { + /* + * use default value + */ + memmove(root, objid_mib, sizeof(objid_mib)); + rootlen = sizeof(objid_mib) / sizeof(oid); + } + + /* + * If we've been given an explicit end point, + * then convert this to an OID, otherwise + * move to the next sibling of the start. + */ + if ( end_name ) { + end_len = MAX_OID_LEN; + if (snmp_parse_oid(end_name, end_oid, &end_len) == NULL) { + snmp_perror(end_name); + exit(1); + } + } else { + memmove(end_oid, root, rootlen*sizeof(oid)); + end_len = rootlen; + end_oid[end_len-1]++; + } + + 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("snmpwalk", &session); + SOCK_CLEANUP; + exit(1); + } + + /* + * get first object to start walk + */ + memmove(name, root, rootlen * sizeof(oid)); + name_length = rootlen; + + running = 1; + + check = + !netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_DONT_CHECK_LEXICOGRAPHIC); + if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_WALK_INCLUDE_REQUESTED)) { + snmp_get_and_print(ss, root, rootlen); + } + + if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_TIME_RESULTS)) + netsnmp_get_monotonic_clock(&tv1); + while (running) { + /* + * create PDU for GETNEXT request and add object name to request + */ + pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); + snmp_add_null_var(pdu, name, name_length); + + /* + * do the request + */ + if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_WALK_TIME_RESULTS_SINGLE)) + netsnmp_get_monotonic_clock(&tv_a); + status = snmp_synch_response(ss, pdu, &response); + if (status == STAT_SUCCESS) { + if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_WALK_TIME_RESULTS_SINGLE)) + netsnmp_get_monotonic_clock(&tv_b); + if (response->errstat == SNMP_ERR_NOERROR) { + /* + * check resulting variables + */ + for (vars = response->variables; vars; + vars = vars->next_variable) { + if (snmp_oid_compare(end_oid, end_len, + vars->name, vars->name_length) <= 0) { + /* + * not part of this subtree + */ + running = 0; + continue; + } + numprinted++; + if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_WALK_TIME_RESULTS_SINGLE)) + fprintf(stdout, "%f s: ", + (double) (tv_b.tv_usec - tv_a.tv_usec)/1000000 + + (double) (tv_b.tv_sec - tv_a.tv_sec)); + print_variable(vars->name, vars->name_length, vars); + if ((vars->type != SNMP_ENDOFMIBVIEW) && + (vars->type != SNMP_NOSUCHOBJECT) && + (vars->type != SNMP_NOSUCHINSTANCE)) { + /* + * not an exception value + */ + if (check + && snmp_oid_compare(name, name_length, + vars->name, + vars->name_length) >= 0) { + fprintf(stderr, "Error: OID not increasing: "); + fprint_objid(stderr, name, name_length); + fprintf(stderr, " >= "); + fprint_objid(stderr, vars->name, + vars->name_length); + fprintf(stderr, "\n"); + running = 0; + exitval = 1; + } + memmove((char *) name, (char *) vars->name, + vars->name_length * sizeof(oid)); + name_length = vars->name_length; + } else + /* + * an exception value, so stop + */ + running = 0; + } + } else { + /* + * error in response, print it + */ + running = 0; + if (response->errstat == SNMP_ERR_NOSUCHNAME) { + printf("End of MIB\n"); + } else { + fprintf(stderr, "Error in packet.\nReason: %s\n", + snmp_errstring(response->errstat)); + if (response->errindex != 0) { + fprintf(stderr, "Failed object: "); + for (count = 1, vars = response->variables; + vars && count != response->errindex; + vars = vars->next_variable, count++) + /*EMPTY*/; + if (vars) + fprint_objid(stderr, vars->name, + vars->name_length); + fprintf(stderr, "\n"); + } + exitval = 2; + } + } + } else if (status == STAT_TIMEOUT) { + fprintf(stderr, "Timeout: No Response from %s\n", + session.peername); + running = 0; + exitval = 1; + } else { /* status == STAT_ERROR */ + snmp_sess_perror("snmpwalk", ss); + running = 0; + exitval = 1; + } + if (response) + snmp_free_pdu(response); + } + if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_TIME_RESULTS)) + netsnmp_get_monotonic_clock(&tv2); + + if (numprinted == 0 && status == STAT_SUCCESS) { + /* + * no printed successful results, which may mean we were + * pointed at an only existing instance. Attempt a GET, just + * for get measure. + */ + if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_WALK_DONT_GET_REQUESTED)) { + snmp_get_and_print(ss, root, rootlen); + } + } + snmp_close(ss); + + if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_PRINT_STATISTICS)) { + printf("Variables found: %d\n", numprinted); + } + if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_WALK_TIME_RESULTS)) { + fprintf (stderr, "Total traversal time = %f seconds\n", + (double) (tv2.tv_usec - tv1.tv_usec)/1000000 + + (double) (tv2.tv_sec - tv1.tv_sec)); + } + + SOCK_CLEANUP; + return exitval; +} |