/* * Return code: * 0 - End Of Table * -1 - Error * -2 - Last change changed - again * +1 - ok, continue */ static int table_check_response(struct tabwork *work, const struct snmp_pdu *resp) { const struct snmp_value *b; struct entry *e; if (resp->error_status != SNMP_ERR_NOERROR) { if (snmp_client.version == SNMP_V1 && resp->error_status == SNMP_ERR_NOSUCHNAME && resp->error_index == (work->descr->last_change.len == 0) ? 1 : 2) /* EOT */ return (0); /* Error */ seterr(&snmp_client, "error fetching table: status=%d index=%d", resp->error_status, resp->error_index); return (-1); } for (b = resp->bindings; b < resp->bindings + resp->nbindings; b++) { if (work->descr->last_change.len != 0 && b == resp->bindings) { if (!asn_is_suboid(&work->descr->last_change, &b->var) || b->var.len != work->descr->last_change.len + 1 || b->var.subs[work->descr->last_change.len] != 0) { seterr(&snmp_client, "last_change: bad response"); return (-1); } if (b->syntax != SNMP_SYNTAX_TIMETICKS) { seterr(&snmp_client, "last_change: bad syntax %u", b->syntax); return (-1); } if (work->first) { work->last_change = b->v.uint32; work->first = 0; } else if (work->last_change != b->v.uint32) { if (++work->iter >= work->descr->max_iter) { seterr(&snmp_client, "max iteration count exceeded"); return (-1); } table_free(work, 1); return (-2); } continue; } if (!asn_is_suboid(&work->descr->table, &b->var) || b->syntax == SNMP_SYNTAX_ENDOFMIBVIEW) return (0); if ((e = table_find(work, &b->var)) == NULL) return (-1); if (table_value(work->descr, e, b)) return (-1); } return (+1); }
static void query_next_response (int request, int code, struct snmp_value *value, void *arg) { rb_item *item = arg; asn_subid_t subid; int matched; /* * Called when we get the next OID in a table */ ASSERT (request == item->query_request); ASSERT (!item->field_request); /* Mark this item as done */ item->query_request = 0; if (code == SNMP_ERR_NOERROR) { ASSERT (value); /* Convert these result codes into 'not found' */ switch (value->syntax) { case SNMP_SYNTAX_NOSUCHOBJECT: case SNMP_SYNTAX_NOSUCHINSTANCE: case SNMP_SYNTAX_ENDOFMIBVIEW: code = SNMP_ERR_NOSUCHNAME; break; /* * Make sure that we haven't gone past the end. For it to * be in the table it must be exactly one longer (the table index) * and otherwise identical. */ default: if (item->query_oid.len + 1 != value->var.len || !asn_is_suboid (&item->query_oid, &value->var)) code = SNMP_ERR_NOSUCHNAME; break; }; } if (code == SNMP_ERR_NOSUCHNAME) log_debug ("query couldn't find table index that matches: %s", item->query_match ? item->query_match : "[null]"); /* Problems communicating with the server, or not found */ if (code != SNMP_ERR_NOERROR) { memset (&item->query_last, 0, sizeof (item->query_last)); complete_requests (item, code); return; } /* Save away the last OID we've seen */ item->query_last = value->var; item->query_searched = 1; ASSERT (value); /* Match the query value received */ if (item->query_match) matched = snmp_engine_match (value, item->query_match); /* When query match is null, anything matches */ else matched = 1; item->query_matched = matched; item->vtype = VALUE_UNSET; if (matched) { /* Do a query for the field value with this sub id */ subid = value->var.subs[value->var.len - 1]; query_value_request (item, subid); } else { /* Look for the next table index */ query_search_request (item); } }
/* * Do a 'snmp walk' - according to command line options request for values lexicographically * subsequent and subrooted at a common node. Send a GetNext PDU requesting the value for each * next variable and print the responce. Stop when a Responce PDU is received that contains * the value of a variable not subrooted at the variable the walk started. */ int main(int argc, char ** argv) { struct snmp_toolinfo *tool; struct snmp_client *client_context; struct asn_oid root; /* keep the inital oid */ struct snmp_pdu pdu_to_send, pdu_to_recv; int oid, opt_num, outputs; tool = snmptool_init(helptxt); client_context = tool->client; if ((opt_num = snmpwalk_parse_options(tool, argc, argv)) < 0) { snmp_tool_freeall(tool); exit(0); } if (snmp_import_all(tool) < 0) { snmp_tool_freeall(tool); exit(0); } oid = argc - opt_num - 1; switch (oid) { case 0: if (snmp_object_add(tool, snmpwalk_add_default, NULL) < 0) { snmp_tool_freeall(tool); errx(1, "Error setting default tree OID to walk"); } break; case 1: /* last command line argument will always be the OID to start the walk from */ if ((snmp_object_add(tool, snmpwalk_parse_oid, argv[argc - 1])) < 0) { snmp_tool_freeall(tool); exit(1); } break; default: snmp_tool_freeall(tool); errx(1, "Only one OID allowed"); } snmp_pdu_create(client_context, &pdu_to_send, SNMP_PDU_GETNEXT); if (snmp_pdu_add_bindings(tool, (snmp_verify_vbind_f) NULL, snmpwalk_add_vbind, &pdu_to_send) < 0) { snmp_tool_freeall(tool); exit(1); } if (snmp_open(client_context, NULL, NULL, NULL, NULL)) { snmp_tool_freeall(tool); err(1, "Failed to open snmp session"); } /* remember the root where the walk started from */ memset(&root, 0 ,sizeof(struct asn_oid)); asn_append_oid(&root, &(pdu_to_send.bindings[0].var)); outputs = 0; while (snmp_dialog(client_context, &pdu_to_send, &pdu_to_recv) >= 0) { if ((snmp_parse_resp(client_context, &pdu_to_recv, &pdu_to_send)) < 0) { snmp_output_err_resp(tool, &pdu_to_recv); snmp_pdu_free(&pdu_to_recv); outputs = -1; break; } if (!(asn_is_suboid(&root, &(pdu_to_recv.bindings[0].var)))) { snmp_pdu_free(&pdu_to_recv); break; } snmp_output_resp(tool, &pdu_to_recv); outputs++; snmp_pdu_free(&pdu_to_recv); snmpwalk_nextpdu_create(client_context, SNMP_PDU_GETNEXT, &(pdu_to_recv.bindings[0].var), &pdu_to_send); } /* Just a case our root was a leaf */ if (outputs == 0) { snmpwalk_nextpdu_create(client_context, SNMP_PDU_GET, &root, &pdu_to_send); if (snmp_dialog(client_context, &pdu_to_send, &pdu_to_recv) == SNMP_CODE_OK /* 0 */) { if(snmp_parse_resp(client_context, &pdu_to_recv,&pdu_to_send) < 0) snmp_output_err_resp(tool, &pdu_to_recv); else snmp_output_resp(tool, &(pdu_to_recv)); snmp_pdu_free(&pdu_to_recv); } else err(1, "Snmp dialog"); } snmp_tool_freeall(tool); exit(0); }