On Thu, Sep 26, 2019 at 02:33:11PM +0200, Martijn van Duren wrote:
> On 9/26/19 9:54 AM, Martijn van Duren wrote:
> > Hello,
> >
> > I reckon this will be on of the last major additions.
> > Adding "snmp set" allows us to run snmpd's regress without installing
> > netsnmp. :-)
> >
> > Tested with snmpd's regress test.
> >
> > Majority of diff is moving oid/value parsing from snmp trap to a
> > separate function.
> >
> > OK?
> >
> > martijn@
few comments.
thanks.
> Index: snmpc.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/snmp/snmpc.c,v
> retrieving revision 1.11
> diff -u -p -r1.11 snmpc.c
> --- snmpc.c 18 Sep 2019 09:54:36 -0000 1.11
> +++ snmpc.c 26 Sep 2019 12:32:38 -0000
> @@ -666,19 +669,54 @@ snmpc_walk(int argc, char *argv[])
> }
>
> int
> +snmpc_set(int argc, char *argv[])
> +{
> + struct snmp_agent *agent;
> + struct ber_element *pdu, *varbind;
> + int errorstatus, errorindex;
> + int class;
> + unsigned type;
> +
> + if (argc < 4)
> + usage();
> + if ((agent = snmpc_connect(argv[0], "161")) == NULL)
> + err(1, "%s", snmp_app->name);
> + argc--;
> + argv++;
> +
> + if (argc < 3 || argc % 3 != 0)
> + usage();
> +
> + if (pledge("stdio", NULL) == -1)
> + err(1, "pledge");
> +
> + pdu = snmp_set(agent, snmpc_varbindparse(argc, argv));
> +
> + (void) ber_scanf_elements(pdu, "t{Sdd{e", &class, &type, &errorstatus,
> + &errorindex, &varbind);
> + if (errorstatus != 0)
> + snmpc_printerror((enum snmp_error) errorstatus,
> + argv[errorindex - 1]);
is "errorindex - 1" the right index ?
$ ./obj/snmp set 192.168.1.5 sysContact.0 s "test"
snmp: Can't parse oid 192.168.1.5: Not writable
Note that the same pattern is used in others commands.
> +
> + if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
> + printf("Received report:\n");
> + for (; varbind != NULL; varbind = varbind->be_next) {
> + if (!snmpc_print(varbind))
> + err(1, "Can't print response");
> + }
> + ber_free_elements(pdu);
> + snmp_free_agent(agent);
> + return 0;
> +}
> +
> +int
> @@ -1116,6 +998,181 @@ fail:
> errno = EINVAL;
> free(decstr);
> return NULL;
> +}
> +
> +struct ber_element *
> +snmpc_varbindparse(int argc, char *argv[])
> +{
> + struct ber_oid oid, oidval;
> + struct in_addr addr4;
> + char *addr = (char *)&addr4;
> + char *str = NULL, *tmpstr, *endstr;
> + const char *errstr = NULL;
> + struct ber_element *varbind = NULL, *vblist = NULL;
> + int i, ret;
> + size_t strl, byte;
> + long long lval;
> +
> + if (argc % 3 != 0)
> + usage();
if I don't mess myself, callers already checks that 'argc % 3 != 0'. So I think
the condition is more a defense for programmer error that user error, and I
would use an assert(argc % 3 == 0) or abort().
> + for (i = 0; i < argc; i += 3) {
> + if (smi_string2oid(argv[i], &oid) == -1)
> + errx(1, "Invalid oid: %s\n", argv[i]);
> + switch (argv[i + 1][0]) {
> + case 'a':
> + ret = inet_pton(AF_INET, argv[i + 2], &addr4);
> + if (ret == -1)
> + err(1, "inet_pton");
> + if (ret == 0)
> + errx(1, "%s: Bad value notation (%s)", argv[i],
> + argv[i + 2]);
> + if ((varbind = ber_printf_elements(varbind, "{Oxt}",
> + &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION,
> + SNMP_T_IPADDR)) == NULL)
> + err(1, "ber_printf_elements");
> + break;
> + case 'b':
> + tmpstr = argv[i + 2];
> + strl = 0;
> + do {
> + lval = strtoll(tmpstr, &endstr, 10);
> + if (endstr[0] != ' ' && endstr[0] != '\t' &&
> + endstr[0] != ',' && endstr[0] != '\0')
> + errx(1, "%s: Bad value notation (%s)",
> + argv[i], argv[i + 2]);
> + if (tmpstr == endstr) {
> + tmpstr++;
> + continue;
> + }
> + if (lval < 0)
> + errx(1, "%s: Bad value notation (%s)",
> + argv[i], argv[i + 2]);
> + byte = lval / 8;
> + if (byte >= strl) {
> + if ((str = recallocarray(str, strl,
> + byte + 1, 1)) == NULL)
> + err(1, "malloc");
> + strl = byte + 1;
> + }
> + str[byte] |= 0x80 >> (lval % 8);
> + tmpstr = endstr + 1;
> + } while (endstr[0] != '\0');
> + /*
> + * RFC3416 Section 2.5
> + * A BITS value is encoded as an OCTET STRING
> + */
> + goto pastestring;
> + case 'c':
> + lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX,
> + &errstr);
> + if (errstr != NULL)
> + errx(1, "%s: Bad value notation (%s)", argv[i],
> + argv[i + 2]);
> + if ((varbind = ber_printf_elements(varbind, "{Oit}",
> + &oid, lval, BER_CLASS_APPLICATION,
> + SNMP_T_COUNTER32)) == NULL)
> + err(1, "ber_printf_elements");
> + break;
> + case 'd':
> + /* String always shrinks */
> + if ((str = malloc(strlen(argv[i + 2]))) == NULL)
> + err(1, "malloc");
> + tmpstr = argv[i + 2];
> + strl = 0;
> + do {
> + lval = strtoll(tmpstr, &endstr, 10);
> + if (endstr[0] != ' ' && endstr[0] != '\t' &&
> + endstr[0] != '\0')
> + errx(1, "%s: Bad value notation (%s)",
> + argv[i], argv[i + 2]);
> + if (tmpstr == endstr) {
> + tmpstr++;
> + continue;
> + }
> + if (lval < 0 || lval > 0xff)
> + errx(1, "%s: Bad value notation (%s)",
> + argv[i], argv[i + 2]);
> + str[strl++] = (unsigned char) lval;
> + tmpstr = endstr + 1;
> + } while (endstr[0] != '\0');
> + goto pastestring;
> + case 'u':
> + case 'i':
> + lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
> + &errstr);
> + if (errstr != NULL)
> + errx(1, "%s: Bad value notation (%s)", argv[i],
> + argv[i + 2]);
> + if ((varbind = ber_printf_elements(varbind, "{Oi}",
> + &oid, lval)) == NULL)
> + err(1, "ber_printf_elements");
> + break;
> + case 'n':
> + if ((varbind = ber_printf_elements(varbind, "{O0}",
> + &oid)) == NULL)
> + err(1, "ber_printf_elements");
> + break;
> + case 'o':
> + if (smi_string2oid(argv[i + 2], &oidval) == -1)
> + errx(1, "%s: Unknown Object Identifier (Sub-id "
> + "not found: (top) -> %s)", argv[i],
> + argv[i + 2]);
> + if ((varbind = ber_printf_elements(varbind, "{OO}",
> + &oid, &oidval)) == NULL)
> + err(1, "ber_printf_elements");
> + break;
> + case 's':
> + if ((str = strdup(argv[i + 2])) == NULL)
> + err(1, NULL);
> + strl = strlen(argv[i + 2]);
> +pastestring:
> + if ((varbind = ber_printf_elements(varbind, "{Ox}",
> + &oid, str, strl)) == NULL)
> + err(1, "ber_printf_elements");
> + free(str);
> + break;
> + case 't':
> + lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
> + &errstr);
> + if (errstr != NULL)
> + errx(1, "%s: Bad value notation (%s)", argv[i],
> + argv[i + 2]);
> + if ((varbind = ber_printf_elements(varbind, "{Oit}",
> + &oid, lval, BER_CLASS_APPLICATION,
> + SNMP_T_TIMETICKS)) == NULL)
> + err(1, "ber_printf_elements");
> + break;
> + case 'x':
> + /* String always shrinks */
> + if ((str = malloc(strlen(argv[i + 2]))) == NULL)
> + err(1, "malloc");
> + tmpstr = argv[i + 2];
> + strl = 0;
> + do {
> + lval = strtoll(tmpstr, &endstr, 16);
> + if (endstr[0] != ' ' && endstr[0] != '\t' &&
> + endstr[0] != '\0')
> + errx(1, "%s: Bad value notation (%s)",
> + argv[i], argv[i + 2]);
> + if (tmpstr == endstr) {
> + tmpstr++;
> + continue;
> + }
> + if (lval < 0 || lval > 0xff)
> + errx(1, "%s: Bad value notation (%s)",
> + argv[i], argv[i + 2]);
> + str[strl++] = (unsigned char) lval;
> + tmpstr = endstr + 1;
> + } while (endstr[0] != '\0');
> + goto pastestring;
> + default:
> + usage();
> + }
> + if (vblist == NULL)
> + vblist = varbind;
> + }
> +
> + return vblist;
> }
>
> __dead void
>
--
Sebastien Marie