2 * Copyright (c) 2005-2006 The FreeBSD Project
5 * Author: Shteryana Shopova <syrinx@FreeBSD.org>
7 * Redistribution of this software and documentation and use in source and
8 * binary forms, with or without modification, are permitted provided that
9 * the following conditions are met:
11 * 1. Redistributions of source code or documentation must retain the above
12 * copyright notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * Bsnmpget and bsnmpwalk are simple tools for querying SNMP agents,
30 * bsnmpset can be used to set MIB objects in an agent.
35 #include <sys/queue.h>
36 #include <sys/types.h>
49 #include <bsnmp/asn1.h>
50 #include <bsnmp/snmp.h>
51 #include <bsnmp/snmpclient.h>
53 #include "bsnmptools.h"
55 static const char *program_name = NULL;
56 static enum program_e {
62 /* *****************************************************************************
63 * Common bsnmptools functions.
70 "%s %s [-A options] [-b buffersize] [-C options] [-I options]\n"
71 "\t[-i filelist] [-l filename]%s [-o output] [-P options]\n"
72 "\t%s[-r retries] [-s [trans::][community@][server][:port]]\n"
73 "\t[-t timeout] [-U options] [-v version]%s\n",
75 (program == BSNMPGET) ? "[-aDdehnK]" :
76 (program == BSNMPWALK) ? "[-dhnK]" :
77 (program == BSNMPSET) ? "[-adehnK]" :
79 (program == BSNMPGET || program == BSNMPWALK) ?
80 " [-M max-repetitions] [-N non-repeaters]" : "",
81 (program == BSNMPGET || program == BSNMPWALK) ? "[-p pdu] " : "",
82 (program == BSNMPGET) ? " OID [OID ...]" :
83 (program == BSNMPWALK || program == BSNMPSET) ? " [OID ...]" :
89 parse_max_repetitions(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
93 assert(opt_arg != NULL);
95 v = strtoul(opt_arg, (void *) NULL, 10);
97 if (v > SNMP_MAX_BINDINGS) {
98 warnx("Max repetitions value greater than %d maximum allowed.",
103 SET_MAXREP(snmptoolctx, v);
108 parse_non_repeaters(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
112 assert(opt_arg != NULL);
114 v = strtoul(opt_arg, (void *) NULL, 10);
116 if (v > SNMP_MAX_BINDINGS) {
117 warnx("Non repeaters value greater than %d maximum allowed.",
122 SET_NONREP(snmptoolctx, v);
127 parse_pdu_type(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
129 assert(opt_arg != NULL);
131 if (strcasecmp(opt_arg, "getbulk") == 0)
132 SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETBULK);
133 else if (strcasecmp(opt_arg, "getnext") == 0)
134 SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETNEXT);
135 else if (strcasecmp(opt_arg, "get") == 0)
136 SET_PDUTYPE(snmptoolctx, SNMP_PDU_GET);
138 warnx("PDU type '%s' not supported.", opt_arg);
146 snmptool_parse_options(struct snmp_toolinfo *snmptoolctx, int argc, char **argv)
148 int32_t count, optnum = 0;
154 opts = "dhnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:";
157 opts = "aDdehnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:";
160 opts = "adehnKA:b:C:I:i:l:o:P:r:s:t:U:v:";
166 while ((ch = getopt(argc, argv, opts)) != EOF) {
169 count = parse_authentication(snmptoolctx, optarg);
172 count = parse_skip_access(snmptoolctx);
175 count = parse_buflen(optarg);
178 count = parse_discovery(snmptoolctx);
181 count = parse_debug();
184 count = parse_errors(snmptoolctx);
190 count = parse_context(snmptoolctx, optarg);
193 count = parse_include(snmptoolctx, optarg);
196 count = parse_file(snmptoolctx, optarg);
199 count = parse_local_key(snmptoolctx);
202 count = parse_local_path(optarg);
205 count = parse_max_repetitions(snmptoolctx, optarg);
208 count = parse_non_repeaters(snmptoolctx, optarg);
211 count = parse_num_oids(snmptoolctx);
214 count = parse_output(snmptoolctx, optarg);
217 count = parse_privacy(snmptoolctx, optarg);
220 count = parse_pdu_type(snmptoolctx, optarg);
223 count = parse_retry(optarg);
226 count = parse_server(optarg);
229 count = parse_timeout(optarg);
232 count = parse_user_security(snmptoolctx, optarg);
235 count = parse_version(optarg);
251 * Read user input OID - one of following formats:
252 * 1) 1.2.1.1.2.1.0 - that is if option numeric was given;
253 * 2) string - in such case append .0 to the asn_oid subs;
254 * 3) string.1 - no additional processing required in such case.
257 snmptools_parse_stroid(struct snmp_toolinfo *snmptoolctx,
258 struct snmp_object *obj, char *argv)
260 char string[MAXSTR], *str;
262 struct asn_oid in_oid;
269 while (isalpha(*str) || *str == '_' || (i != 0 && isdigit(*str))) {
274 if (i <= 0 || i >= MAXSTR)
277 memset(&in_oid, 0, sizeof(struct asn_oid));
278 if ((str = snmp_parse_suboid((argv + i), &in_oid)) == NULL) {
279 warnx("Invalid OID - %s", argv);
283 strlcpy(string, argv, i + 1);
284 if (snmp_lookup_oidall(snmptoolctx, obj, string) < 0) {
285 warnx("No entry for %s in mapping lists", string);
289 /* If OID given on command line append it. */
291 asn_append_oid(&(obj->val.var), &in_oid);
292 else if (*str == '[') {
293 if ((str = snmp_parse_index(snmptoolctx, str + 1, obj)) == NULL)
295 } else if (obj->val.syntax > 0 && GET_PDUTYPE(snmptoolctx) ==
297 if (snmp_suboid_append(&(obj->val.var), (asn_subid_t) 0) < 0)
305 snmptools_parse_oid(struct snmp_toolinfo *snmptoolctx,
306 struct snmp_object *obj, char *argv)
311 if (ISSET_NUMERIC(snmptoolctx)) {
312 if (snmp_parse_numoid(argv, &(obj->val.var)) < 0)
315 if (snmptools_parse_stroid(snmptoolctx, obj, argv) == NULL &&
316 snmp_parse_numoid(argv, &(obj->val.var)) < 0)
324 snmptool_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj)
329 asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var));
332 return (pdu->nbindings);
335 /* *****************************************************************************
336 * bsnmpget private functions.
339 snmpget_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
340 struct snmp_object *obj)
342 if (pdu->version == SNMP_V1 && obj->val.syntax ==
343 SNMP_SYNTAX_COUNTER64) {
344 warnx("64-bit counters are not supported in SNMPv1 PDU");
348 if (ISSET_NUMERIC(snmptoolctx) || pdu->type == SNMP_PDU_GETNEXT ||
349 pdu->type == SNMP_PDU_GETBULK)
352 if (pdu->type == SNMP_PDU_GET && obj->val.syntax == SNMP_SYNTAX_NULL) {
353 warnx("Only leaf object values can be added to GET PDU");
361 * In case of a getbulk PDU, the error_status and error_index fields are used by
362 * libbsnmp to hold the values of the non-repeaters and max-repetitions fields
363 * that are present only in the getbulk - so before sending the PDU make sure
364 * these have correct values as well.
367 snmpget_fix_getbulk(struct snmp_pdu *pdu, uint32_t max_rep, uint32_t non_rep)
371 if (pdu->nbindings < non_rep)
372 pdu->error_status = pdu->nbindings;
374 pdu->error_status = non_rep;
377 pdu->error_index = max_rep;
379 pdu->error_index = 1;
383 snmptool_get(struct snmp_toolinfo *snmptoolctx)
385 struct snmp_pdu req, resp;
387 snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx));
389 while ((snmp_pdu_add_bindings(snmptoolctx, snmpget_verify_vbind,
390 snmptool_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) {
392 if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK)
393 snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
394 GET_NONREP(snmptoolctx));
396 if (snmp_dialog(&req, &resp) == -1) {
397 warnx("Snmp dialog - %s", strerror(errno));
401 if (snmp_parse_resp(&resp, &req) >= 0) {
402 snmp_output_resp(snmptoolctx, &resp, NULL);
406 snmp_output_err_resp(snmptoolctx, &resp);
407 if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK ||
408 !ISSET_RETRY(snmptoolctx))
412 * Loop through the object list and set object->error to the
413 * varbinding that caused the error.
415 if (snmp_object_seterror(snmptoolctx,
416 &(resp.bindings[resp.error_index - 1]),
417 resp.error_status) <= 0)
420 fprintf(stderr, "Retrying...\n");
421 snmp_pdu_free(&resp);
422 snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx));
425 snmp_pdu_free(&resp);
431 /* *****************************************************************************
432 * bsnmpwalk private functions.
434 /* The default tree to walk. */
435 static const struct asn_oid snmp_mibII_OID = {
436 6 , { 1, 3, 6, 1, 2, 1 }
440 snmpwalk_add_default(struct snmp_toolinfo *snmptoolctx __unused,
441 struct snmp_object *obj, char *string __unused)
443 asn_append_oid(&(obj->val.var), &snmp_mibII_OID);
448 * Prepare the next GetNext/Get PDU to send.
451 snmpwalk_nextpdu_create(uint32_t op, struct asn_oid *var, struct snmp_pdu *pdu)
453 snmp_pdu_create(pdu, op);
454 asn_append_oid(&(pdu->bindings[0].var), var);
459 snmptool_walk(struct snmp_toolinfo *snmptoolctx)
461 struct snmp_pdu req, resp;
462 struct asn_oid root; /* Keep the initial oid. */
466 if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK)
467 op = SNMP_PDU_GETBULK;
469 op = SNMP_PDU_GETNEXT;
471 snmp_pdu_create(&req, op);
473 while ((rc = snmp_pdu_add_bindings(snmptoolctx, NULL,
474 snmptool_add_vbind, &req, 1)) > 0) {
476 /* Remember the root where the walk started from. */
477 memset(&root, 0, sizeof(struct asn_oid));
478 asn_append_oid(&root, &(req.bindings[0].var));
480 if (op == SNMP_PDU_GETBULK)
481 snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
482 GET_NONREP(snmptoolctx));
485 while (snmp_dialog(&req, &resp) >= 0) {
486 if ((snmp_parse_resp(&resp, &req)) < 0) {
487 snmp_output_err_resp(snmptoolctx, &resp);
488 snmp_pdu_free(&resp);
493 rc = snmp_output_resp(snmptoolctx, &resp, &root);
495 snmp_pdu_free(&resp);
501 snmp_pdu_free(&resp);
503 if (rc < resp.nbindings)
506 snmpwalk_nextpdu_create(op,
507 &(resp.bindings[resp.nbindings - 1].var), &req);
508 if (op == SNMP_PDU_GETBULK)
509 snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
510 GET_NONREP(snmptoolctx));
513 /* Just in case our root was a leaf. */
515 snmpwalk_nextpdu_create(SNMP_PDU_GET, &root, &req);
516 if (snmp_dialog(&req, &resp) == SNMP_CODE_OK) {
517 if (snmp_parse_resp(&resp,&req) < 0)
518 snmp_output_err_resp(snmptoolctx, &resp);
520 snmp_output_resp(snmptoolctx, &(resp), NULL);
522 snmp_pdu_free(&resp);
524 warnx("Snmp dialog - %s", strerror(errno));
527 if (snmp_object_remove(snmptoolctx, &root) < 0) {
528 warnx("snmp_object_remove");
532 snmp_pdu_create(&req, op);
541 /* *****************************************************************************
542 * bsnmpset private functions.
546 parse_oid_numeric(struct snmp_value *value, char *val)
555 suboid = strtoul(val, &endptr, 10);
557 warnx("Value %s not supported - %s", val,
563 if ((asn_subid_t) suboid > ASN_MAXID) {
564 warnx("Suboid %u > ASN_MAXID", suboid);
567 if (snmp_suboid_append(&(value->v.oid), suboid) < 0)
570 } while (*endptr == '.');
573 warnx("OID value %s not supported", val);
575 value->syntax = SNMP_SYNTAX_OID;
580 * Allow OID leaf in both forms:
581 * 1) 1.3.6.1.2... -> in such case call directly the function reading raw OIDs;
582 * 2) begemotSnmpdAgentFreeBSD -> lookup the ASN OID corresponding to that.
585 parse_oid_string(struct snmp_toolinfo *snmptoolctx,
586 struct snmp_value *value, char *string)
588 struct snmp_object obj;
590 if (isdigit(string[0]))
591 return (parse_oid_numeric(value, string));
593 memset(&obj, 0, sizeof(struct snmp_object));
594 if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {
595 warnx("Unknown OID enum string - %s", string);
599 asn_append_oid(&(value->v.oid), &(obj.val.var));
604 parse_ip(struct snmp_value * value, char * val)
611 for (i = 0; i < 4; i++) {
612 v = strtoul(str, &endptr, 10);
615 if (*endptr != '.' && *endptr != '\0' && i != 3)
618 value->v.ipaddress[i] = (uint8_t) v;
621 value->syntax = SNMP_SYNTAX_IPADDRESS;
626 parse_int(struct snmp_value *value, char *val)
629 int32_t v, saved_errno;
634 v = strtol(val, &endptr, 10);
637 warnx("Value %s not supported - %s", val, strerror(errno));
642 value->syntax = SNMP_SYNTAX_INTEGER;
643 value->v.integer = v;
650 parse_int_string(struct snmp_object *object, char *val)
655 return ((parse_int(&(object->val), val)));
657 if (object->info == NULL) {
658 warnx("Unknown enumerated integer type - %s", val);
661 if ((v = enum_number_lookup(object->info->snmp_enum, val)) < 0)
662 warnx("Unknown enumerated integer type - %s", val);
664 object->val.v.integer = v;
669 * Here syntax may be one of SNMP_SYNTAX_COUNTER, SNMP_SYNTAX_GAUGE,
670 * SNMP_SYNTAX_TIMETICKS.
673 parse_uint(struct snmp_value *value, char *val)
682 v = strtoul(val, &endptr, 10);
685 warnx("Value %s not supported - %s", val, strerror(errno));
697 parse_ticks(struct snmp_value *value, char *val)
699 if (parse_uint(value, val) < 0)
702 value->syntax = SNMP_SYNTAX_TIMETICKS;
707 parse_gauge(struct snmp_value *value, char *val)
709 if (parse_uint(value, val) < 0)
712 value->syntax = SNMP_SYNTAX_GAUGE;
717 parse_counter(struct snmp_value *value, char *val)
719 if (parse_uint(value, val) < 0)
722 value->syntax = SNMP_SYNTAX_COUNTER;
727 parse_uint64(struct snmp_value *value, char *val)
736 v = strtoull(val, &endptr, 10);
739 warnx("Value %s not supported - %s", val, strerror(errno));
744 value->syntax = SNMP_SYNTAX_COUNTER64;
745 value->v.counter64 = v;
752 parse_syntax_val(struct snmp_value *value, enum snmp_syntax syntax, char *val)
755 case SNMP_SYNTAX_INTEGER:
756 return (parse_int(value, val));
757 case SNMP_SYNTAX_IPADDRESS:
758 return (parse_ip(value, val));
759 case SNMP_SYNTAX_COUNTER:
760 return (parse_counter(value, val));
761 case SNMP_SYNTAX_GAUGE:
762 return (parse_gauge(value, val));
763 case SNMP_SYNTAX_TIMETICKS:
764 return (parse_ticks(value, val));
765 case SNMP_SYNTAX_COUNTER64:
766 return (parse_uint64(value, val));
767 case SNMP_SYNTAX_OCTETSTRING:
768 return (snmp_tc2oct(SNMP_STRING, value, val));
769 case SNMP_SYNTAX_OID:
770 return (parse_oid_numeric(value, val));
780 * Parse a command line argument of type OID=syntax:value and fill in whatever
781 * fields can be derived from the input into snmp_value structure. Reads numeric
785 parse_pair_numoid_val(char *str, struct snmp_value *snmp_val)
789 enum snmp_syntax syntax;
790 char oid_str[ASN_OIDSTRLEN];
793 for (cnt = 0; cnt < ASN_OIDSTRLEN; cnt++)
797 if (cnt >= ASN_OIDSTRLEN) {
798 warnx("OID too long - %s", str);
801 strlcpy(oid_str, ptr, (size_t) (cnt + 1));
804 for (cnt = 0; cnt < MAX_CMD_SYNTAX_LEN; cnt++)
808 if (cnt >= MAX_CMD_SYNTAX_LEN) {
809 warnx("Unknown syntax in OID - %s", str);
813 if ((syntax = parse_syntax(ptr)) <= SNMP_SYNTAX_NULL) {
814 warnx("Unknown syntax in OID - %s", ptr);
819 for (cnt = 0; cnt < MAX_OCTSTRING_LEN; cnt++)
820 if (ptr[cnt] == '\0')
823 if (ptr[cnt] != '\0') {
824 warnx("Value string too long - %s",ptr);
829 * Here try parsing the OIDs and syntaxes and then check values - have
830 * to know syntax to check value boundaries.
832 if (snmp_parse_numoid(oid_str, &(snmp_val->var)) < 0) {
833 warnx("Error parsing OID %s",oid_str);
837 if (parse_syntax_val(snmp_val, syntax, ptr) < 0)
843 /* XXX-BZ aruments should be swapped. */
845 parse_syntax_strval(struct snmp_toolinfo *snmptoolctx, char *str,
846 struct snmp_object *object)
849 enum snmp_syntax syn;
852 * Syntax string here not required - still may be present.
855 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {
856 for (len = 0 ; *(str + len) != ':'; len++) {
857 if (*(str + len) == '\0') {
858 warnx("Syntax missing in value - %s", str);
862 if ((syn = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {
863 warnx("Unknown syntax in - %s", str);
866 if (syn != object->val.syntax) {
867 if (!ISSET_ERRIGNORE(snmptoolctx)) {
868 warnx("Bad syntax in - %s", str);
871 object->val.syntax = syn;
877 switch (object->val.syntax) {
878 case SNMP_SYNTAX_INTEGER:
879 return (parse_int_string(object, str + len));
880 case SNMP_SYNTAX_IPADDRESS:
881 return (parse_ip(&(object->val), str + len));
882 case SNMP_SYNTAX_COUNTER:
883 return (parse_counter(&(object->val), str + len));
884 case SNMP_SYNTAX_GAUGE:
885 return (parse_gauge(&(object->val), str + len));
886 case SNMP_SYNTAX_TIMETICKS:
887 return (parse_ticks(&(object->val), str + len));
888 case SNMP_SYNTAX_COUNTER64:
889 return (parse_uint64(&(object->val), str + len));
890 case SNMP_SYNTAX_OCTETSTRING:
891 return (snmp_tc2oct(object->info->tc, &(object->val),
893 case SNMP_SYNTAX_OID:
894 return (parse_oid_string(snmptoolctx, &(object->val),
905 parse_pair_stroid_val(struct snmp_toolinfo *snmptoolctx,
906 struct snmp_object *obj, char *argv)
910 if ((ptr = snmptools_parse_stroid(snmptoolctx, obj, argv)) == NULL)
914 warnx("Value to set expected after OID");
918 if (parse_syntax_strval(snmptoolctx, ptr + 1, obj) < 0)
926 snmpset_parse_oid(struct snmp_toolinfo *snmptoolctx,
927 struct snmp_object *obj, char *argv)
932 if (ISSET_NUMERIC(snmptoolctx)) {
933 if (parse_pair_numoid_val(argv, &(obj->val)) < 0)
936 if (parse_pair_stroid_val(snmptoolctx, obj, argv) < 0)
944 add_ip_syntax(struct snmp_value *dst, struct snmp_value *src)
948 dst->syntax = SNMP_SYNTAX_IPADDRESS;
949 for (i = 0; i < 4; i++)
950 dst->v.ipaddress[i] = src->v.ipaddress[i];
956 add_octstring_syntax(struct snmp_value *dst, struct snmp_value *src)
958 if (src->v.octetstring.len > ASN_MAXOCTETSTRING) {
959 warnx("OctetString len too big - %u",src->v.octetstring.len);
963 if ((dst->v.octetstring.octets = malloc(src->v.octetstring.len)) ==
965 syslog(LOG_ERR, "malloc() failed - %s", strerror(errno));
969 memcpy(dst->v.octetstring.octets, src->v.octetstring.octets,
970 src->v.octetstring.len);
971 dst->syntax = SNMP_SYNTAX_OCTETSTRING;
972 dst->v.octetstring.len = src->v.octetstring.len;
978 add_oid_syntax(struct snmp_value *dst, struct snmp_value *src)
980 asn_append_oid(&(dst->v.oid), &(src->v.oid));
981 dst->syntax = SNMP_SYNTAX_OID;
986 * Check syntax - if one of SNMP_SYNTAX_NULL, SNMP_SYNTAX_NOSUCHOBJECT,
987 * SNMP_SYNTAX_NOSUCHINSTANCE, SNMP_SYNTAX_ENDOFMIBVIEW or anything not known -
991 snmpset_add_value(struct snmp_value *dst, struct snmp_value *src)
993 if (dst == NULL || src == NULL)
996 switch (src->syntax) {
997 case SNMP_SYNTAX_INTEGER:
998 dst->v.integer = src->v.integer;
999 dst->syntax = SNMP_SYNTAX_INTEGER;
1001 case SNMP_SYNTAX_TIMETICKS:
1002 dst->v.uint32 = src->v.uint32;
1003 dst->syntax = SNMP_SYNTAX_TIMETICKS;
1005 case SNMP_SYNTAX_GAUGE:
1006 dst->v.uint32 = src->v.uint32;
1007 dst->syntax = SNMP_SYNTAX_GAUGE;
1009 case SNMP_SYNTAX_COUNTER:
1010 dst->v.uint32 = src->v.uint32;
1011 dst->syntax = SNMP_SYNTAX_COUNTER;
1013 case SNMP_SYNTAX_COUNTER64:
1014 dst->v.counter64 = src->v.counter64;
1015 dst->syntax = SNMP_SYNTAX_COUNTER64;
1017 case SNMP_SYNTAX_IPADDRESS:
1018 add_ip_syntax(dst, src);
1020 case SNMP_SYNTAX_OCTETSTRING:
1021 add_octstring_syntax(dst, src);
1023 case SNMP_SYNTAX_OID:
1024 add_oid_syntax(dst, src);
1027 warnx("Unknown syntax %d", src->syntax);
1035 snmpset_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
1036 struct snmp_object *obj)
1038 if (pdu->version == SNMP_V1 && obj->val.syntax ==
1039 SNMP_SYNTAX_COUNTER64) {
1040 warnx("64-bit counters are not supported in SNMPv1 PDU");
1044 if (ISSET_NUMERIC(snmptoolctx) || ISSET_ERRIGNORE(snmptoolctx))
1047 if (obj->info->access < SNMP_ACCESS_SET) {
1048 warnx("Object %s not accessible for set - try 'bsnmpset -a'",
1057 snmpset_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj)
1059 if (pdu->nbindings > SNMP_MAX_BINDINGS) {
1060 warnx("Too many OIDs for one PDU");
1067 if (snmpset_add_value(&(pdu->bindings[pdu->nbindings]), &(obj->val))
1071 asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var));
1074 return (pdu->nbindings);
1078 snmptool_set(struct snmp_toolinfo *snmptoolctx)
1080 struct snmp_pdu req, resp;
1082 snmp_pdu_create(&req, SNMP_PDU_SET);
1084 while ((snmp_pdu_add_bindings(snmptoolctx, snmpset_verify_vbind,
1085 snmpset_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) {
1086 if (snmp_dialog(&req, &resp)) {
1087 warnx("Snmp dialog - %s", strerror(errno));
1091 if (snmp_pdu_check(&req, &resp) > 0) {
1092 if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)
1093 snmp_output_resp(snmptoolctx, &resp, NULL);
1097 snmp_output_err_resp(snmptoolctx, &resp);
1098 if (!ISSET_RETRY(snmptoolctx))
1101 if (snmp_object_seterror(snmptoolctx,
1102 &(resp.bindings[resp.error_index - 1]),
1103 resp.error_status) <= 0)
1106 fprintf(stderr, "Retrying...\n");
1107 snmp_pdu_free(&req);
1108 snmp_pdu_free(&resp);
1109 snmp_pdu_create(&req, SNMP_PDU_SET);
1112 snmp_pdu_free(&resp);
1117 /* *****************************************************************************
1121 * According to command line options prepare SNMP Get | GetNext | GetBulk PDU.
1122 * Wait for a response and print it.
1125 * Do a 'snmp walk' - according to command line options request for values
1126 * lexicographically subsequent and subrooted at a common node. Send a GetNext
1127 * PDU requesting the value for each next variable and print the response. Stop
1128 * when a Response PDU is received that contains the value of a variable not
1129 * subrooted at the variable the walk started.
1132 main(int argc, char ** argv)
1134 struct snmp_toolinfo snmptoolctx;
1135 int32_t oid_cnt, last_oid, opt_num;
1138 /* Make sure program_name is set and valid. */
1140 program_name = "snmptool";
1142 program_name = strrchr(*argv, '/');
1143 if (program_name != NULL)
1146 program_name = *argv;
1149 if (program_name == NULL) {
1150 fprintf(stderr, "Error: No program name?\n");
1152 } else if (strcmp(program_name, "bsnmpget") == 0)
1154 else if (strcmp(program_name, "bsnmpwalk") == 0)
1155 program = BSNMPWALK;
1156 else if (strcmp(program_name, "bsnmpset") == 0)
1159 fprintf(stderr, "Unknown snmp tool name '%s'.\n", program_name);
1164 if (snmptool_init(&snmptoolctx) < 0)
1167 if ((opt_num = snmptool_parse_options(&snmptoolctx, argc, argv)) < 0) {
1168 snmp_tool_freeall(&snmptoolctx);
1169 /* On -h (help) exit without error. */
1176 oid_cnt = argc - opt_num - 1;
1180 if (!ISSET_EDISCOVER(&snmptoolctx) &&
1181 !ISSET_LOCALKEY(&snmptoolctx)) {
1182 fprintf(stderr, "No OID given.\n");
1184 snmp_tool_freeall(&snmptoolctx);
1190 if (snmp_object_add(&snmptoolctx, snmpwalk_add_default,
1193 "Error setting default subtree.\n");
1194 snmp_tool_freeall(&snmptoolctx);
1200 fprintf(stderr, "No OID given.\n");
1202 snmp_tool_freeall(&snmptoolctx);
1207 if (snmp_import_all(&snmptoolctx) < 0) {
1208 snmp_tool_freeall(&snmptoolctx);
1212 /* A simple sanity check - can not send GETBULK when using SNMPv1. */
1213 if (program == BSNMPGET && snmp_client.version == SNMP_V1 &&
1214 GET_PDUTYPE(&snmptoolctx) == SNMP_PDU_GETBULK) {
1215 fprintf(stderr, "Cannot send GETBULK PDU with SNMPv1.\n");
1216 snmp_tool_freeall(&snmptoolctx);
1220 for (last_oid = argc - 1; oid_cnt > 0; last_oid--, oid_cnt--) {
1221 if ((snmp_object_add(&snmptoolctx, (program == BSNMPSET) ?
1222 snmpset_parse_oid : snmptools_parse_oid,
1223 argv[last_oid])) < 0) {
1224 fprintf(stderr, "Error parsing OID string '%s'.\n",
1226 snmp_tool_freeall(&snmptoolctx);
1231 if (snmp_open(NULL, NULL, NULL, NULL)) {
1232 warnx("Failed to open snmp session: %s.", strerror(errno));
1233 snmp_tool_freeall(&snmptoolctx);
1237 if (snmp_client.version == SNMP_V3 && snmp_client.engine.engine_len == 0)
1238 SET_EDISCOVER(&snmptoolctx);
1240 if (ISSET_EDISCOVER(&snmptoolctx) &&
1241 snmp_discover_engine(snmptoolctx.passwd) < 0) {
1242 warnx("Unknown SNMP Engine ID: %s.", strerror(errno));
1247 if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE ||
1248 ISSET_EDISCOVER(&snmptoolctx))
1249 snmp_output_engine();
1251 if (snmp_client.version == SNMP_V3 && ISSET_LOCALKEY(&snmptoolctx) &&
1252 !ISSET_EDISCOVER(&snmptoolctx)) {
1253 if (snmp_passwd_to_keys(&snmp_client.user,
1254 snmptoolctx.passwd) != SNMP_CODE_OK ||
1255 snmp_get_local_keys(&snmp_client.user,
1256 snmp_client.engine.engine_id,
1257 snmp_client.engine.engine_len) != SNMP_CODE_OK) {
1258 warnx("Failed to get keys: %s.", strerror(errno));
1264 if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE ||
1265 ISSET_EDISCOVER(&snmptoolctx))
1268 if (ISSET_EDISCOVER(&snmptoolctx) && snmptoolctx.objects == 0)
1273 rc = snmptool_get(&snmptoolctx);
1276 rc = snmptool_walk(&snmptoolctx);
1279 rc = snmptool_set(&snmptoolctx);
1285 snmp_tool_freeall(&snmptoolctx);