Annotation of src/usr.bin/snmp/snmpc.c, Revision 1.8
1.8 ! martijn 1: /* $OpenBSD: snmpc.c,v 1.7 2019/08/14 14:40:23 deraadt Exp $ */
1.1 martijn 2:
3: /*
4: * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
5: * Copyright (c) 2013 Reyk Floeter <reyk@openbsd.org>
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: */
19:
20: #include <sys/limits.h>
21: #include <sys/types.h>
22: #include <sys/socket.h>
23: #include <sys/un.h>
24:
25: #include <arpa/inet.h>
26:
27: #include <ber.h>
28: #include <err.h>
29: #include <errno.h>
30: #include <netdb.h>
31: #include <poll.h>
32: #include <stdio.h>
33: #include <stdlib.h>
34: #include <stdint.h>
35: #include <string.h>
36: #include <time.h>
37: #include <unistd.h>
38:
39: #include "smi.h"
40: #include "snmp.h"
41:
42: #define GETOPT_COMMON "c:r:t:v:O:"
43:
44: int snmpc_get(int, char *[]);
45: int snmpc_walk(int, char *[]);
46: int snmpc_trap(int, char *[]);
47: int snmpc_mibtree(int, char *[]);
1.8 ! martijn 48: struct snmp_agent *snmpc_connect(char *, char *);
1.1 martijn 49: int snmpc_parseagent(char *, char *);
50: int snmpc_print(struct ber_element *);
51: __dead void snmpc_printerror(enum snmp_error, char *);
52: void usage(void);
53:
54: struct snmp_app {
55: const char *name;
56: const int usecommonopt;
57: const char *optstring;
58: const char *usage;
1.2 deraadt 59: int (*exec)(int, char *[]);
1.1 martijn 60: };
61:
62: struct snmp_app snmp_apps[] = {
1.2 deraadt 63: { "get", 1, NULL, "agent oid ...", snmpc_get },
64: { "getnext", 1, NULL, "agent oid ...", snmpc_get },
1.7 deraadt 65: { "walk", 1, "C:", "[-C cIipt] [-C E endoid] agent [oid]", snmpc_walk },
1.2 deraadt 66: { "bulkget", 1, "C:", "[-C n<nonrep>r<maxrep>] agent oid ...", snmpc_get },
67: { "bulkwalk", 1, "C:", "[-C cipn<nonrep>r<maxrep>] agent [oid]", snmpc_walk },
68: { "trap", 1, NULL, "agent uptime oid [oid type value] ...", snmpc_trap },
69: { "mibtree", 0, "O:", "[-O fnS]", snmpc_mibtree }
1.1 martijn 70: };
71: struct snmp_app *snmp_app = NULL;
72:
73: char *community = "public";
74: char *mib = "mib_2";
75: int retries = 5;
76: int timeout = 1;
77: int version = SNMP_V2C;
78: int print_equals = 1;
79: int print_varbind_only = 0;
80: int print_summary = 0;
81: int print_time = 0;
82: int walk_check_increase = 1;
83: int walk_fallback_oid = 1;
84: int walk_include_oid = 0;
85: int smi_print_hint = 1;
86: int non_repeaters = 0;
87: int max_repetitions = 10;
88: struct ber_oid walk_end = {{0}, 0};
89: enum smi_oid_lookup oid_lookup = smi_oidl_short;
90: enum smi_output_string output_string = smi_os_default;
91:
92: int
93: main(int argc, char *argv[])
94: {
95: char optstr[BUFSIZ];
96: const char *errstr;
97: char *strtolp;
98: int ch;
99: size_t i;
100:
101: if (pledge("stdio inet dns", NULL) == -1)
102: err(1, "pledge");
1.2 deraadt 103:
1.1 martijn 104: if (argc <= 1)
105: usage();
106:
107: for (i = 0; i < sizeof(snmp_apps)/sizeof(*snmp_apps); i++) {
108: if (strcmp(snmp_apps[i].name, argv[1]) == 0) {
109: snmp_app = &snmp_apps[i];
110: if (snmp_app->optstring != NULL) {
111: if (strlcpy(optstr, snmp_app->optstring,
112: sizeof(optstr)) > sizeof(optstr))
113: errx(1, "strlcat");
114: }
115: break;
116: }
117: }
118: if (snmp_app == NULL)
119: usage();
120:
121: if (snmp_app->usecommonopt) {
122: if (strlcat(optstr, GETOPT_COMMON, sizeof(optstr)) >
123: sizeof(optstr))
124: errx(1, "strlcpy");
125: }
126:
127: argc--;
128: argv++;
129:
130: smi_init();
131:
132: while ((ch = getopt(argc, argv, optstr)) != -1) {
133: switch (ch) {
134: case 'c':
135: community = optarg;
136: break;
137: case 'r':
138: if ((retries = strtonum(optarg, 0, INT_MAX,
139: &errstr)) == 0) {
140: if (errstr != NULL)
141: errx(1, "-r: %s argument", errstr);
142: }
143: break;
144: case 't':
145: if ((timeout = strtonum(optarg, 1, INT_MAX,
146: &errstr)) == 0) {
147: if (errstr != NULL)
148: errx(1, "-t: %s argument", errstr);
149: }
150: break;
151: case 'v':
152: if (strcmp(optarg, "1") == 0)
153: version = SNMP_V1;
154: else if (strcmp(optarg, "2c") == 0)
155: version = SNMP_V2C;
156: else
157: errc(1, EINVAL, "-v");
158: break;
159: case 'C':
160: for (i = 0; i < strlen(optarg); i++) {
161: switch (optarg[i]) {
162: case 'c':
163: if (strcmp(snmp_app->name, "walk") &&
164: strcmp(snmp_app->name, "bulkwalk"))
165: usage();
166: walk_check_increase = 0;
167: break;
168: case 'i':
169: if (strcmp(snmp_app->name, "walk") &&
170: strcmp(snmp_app->name, "bulkwalk"))
171: usage();
172: walk_include_oid = 1;
173: break;
174: case 'n':
175: if (strcmp(snmp_app->name, "bulkget") &&
176: strcmp(snmp_app->name, "bulkwalk"))
177: usage();
178: errno = 0;
179: non_repeaters = strtol(&optarg[i + 1],
180: &strtolp, 10);
181: if (non_repeaters < 0 ||
182: errno == ERANGE) {
183: if (non_repeaters < 0)
184: errx(1, "%s%s",
185: "-Cn: too small ",
186: "argument");
187: else
188: errx(1, "%s%s",
189: "-Cn: too large",
190: "argument");
191: } else if (&optarg[i + 1] == strtolp)
192: errx(1, "-Cn invalid argument");
193: i = strtolp - optarg - 1;
194: break;
195: case 'p':
196: if (strcmp(snmp_app->name, "walk") &&
197: strcmp(snmp_app->name, "bulkwalk"))
198: usage();
199: print_summary = 1;
200: break;
201: case 'r':
202: if (strcmp(snmp_app->name, "bulkget") &&
203: strcmp(snmp_app->name, "bulkwalk"))
204: usage();
205: errno = 0;
206: max_repetitions = strtol(&optarg[i + 1],
207: &strtolp, 10);
208: if (max_repetitions < 0 ||
209: errno == ERANGE) {
210: if (max_repetitions < 0)
211: errx(1, "%s%s",
212: "-Cr: too small ",
213: "argument");
214: else
215: errx(1, "%s%s",
216: "-Cr: too large",
217: "argument");
218: } else if (&optarg[i + 1] == strtolp)
219: errx(1, "-Cr invalid argument");
220: i = strtolp - optarg - 1;
221: break;
222: case 't':
223: if (strcmp(snmp_app->name, "walk"))
224: usage();
225: print_time = 1;
226: break;
227: case 'E':
228: if (strcmp(snmp_app->name, "walk"))
229: usage();
230: if (smi_string2oid(argv[optind],
231: &walk_end) != 0)
232: errx(1, "%s: %s",
233: "Unknown Object Identifier",
234: argv[optind]);
235: optind++;
236: continue;
237: case 'I':
238: if (strcmp(snmp_app->name, "walk"))
239: usage();
240: walk_fallback_oid = 0;
241: break;
242: default:
243: usage();
244: }
245: if (optarg[i] == 'E')
246: break;
247: }
248: break;
249: case 'O':
250: for (i = 0; i < strlen(optarg); i++) {
251: if (strcmp(snmp_app->name, "mibtree") == 0 &&
252: optarg[i] != 'f' && optarg[i] != 'n' &&
253: optarg[i] != 'S')
254: usage();
255: switch (optarg[i]) {
256: case 'a':
257: output_string = smi_os_ascii;
258: break;
259: case 'f':
260: oid_lookup = smi_oidl_full;
261: break;
262: case 'n':
263: oid_lookup = smi_oidl_numeric;
264: break;
265: case 'q':
266: print_equals = 0;
267: smi_print_hint = 0;
268: break;
269: case 'v':
1.2 deraadt 270: print_varbind_only = 1;
1.1 martijn 271: break;
272: case 'x':
273: output_string = smi_os_hex;
274: break;
275: case 'S':
276: oid_lookup = smi_oidl_short;
277: break;
278: case 'Q':
279: smi_print_hint = 0;
280: break;
281: default:
282: usage();
283: }
284: }
285: break;
286: default:
287: usage();
288: }
289: }
290: argc -= optind;
291: argv += optind;
292:
293: return snmp_app->exec(argc, argv);
294: }
295:
296: int
297: snmpc_get(int argc, char *argv[])
298: {
299: struct ber_oid *oid;
300: struct ber_element *pdu, *varbind;
301: struct snmp_agent *agent;
302: int errorstatus, errorindex;
303: int i;
304:
305: if (argc < 2)
306: usage();
307:
1.8 ! martijn 308: if ((agent = snmpc_connect(argv[0], "161")) == NULL)
1.1 martijn 309: err(1, "%s", snmp_app->name);
310: agent->timeout = timeout;
311: agent->retries = retries;
312:
313: if (pledge("stdio", NULL) == -1)
314: err(1, "pledge");
315: argc--;
316: argv++;
317:
318: oid = reallocarray(NULL, argc, sizeof(*oid));
1.3 deraadt 319: if (oid == NULL)
320: err(1, "malloc");
1.1 martijn 321: for (i = 0; i < argc; i++) {
322: if (smi_string2oid(argv[i], &oid[i]) == -1)
323: errx(1, "%s: Unknown object identifier", argv[0]);
324: }
325: if (strcmp(snmp_app->name, "getnext") == 0) {
326: if ((pdu = snmp_getnext(agent, oid, argc)) == NULL)
327: err(1, "getnext");
328: } else if (strcmp(snmp_app->name, "bulkget") == 0) {
329: if (version < SNMP_V2C)
330: errx(1, "Cannot send V2 PDU on V1 session");
331: if (non_repeaters > argc)
332: errx(1, "need more objects than -Cn<num>");
333: if ((pdu = snmp_getbulk(agent, oid, argc, non_repeaters,
334: max_repetitions)) == NULL)
335: err(1, "bulkget");
336: } else {
337: if ((pdu = snmp_get(agent, oid, argc)) == NULL)
338: err(1, "get");
339: }
340:
341: (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus, &errorindex,
342: &varbind);
343: if (errorstatus != 0)
344: snmpc_printerror((enum snmp_error) errorstatus,
1.6 martijn 345: argv[errorindex - 1]);
1.1 martijn 346:
347: for (; varbind != NULL; varbind = varbind->be_next) {
348: if (!snmpc_print(varbind))
349: err(1, "Can't print response");
350: }
351: ber_free_elements(pdu);
352: snmp_free_agent(agent);
353: return 0;
354: }
355:
356: int
357: snmpc_walk(int argc, char *argv[])
358: {
359: struct ber_oid oid, loid, noid;
360: struct ber_element *pdu, *varbind, *value;
361: struct timespec start, finish;
362: struct snmp_agent *agent;
363: const char *oids;
364: char oidstr[SNMP_MAX_OID_STRLEN];
365: int n = 0, prev_cmp;
366: int errorstatus, errorindex;
367:
368: if (strcmp(snmp_app->name, "bulkwalk") == 0 && version < SNMP_V2C)
369: errx(1, "Cannot send V2 PDU on V1 session");
370: if (argc < 1 || argc > 2)
371: usage();
372: oids = argc == 1 ? mib : argv[1];
373:
1.8 ! martijn 374: if ((agent = snmpc_connect(argv[0], "161"))== NULL)
1.1 martijn 375: err(1, "%s", snmp_app->name);
376: agent->timeout = timeout;
377: agent->retries = retries;
378: if (pledge("stdio", NULL) == -1)
379: err(1, "pledge");
380:
381: if (smi_string2oid(oids, &oid) == -1)
382: errx(1, "%s: Unknown object identifier", oids);
383: bcopy(&oid, &noid, sizeof(noid));
384: if (print_time)
385: clock_gettime(CLOCK_MONOTONIC, &start);
386:
387: if (walk_include_oid) {
388: if ((pdu = snmp_get(agent, &oid, 1)) == NULL)
389: err(1, "%s", snmp_app->name);
390:
391: (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus,
392: &errorindex, &varbind);
393: if (errorstatus != 0)
394: snmpc_printerror((enum snmp_error) errorstatus,
1.6 martijn 395: argv[errorindex - 1]);
1.1 martijn 396:
397: if (!snmpc_print(varbind))
398: err(1, "Can't print response");
399: ber_free_element(pdu);
400: n++;
401: }
402: while (1) {
403: bcopy(&noid, &loid, sizeof(loid));
404: if (strcmp(snmp_app->name, "bulkwalk") == 0) {
405: if ((pdu = snmp_getbulk(agent, &noid, 1,
406: non_repeaters, max_repetitions)) == NULL)
407: err(1, "bulkwalk");
408: } else {
409: if ((pdu = snmp_getnext(agent, &noid, 1)) == NULL)
410: err(1, "walk");
411: }
412:
413: (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus,
414: &errorindex, &varbind);
415: if (errorstatus != 0) {
416: smi_oid2string(&noid, oidstr, sizeof(oidstr),
417: oid_lookup);
418: snmpc_printerror((enum snmp_error) errorstatus, oidstr);
419: }
420:
1.2 deraadt 421: for (; varbind != NULL; varbind = varbind->be_next) {
1.1 martijn 422: (void) ber_scanf_elements(varbind, "{oe}", &noid,
423: &value);
424: if (value->be_class == BER_CLASS_CONTEXT &&
425: value->be_type == BER_TYPE_EOC)
426: break;
427: prev_cmp = ber_oid_cmp(&loid, &noid);
428: if (walk_check_increase && prev_cmp == -1)
429: errx(1, "OID not increasing");
430: if (prev_cmp == 0 || ber_oid_cmp(&oid, &noid) != 2)
431: break;
432: if (walk_end.bo_n != 0 &&
433: ber_oid_cmp(&walk_end, &noid) != -1)
434: break;
435:
436: if (!snmpc_print(varbind))
437: err(1, "Can't print response");
438: n++;
439: }
440: ber_free_elements(pdu);
441: if (varbind != NULL)
442: break;
443: }
444: if (walk_fallback_oid && n == 0) {
445: if ((pdu = snmp_get(agent, &oid, 1)) == NULL)
446: err(1, "%s", snmp_app->name);
447:
448: (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus,
449: &errorindex, &varbind);
450: if (errorstatus != 0)
451: snmpc_printerror((enum snmp_error) errorstatus,
1.6 martijn 452: argv[errorindex - 1]);
1.1 martijn 453:
454: if (!snmpc_print(varbind))
455: err(1, "Can't print response");
456: ber_free_element(pdu);
457: n++;
458: }
459: if (print_time)
460: clock_gettime(CLOCK_MONOTONIC, &finish);
461: if (print_summary)
462: printf("Variables found: %d\n", n);
463: if (print_time) {
464: if ((finish.tv_nsec -= start.tv_nsec) < 0) {
465: finish.tv_sec -= 1;
466: finish.tv_nsec += 1000000000;
467: }
468: finish.tv_sec -= start.tv_sec;
469: fprintf(stderr, "Total traversal time: %lld.%09ld seconds\n",
470: finish.tv_sec, finish.tv_nsec);
471: }
472: snmp_free_agent(agent);
473: return 0;
474: }
475:
476: int
477: snmpc_trap(int argc, char *argv[])
478: {
479: struct snmp_agent *agent;
480: struct timespec ts;
481: struct ber_oid trapoid, oid, oidval;
482: struct in_addr addr4;
483: char *addr = (char *)&addr4;
484: char *str = NULL, *tmpstr, *endstr;
485: const char *errstr = NULL;
486: struct ber_element *varbind = NULL, *pdu = NULL;
487: long long lval;
488: int i, ret;
489: size_t strl, byte;
490:
491: if (argc < 3 || argc % 3 != 0)
492: usage();
493: if (version == SNMP_V1)
494: errx(1, "trap is not supported for snmp v1");
495:
1.8 ! martijn 496: if ((agent = snmpc_connect(argv[0], "162")) == NULL)
1.1 martijn 497: err(1, "%s", snmp_app->name);
498:
499: if (pledge("stdio", NULL) == -1)
500: err(1, "pledge");
501:
502: if (argv[1][0] == '\0') {
503: if (clock_gettime(CLOCK_UPTIME, &ts) == -1)
504: err(1, "clock_gettime");
505: } else {
506: lval = strtonum(argv[1], 0, LLONG_MAX, &errstr);
507: if (errstr != NULL)
508: errx(1, "Bad value notation (%s)", argv[1]);
509: ts.tv_sec = lval / 100;
510: ts.tv_nsec = (lval % 100) * 10000000;
511: }
512: if (smi_string2oid(argv[2], &trapoid) == -1)
513: errx(1, "Invalid oid: %s\n", argv[2]);
514:
515: argc -= 3;
516: argv += 3;
517: for (i = 0; i < argc; i += 3) {
518: if (smi_string2oid(argv[i], &oid) == -1)
519: errx(1, "Invalid oid: %s\n", argv[i]);
520: switch (argv[i + 1][0]) {
521: case 'a':
522: ret = inet_pton(AF_INET, argv[i + 2], &addr4);
523: if (ret == -1)
524: err(1, "inet_pton");
525: if (ret == 0)
526: errx(1, "%s: Bad value notation (%s)", argv[i],
527: argv[i + 2]);
528: if ((varbind = ber_printf_elements(varbind, "{Oxt}",
529: &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION,
530: SNMP_T_IPADDR)) == NULL)
531: err(1, "ber_printf_elements");
532: break;
533: case 'b':
534: tmpstr = argv[i + 2];
535: strl = 0;
536: do {
537: lval = strtoll(tmpstr, &endstr, 10);
538: if (endstr[0] != ' ' && endstr[0] != '\t' &&
539: endstr[0] != ',' && endstr[0] != '\0')
540: errx(1, "%s: Bad value notation (%s)",
541: argv[i], argv[i + 2]);
542: if (tmpstr == endstr) {
543: tmpstr++;
544: continue;
545: }
546: if (lval < 0)
547: errx(1, "%s: Bad value notation (%s)",
548: argv[i], argv[i + 2]);
549: byte = lval / 8;
550: if (byte >= strl) {
551: if ((str = recallocarray(str, strl,
552: byte + 1, 1)) == NULL)
1.5 martijn 553: err(1, "malloc");
1.1 martijn 554: strl = byte + 1;
555: }
556: str[byte] |= 0x80 >> (lval % 8);
557: tmpstr = endstr + 1;
558: } while (endstr[0] != '\0');
559: /*
560: * RFC3416 Section 2.5
561: * A BITS value is encoded as an OCTET STRING
562: */
563: goto pastestring;
564: case 'c':
565: lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX,
566: &errstr);
567: if (errstr != NULL)
568: errx(1, "%s: Bad value notation (%s)", argv[i],
569: argv[i + 2]);
570: if ((varbind = ber_printf_elements(varbind, "{Oit}",
571: &oid, lval, BER_CLASS_APPLICATION,
572: SNMP_T_COUNTER32)) == NULL)
573: err(1, "ber_printf_elements");
574: break;
575: case 'd':
576: /* String always shrinks */
577: if ((str = malloc(strlen(argv[i + 2]))) == NULL)
1.5 martijn 578: err(1, "malloc");
1.1 martijn 579: tmpstr = argv[i + 2];
580: strl = 0;
581: do {
582: lval = strtoll(tmpstr, &endstr, 10);
583: if (endstr[0] != ' ' && endstr[0] != '\t' &&
584: endstr[0] != '\0')
585: errx(1, "%s: Bad value notation (%s)",
586: argv[i], argv[i + 2]);
587: if (tmpstr == endstr) {
588: tmpstr++;
589: continue;
590: }
591: if (lval < 0 || lval > 0xff)
592: errx(1, "%s: Bad value notation (%s)",
593: argv[i], argv[i + 2]);
594: str[strl++] = (unsigned char) lval;
595: tmpstr = endstr + 1;
596: } while (endstr[0] != '\0');
597: goto pastestring;
598: case 'u':
599: case 'i':
600: lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
601: &errstr);
602: if (errstr != NULL)
603: errx(1, "%s: Bad value notation (%s)", argv[i],
604: argv[i + 2]);
605: if ((varbind = ber_printf_elements(varbind, "{Oi}",
606: &oid, lval)) == NULL)
607: err(1, "ber_printf_elements");
608: break;
609: case 'n':
610: if ((varbind = ber_printf_elements(varbind, "{O0}",
611: &oid)) == NULL)
612: err(1, "ber_printf_elements");
613: break;
614: case 'o':
615: if (smi_string2oid(argv[i + 2], &oidval) == -1)
616: errx(1, "%s: Unknown Object Identifier (Sub-id "
617: "not found: (top) -> %s)", argv[i],
618: argv[i + 2]);
619: if ((varbind = ber_printf_elements(varbind, "{OO}",
620: &oid, &oidval)) == NULL)
621: err(1, "ber_printf_elements");
622: break;
623: case 's':
624: if ((str = strdup(argv[i + 2])) == NULL)
625: err(1, NULL);
626: strl = strlen(argv[i + 2]);
627: pastestring:
628: if ((varbind = ber_printf_elements(varbind, "{Ox}",
629: &oid, str, strl)) == NULL)
630: err(1, "ber_printf_elements");
631: free(str);
632: break;
633: case 't':
634: lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
635: &errstr);
636: if (errstr != NULL)
637: errx(1, "%s: Bad value notation (%s)", argv[i],
638: argv[i + 2]);
639: if ((varbind = ber_printf_elements(varbind, "{Oit}",
640: &oid, lval, BER_CLASS_APPLICATION,
641: SNMP_T_TIMETICKS)) == NULL)
642: err(1, "ber_printf_elements");
643: break;
644: case 'x':
645: /* String always shrinks */
646: if ((str = malloc(strlen(argv[i + 2]))) == NULL)
1.5 martijn 647: err(1, "malloc");
1.1 martijn 648: tmpstr = argv[i + 2];
649: strl = 0;
650: do {
651: lval = strtoll(tmpstr, &endstr, 16);
652: if (endstr[0] != ' ' && endstr[0] != '\t' &&
653: endstr[0] != '\0')
654: errx(1, "%s: Bad value notation (%s)",
655: argv[i], argv[i + 2]);
656: if (tmpstr == endstr) {
657: tmpstr++;
658: continue;
659: }
660: if (lval < 0 || lval > 0xff)
661: errx(1, "%s: Bad value notation (%s)",
662: argv[i], argv[i + 2]);
663: str[strl++] = (unsigned char) lval;
664: tmpstr = endstr + 1;
665: } while (endstr[0] != '\0');
666: goto pastestring;
667: default:
668: usage();
669: }
670: if (pdu == NULL)
671: pdu = varbind;
672: }
673:
674: snmp_trap(agent, &ts, &trapoid, pdu);
675:
676: return 0;
677: }
678:
679: int
680: snmpc_mibtree(int argc, char *argv[])
681: {
682: struct oid *oid;
683: char buf[BUFSIZ];
684:
685: for (oid = NULL; (oid = smi_foreach(oid, 0)) != NULL;) {
686: smi_oid2string(&oid->o_id, buf, sizeof(buf), oid_lookup);
687: printf("%s\n", buf);
688: }
689: return 0;
1.8 ! martijn 690: }
! 691:
! 692: struct snmp_agent *
! 693: snmpc_connect(char *host, char *port)
! 694: {
! 695: switch (version) {
! 696: case SNMP_V1:
! 697: case SNMP_V2C:
! 698: return snmp_connect_v12(snmpc_parseagent(host, port), version,
! 699: community);
! 700: }
! 701: return NULL;
1.1 martijn 702: }
703:
704: int
705: snmpc_print(struct ber_element *elm)
706: {
707: struct ber_oid oid;
708: char oids[SNMP_MAX_OID_STRLEN];
709: char *value;
710:
711: elm = elm->be_sub;
712: if (ber_get_oid(elm, &oid) != 0) {
713: errno = EINVAL;
714: return 0;
715: }
716:
717: elm = elm->be_next;
718: value = smi_print_element(elm, smi_print_hint, output_string, oid_lookup);
719: if (value == NULL)
720: return 0;
721:
722: if (print_varbind_only)
723: printf("%s\n", value);
724: else if (print_equals) {
725: smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
726: printf("%s = %s\n", oids, value);
727: } else {
728: smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
729: printf("%s %s\n", oids, value);
730: }
731: free(value);
1.2 deraadt 732:
1.1 martijn 733: return 1;
734: }
735:
736: __dead void
737: snmpc_printerror(enum snmp_error error, char *oid)
738: {
1.2 deraadt 739: switch (error) {
1.1 martijn 740: case SNMP_ERROR_NONE:
741: errx(1, "No error, how did I get here?");
742: case SNMP_ERROR_TOOBIG:
743: errx(1, "Can't parse oid %s: Response too big", oid);
744: case SNMP_ERROR_NOSUCHNAME:
745: errx(1, "Can't parse oid %s: No such object", oid);
746: case SNMP_ERROR_BADVALUE:
747: errx(1, "Can't parse oid %s: Bad value", oid);
748: case SNMP_ERROR_READONLY:
749: errx(1, "Can't parse oid %s: Read only", oid);
750: case SNMP_ERROR_GENERR:
751: errx(1, "Can't parse oid %s: Generic error", oid);
752: case SNMP_ERROR_NOACCESS:
753: errx(1, "Can't parse oid %s: Access denied", oid);
754: case SNMP_ERROR_WRONGTYPE:
755: errx(1, "Can't parse oid %s: Wrong type", oid);
756: case SNMP_ERROR_WRONGLENGTH:
757: errx(1, "Can't parse oid %s: Wrong length", oid);
758: case SNMP_ERROR_WRONGENC:
759: errx(1, "Can't parse oid %s: Wrong encoding", oid);
760: case SNMP_ERROR_WRONGVALUE:
761: errx(1, "Can't parse oid %s: Wrong value", oid);
762: case SNMP_ERROR_NOCREATION:
763: errx(1, "Can't parse oid %s: Can't be created", oid);
764: case SNMP_ERROR_INCONVALUE:
765: errx(1, "Can't parse oid %s: Inconsistent value", oid);
766: case SNMP_ERROR_RESUNAVAIL:
767: errx(1, "Can't parse oid %s: Resource unavailable", oid);
768: case SNMP_ERROR_COMMITFAILED:
769: errx(1, "Can't parse oid %s: Commit failed", oid);
770: case SNMP_ERROR_UNDOFAILED:
771: errx(1, "Can't parse oid %s: Undo faild", oid);
772: case SNMP_ERROR_AUTHERROR:
773: errx(1, "Can't parse oid %s: Authorization error", oid);
774: case SNMP_ERROR_NOTWRITABLE:
775: errx(1, "Can't parse oid %s: Not writable", oid);
776: case SNMP_ERROR_INCONNAME:
777: errx(1, "Can't parse oid %s: Inconsistent name", oid);
778: }
779: errx(1, "Can't parse oid %s: Unknown error (%d)", oid, error);
780: }
781:
782: int
783: snmpc_parseagent(char *agent, char *defaultport)
784: {
785: struct addrinfo hints, *ai, *ai0 = NULL;
786: struct sockaddr_un saddr;
787: char *agentdup, *specifier, *hostname, *port = NULL;
788: int error;
789: int s;
790:
791: if ((agentdup = specifier = strdup(agent)) == NULL)
792: err(1, NULL);
793:
794: bzero(&hints, sizeof(hints));
795: if ((hostname = strchr(specifier, ':')) != NULL) {
796: *hostname++ = '\0';
797: if (strcasecmp(specifier, "udp") == 0) {
798: hints.ai_family = AF_INET;
799: hints.ai_socktype = SOCK_DGRAM;
800: } else if (strcasecmp(specifier, "tcp") == 0) {
801: hints.ai_family = AF_INET;
802: hints.ai_socktype = SOCK_STREAM;
803: } else if (strcasecmp(specifier, "udp6") == 0 ||
804: strcasecmp(specifier, "udpv6") == 0 ||
805: strcasecmp(specifier, "udpipv6") == 0) {
806: hints.ai_family = AF_INET6;
807: hints.ai_socktype = SOCK_DGRAM;
808: } else if (strcasecmp(specifier, "tcp6") == 0 ||
809: strcasecmp(specifier, "tcpv6") == 0 ||
810: strcasecmp(specifier, "tcpipv6") == 0) {
811: hints.ai_family = AF_INET6;
812: hints.ai_socktype = SOCK_STREAM;
813: } else if (strcasecmp(specifier, "unix") == 0) {
814: hints.ai_family = AF_UNIX;
815: hints.ai_socktype = SOCK_STREAM;
816: hints.ai_addr = (struct sockaddr *)&saddr;
817: hints.ai_addrlen = sizeof(saddr);
818: saddr.sun_len = sizeof(saddr);
819: saddr.sun_family = AF_UNIX;
820: if (strlcpy(saddr.sun_path, hostname,
821: sizeof(saddr.sun_path)) > sizeof(saddr.sun_path))
822: errx(1, "Hostname path too long");
823: ai = &hints;
824: } else {
825: port = hostname;
826: hostname = specifier;
827: specifier = NULL;
828: hints.ai_family = AF_INET;
829: hints.ai_socktype = SOCK_DGRAM;
830: }
831: if (port == NULL) {
832: if (hints.ai_family == AF_INET) {
833: if ((port = strchr(hostname, ':')) != NULL)
834: *port++ = '\0';
835: } else if (hints.ai_family == AF_INET6) {
836: if (hostname[0] == '[') {
837: hostname++;
838: if ((port = strchr(hostname, ']')) == NULL)
839: errx(1, "invalid agent");
840: *port++ = '\0';
841: if (port[0] == ':')
842: *port++ = '\0';
843: else
844: port = NULL;
845: } else {
846: if ((port = strrchr(hostname, ':')) == NULL)
847: errx(1, "invalid agent");
848: *port++ = '\0';
849: }
850: }
851: }
852: } else {
853: hostname = specifier;
854: hints.ai_family = AF_INET;
855: hints.ai_socktype = SOCK_DGRAM;
856: }
857:
858: if (hints.ai_family != AF_UNIX) {
859: if (port == NULL)
860: port = defaultport;
861: error = getaddrinfo(hostname, port, &hints, &ai0);
862: if (error)
863: errx(1, "%s", gai_strerror(error));
864: s = -1;
865: for (ai = ai0; ai != NULL; ai = ai->ai_next) {
866: if ((s = socket(ai->ai_family, ai->ai_socktype,
867: ai->ai_protocol)) == -1)
868: continue;
869: break;
870: }
871: } else
872: s = socket(hints.ai_family, hints.ai_socktype,
873: hints.ai_protocol);
874: if (s == -1)
875: err(1, "socket");
876:
877: if (connect(s, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) == -1)
878: err(1, "Can't connect to %s", agent);
879:
880: if (ai0 != NULL)
881: freeaddrinfo(ai0);
882: free(agentdup);
883: return s;
884: }
885:
886: __dead void
887: usage(void)
888: {
889: size_t i;
890:
891: if (snmp_app != NULL) {
1.4 martijn 892: fprintf(stderr, "usage: snmp %s%s%s%s\n",
893: snmp_app->name,
1.1 martijn 894: snmp_app->usecommonopt ?
1.4 martijn 895: " [-c community] [-r retries] [-t timeout] [-v version]\n"
896: " [-O afnqvxSQ]" : "",
1.1 martijn 897: snmp_app->usage == NULL ? "" : " ",
898: snmp_app->usage == NULL ? "" : snmp_app->usage);
899: exit(1);
900: }
901: for (i = 0; i < (sizeof(snmp_apps)/sizeof(*snmp_apps)); i++) {
1.4 martijn 902: if (i == 0)
903: fprintf(stderr, "usage: ");
904: else
905: fprintf(stderr, " ");
906: fprintf(stderr, "snmp %s%s %s\n",
907: snmp_apps[i].name,
1.1 martijn 908: snmp_apps[i].usecommonopt ?
1.4 martijn 909: " [-c community] [-r retries] [-t timeout] [-v version]\n"
910: " [-O afnqvxSQ]" : "",
911: snmp_apps[i].usage ? snmp_apps[i].usage : "");
1.1 martijn 912: }
913: exit(1);
914: }