Annotation of src/usr.bin/snmp/snmpc.c, Revision 1.2
1.2 ! deraadt 1: /* $OpenBSD: snmpc.c,v 1.1 2019/08/09 06:17:59 martijn 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 *[]);
48: int snmpc_parseagent(char *, char *);
49: int snmpc_print(struct ber_element *);
50: __dead void snmpc_printerror(enum snmp_error, char *);
51: void usage(void);
52:
53: struct snmp_app {
54: const char *name;
55: const int usecommonopt;
56: const char *optstring;
57: const char *usage;
1.2 ! deraadt 58: int (*exec)(int, char *[]);
1.1 martijn 59: };
60:
61: struct snmp_app snmp_apps[] = {
1.2 ! deraadt 62: { "get", 1, NULL, "agent oid ...", snmpc_get },
! 63: { "getnext", 1, NULL, "agent oid ...", snmpc_get },
! 64: { "walk", 1, "C:", "[-C cIipt] [-C E OID] agent [oid]", snmpc_walk },
! 65: { "bulkget", 1, "C:", "[-C n<nonrep>r<maxrep>] agent oid ...", snmpc_get },
! 66: { "bulkwalk", 1, "C:", "[-C cipn<nonrep>r<maxrep>] agent [oid]", snmpc_walk },
! 67: { "trap", 1, NULL, "agent uptime oid [oid type value] ...", snmpc_trap },
! 68: { "mibtree", 0, "O:", "[-O fnS]", snmpc_mibtree }
1.1 martijn 69: };
70: struct snmp_app *snmp_app = NULL;
71:
72: char *community = "public";
73: char *mib = "mib_2";
74: int retries = 5;
75: int timeout = 1;
76: int version = SNMP_V2C;
77: int print_equals = 1;
78: int print_varbind_only = 0;
79: int print_summary = 0;
80: int print_time = 0;
81: int walk_check_increase = 1;
82: int walk_fallback_oid = 1;
83: int walk_include_oid = 0;
84: int smi_print_hint = 1;
85: int non_repeaters = 0;
86: int max_repetitions = 10;
87: struct ber_oid walk_end = {{0}, 0};
88: enum smi_oid_lookup oid_lookup = smi_oidl_short;
89: enum smi_output_string output_string = smi_os_default;
90:
91: int
92: main(int argc, char *argv[])
93: {
94: char optstr[BUFSIZ];
95: const char *errstr;
96: char *strtolp;
97: int ch;
98: size_t i;
99:
100: if (pledge("stdio inet dns", NULL) == -1)
101: err(1, "pledge");
1.2 ! deraadt 102:
1.1 martijn 103: if (argc <= 1)
104: usage();
105:
106: for (i = 0; i < sizeof(snmp_apps)/sizeof(*snmp_apps); i++) {
107: if (strcmp(snmp_apps[i].name, argv[1]) == 0) {
108: snmp_app = &snmp_apps[i];
109: if (snmp_app->optstring != NULL) {
110: if (strlcpy(optstr, snmp_app->optstring,
111: sizeof(optstr)) > sizeof(optstr))
112: errx(1, "strlcat");
113: }
114: break;
115: }
116: }
117: if (snmp_app == NULL)
118: usage();
119:
120: if (snmp_app->usecommonopt) {
121: if (strlcat(optstr, GETOPT_COMMON, sizeof(optstr)) >
122: sizeof(optstr))
123: errx(1, "strlcpy");
124: }
125:
126: argc--;
127: argv++;
128:
129: smi_init();
130:
131: while ((ch = getopt(argc, argv, optstr)) != -1) {
132: switch (ch) {
133: case 'c':
134: community = optarg;
135: break;
136: case 'r':
137: if ((retries = strtonum(optarg, 0, INT_MAX,
138: &errstr)) == 0) {
139: if (errstr != NULL)
140: errx(1, "-r: %s argument", errstr);
141: }
142: break;
143: case 't':
144: if ((timeout = strtonum(optarg, 1, INT_MAX,
145: &errstr)) == 0) {
146: if (errstr != NULL)
147: errx(1, "-t: %s argument", errstr);
148: }
149: break;
150: case 'v':
151: if (strcmp(optarg, "1") == 0)
152: version = SNMP_V1;
153: else if (strcmp(optarg, "2c") == 0)
154: version = SNMP_V2C;
155: else
156: errc(1, EINVAL, "-v");
157: break;
158: case 'C':
159: for (i = 0; i < strlen(optarg); i++) {
160: switch (optarg[i]) {
161: case 'c':
162: if (strcmp(snmp_app->name, "walk") &&
163: strcmp(snmp_app->name, "bulkwalk"))
164: usage();
165: walk_check_increase = 0;
166: break;
167: case 'i':
168: if (strcmp(snmp_app->name, "walk") &&
169: strcmp(snmp_app->name, "bulkwalk"))
170: usage();
171: walk_include_oid = 1;
172: break;
173: case 'n':
174: if (strcmp(snmp_app->name, "bulkget") &&
175: strcmp(snmp_app->name, "bulkwalk"))
176: usage();
177: errno = 0;
178: non_repeaters = strtol(&optarg[i + 1],
179: &strtolp, 10);
180: if (non_repeaters < 0 ||
181: errno == ERANGE) {
182: if (non_repeaters < 0)
183: errx(1, "%s%s",
184: "-Cn: too small ",
185: "argument");
186: else
187: errx(1, "%s%s",
188: "-Cn: too large",
189: "argument");
190: } else if (&optarg[i + 1] == strtolp)
191: errx(1, "-Cn invalid argument");
192: i = strtolp - optarg - 1;
193: break;
194: case 'p':
195: if (strcmp(snmp_app->name, "walk") &&
196: strcmp(snmp_app->name, "bulkwalk"))
197: usage();
198: print_summary = 1;
199: break;
200: case 'r':
201: if (strcmp(snmp_app->name, "bulkget") &&
202: strcmp(snmp_app->name, "bulkwalk"))
203: usage();
204: errno = 0;
205: max_repetitions = strtol(&optarg[i + 1],
206: &strtolp, 10);
207: if (max_repetitions < 0 ||
208: errno == ERANGE) {
209: if (max_repetitions < 0)
210: errx(1, "%s%s",
211: "-Cr: too small ",
212: "argument");
213: else
214: errx(1, "%s%s",
215: "-Cr: too large",
216: "argument");
217: } else if (&optarg[i + 1] == strtolp)
218: errx(1, "-Cr invalid argument");
219: i = strtolp - optarg - 1;
220: break;
221: case 't':
222: if (strcmp(snmp_app->name, "walk"))
223: usage();
224: print_time = 1;
225: break;
226: case 'E':
227: if (strcmp(snmp_app->name, "walk"))
228: usage();
229: if (smi_string2oid(argv[optind],
230: &walk_end) != 0)
231: errx(1, "%s: %s",
232: "Unknown Object Identifier",
233: argv[optind]);
234: optind++;
235: continue;
236: case 'I':
237: if (strcmp(snmp_app->name, "walk"))
238: usage();
239: walk_fallback_oid = 0;
240: break;
241: default:
242: usage();
243: }
244: if (optarg[i] == 'E')
245: break;
246: }
247: break;
248: case 'O':
249: for (i = 0; i < strlen(optarg); i++) {
250: if (strcmp(snmp_app->name, "mibtree") == 0 &&
251: optarg[i] != 'f' && optarg[i] != 'n' &&
252: optarg[i] != 'S')
253: usage();
254: switch (optarg[i]) {
255: case 'a':
256: output_string = smi_os_ascii;
257: break;
258: case 'f':
259: oid_lookup = smi_oidl_full;
260: break;
261: case 'n':
262: oid_lookup = smi_oidl_numeric;
263: break;
264: case 'q':
265: print_equals = 0;
266: smi_print_hint = 0;
267: break;
268: case 'v':
1.2 ! deraadt 269: print_varbind_only = 1;
1.1 martijn 270: break;
271: case 'x':
272: output_string = smi_os_hex;
273: break;
274: case 'S':
275: oid_lookup = smi_oidl_short;
276: break;
277: case 'Q':
278: smi_print_hint = 0;
279: break;
280: default:
281: usage();
282: }
283: }
284: break;
285: default:
286: usage();
287: }
288: }
289: argc -= optind;
290: argv += optind;
291:
292: return snmp_app->exec(argc, argv);
293: }
294:
295: int
296: snmpc_get(int argc, char *argv[])
297: {
298: struct ber_oid *oid;
299: struct ber_element *pdu, *varbind;
300: struct snmp_agent *agent;
301: int errorstatus, errorindex;
302: int i;
303:
304: if (argc < 2)
305: usage();
306:
307: agent = snmp_connect_v12(snmpc_parseagent(argv[0], "161"), version,
308: community);
309: if (agent == NULL)
310: err(1, "%s", snmp_app->name);
311: agent->timeout = timeout;
312: agent->retries = retries;
313:
314: if (pledge("stdio", NULL) == -1)
315: err(1, "pledge");
316: argc--;
317: argv++;
318:
319: oid = reallocarray(NULL, argc, sizeof(*oid));
320: for (i = 0; i < argc; i++) {
321: if (smi_string2oid(argv[i], &oid[i]) == -1)
322: errx(1, "%s: Unknown object identifier", argv[0]);
323: }
324: if (strcmp(snmp_app->name, "getnext") == 0) {
325: if ((pdu = snmp_getnext(agent, oid, argc)) == NULL)
326: err(1, "getnext");
327: } else if (strcmp(snmp_app->name, "bulkget") == 0) {
328: if (version < SNMP_V2C)
329: errx(1, "Cannot send V2 PDU on V1 session");
330: if (non_repeaters > argc)
331: errx(1, "need more objects than -Cn<num>");
332: if ((pdu = snmp_getbulk(agent, oid, argc, non_repeaters,
333: max_repetitions)) == NULL)
334: err(1, "bulkget");
335: } else {
336: if ((pdu = snmp_get(agent, oid, argc)) == NULL)
337: err(1, "get");
338: }
339:
340: (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus, &errorindex,
341: &varbind);
342: if (errorstatus != 0)
343: snmpc_printerror((enum snmp_error) errorstatus,
344: argv[errorindex]);
345:
346: for (; varbind != NULL; varbind = varbind->be_next) {
347: if (!snmpc_print(varbind))
348: err(1, "Can't print response");
349: }
350: ber_free_elements(pdu);
351: snmp_free_agent(agent);
352: return 0;
353: }
354:
355: int
356: snmpc_walk(int argc, char *argv[])
357: {
358: struct ber_oid oid, loid, noid;
359: struct ber_element *pdu, *varbind, *value;
360: struct timespec start, finish;
361: struct snmp_agent *agent;
362: const char *oids;
363: char oidstr[SNMP_MAX_OID_STRLEN];
364: int n = 0, prev_cmp;
365: int errorstatus, errorindex;
366:
367: if (strcmp(snmp_app->name, "bulkwalk") == 0 && version < SNMP_V2C)
368: errx(1, "Cannot send V2 PDU on V1 session");
369: if (argc < 1 || argc > 2)
370: usage();
371: oids = argc == 1 ? mib : argv[1];
372:
373: agent = snmp_connect_v12(snmpc_parseagent(argv[0], "161"), version, community);
374: if (agent == NULL)
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,
395: argv[errorindex]);
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,
452: argv[errorindex]);
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:
496: agent = snmp_connect_v12(snmpc_parseagent(argv[0], "162"),
497: version, community);
498: if (agent == NULL)
499: err(1, "%s", snmp_app->name);
500:
501: if (pledge("stdio", NULL) == -1)
502: err(1, "pledge");
503:
504: if (argv[1][0] == '\0') {
505: if (clock_gettime(CLOCK_UPTIME, &ts) == -1)
506: err(1, "clock_gettime");
507: } else {
508: lval = strtonum(argv[1], 0, LLONG_MAX, &errstr);
509: if (errstr != NULL)
510: errx(1, "Bad value notation (%s)", argv[1]);
511: ts.tv_sec = lval / 100;
512: ts.tv_nsec = (lval % 100) * 10000000;
513: }
514: if (smi_string2oid(argv[2], &trapoid) == -1)
515: errx(1, "Invalid oid: %s\n", argv[2]);
516:
517: argc -= 3;
518: argv += 3;
519: for (i = 0; i < argc; i += 3) {
520: if (smi_string2oid(argv[i], &oid) == -1)
521: errx(1, "Invalid oid: %s\n", argv[i]);
522: switch (argv[i + 1][0]) {
523: case 'a':
524: ret = inet_pton(AF_INET, argv[i + 2], &addr4);
525: if (ret == -1)
526: err(1, "inet_pton");
527: if (ret == 0)
528: errx(1, "%s: Bad value notation (%s)", argv[i],
529: argv[i + 2]);
530: if ((varbind = ber_printf_elements(varbind, "{Oxt}",
531: &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION,
532: SNMP_T_IPADDR)) == NULL)
533: err(1, "ber_printf_elements");
534: break;
535: case 'b':
536: tmpstr = argv[i + 2];
537: strl = 0;
538: do {
539: lval = strtoll(tmpstr, &endstr, 10);
540: if (endstr[0] != ' ' && endstr[0] != '\t' &&
541: endstr[0] != ',' && endstr[0] != '\0')
542: errx(1, "%s: Bad value notation (%s)",
543: argv[i], argv[i + 2]);
544: if (tmpstr == endstr) {
545: tmpstr++;
546: continue;
547: }
548: if (lval < 0)
549: errx(1, "%s: Bad value notation (%s)",
550: argv[i], argv[i + 2]);
551: byte = lval / 8;
552: if (byte >= strl) {
553: if ((str = recallocarray(str, strl,
554: byte + 1, 1)) == NULL)
555: err(1, NULL);
556: strl = byte + 1;
557: }
558: str[byte] |= 0x80 >> (lval % 8);
559: tmpstr = endstr + 1;
560: } while (endstr[0] != '\0');
561: /*
562: * RFC3416 Section 2.5
563: * A BITS value is encoded as an OCTET STRING
564: */
565: goto pastestring;
566: case 'c':
567: lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX,
568: &errstr);
569: if (errstr != NULL)
570: errx(1, "%s: Bad value notation (%s)", argv[i],
571: argv[i + 2]);
572: if ((varbind = ber_printf_elements(varbind, "{Oit}",
573: &oid, lval, BER_CLASS_APPLICATION,
574: SNMP_T_COUNTER32)) == NULL)
575: err(1, "ber_printf_elements");
576: break;
577: case 'd':
578: /* String always shrinks */
579: if ((str = malloc(strlen(argv[i + 2]))) == NULL)
580: err(1, NULL);
581: tmpstr = argv[i + 2];
582: strl = 0;
583: do {
584: lval = strtoll(tmpstr, &endstr, 10);
585: if (endstr[0] != ' ' && endstr[0] != '\t' &&
586: endstr[0] != '\0')
587: errx(1, "%s: Bad value notation (%s)",
588: argv[i], argv[i + 2]);
589: if (tmpstr == endstr) {
590: tmpstr++;
591: continue;
592: }
593: if (lval < 0 || lval > 0xff)
594: errx(1, "%s: Bad value notation (%s)",
595: argv[i], argv[i + 2]);
596: str[strl++] = (unsigned char) lval;
597: tmpstr = endstr + 1;
598: } while (endstr[0] != '\0');
599: goto pastestring;
600: case 'u':
601: case 'i':
602: lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
603: &errstr);
604: if (errstr != NULL)
605: errx(1, "%s: Bad value notation (%s)", argv[i],
606: argv[i + 2]);
607: if ((varbind = ber_printf_elements(varbind, "{Oi}",
608: &oid, lval)) == NULL)
609: err(1, "ber_printf_elements");
610: break;
611: case 'n':
612: if ((varbind = ber_printf_elements(varbind, "{O0}",
613: &oid)) == NULL)
614: err(1, "ber_printf_elements");
615: break;
616: case 'o':
617: if (smi_string2oid(argv[i + 2], &oidval) == -1)
618: errx(1, "%s: Unknown Object Identifier (Sub-id "
619: "not found: (top) -> %s)", argv[i],
620: argv[i + 2]);
621: if ((varbind = ber_printf_elements(varbind, "{OO}",
622: &oid, &oidval)) == NULL)
623: err(1, "ber_printf_elements");
624: break;
625: case 's':
626: if ((str = strdup(argv[i + 2])) == NULL)
627: err(1, NULL);
628: strl = strlen(argv[i + 2]);
629: pastestring:
630: if ((varbind = ber_printf_elements(varbind, "{Ox}",
631: &oid, str, strl)) == NULL)
632: err(1, "ber_printf_elements");
633: free(str);
634: break;
635: case 't':
636: lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
637: &errstr);
638: if (errstr != NULL)
639: errx(1, "%s: Bad value notation (%s)", argv[i],
640: argv[i + 2]);
641: if ((varbind = ber_printf_elements(varbind, "{Oit}",
642: &oid, lval, BER_CLASS_APPLICATION,
643: SNMP_T_TIMETICKS)) == NULL)
644: err(1, "ber_printf_elements");
645: break;
646: case 'x':
647: /* String always shrinks */
648: if ((str = malloc(strlen(argv[i + 2]))) == NULL)
649: err(1, NULL);
650: tmpstr = argv[i + 2];
651: strl = 0;
652: do {
653: lval = strtoll(tmpstr, &endstr, 16);
654: if (endstr[0] != ' ' && endstr[0] != '\t' &&
655: endstr[0] != '\0')
656: errx(1, "%s: Bad value notation (%s)",
657: argv[i], argv[i + 2]);
658: if (tmpstr == endstr) {
659: tmpstr++;
660: continue;
661: }
662: if (lval < 0 || lval > 0xff)
663: errx(1, "%s: Bad value notation (%s)",
664: argv[i], argv[i + 2]);
665: str[strl++] = (unsigned char) lval;
666: tmpstr = endstr + 1;
667: } while (endstr[0] != '\0');
668: goto pastestring;
669: default:
670: usage();
671: }
672: if (pdu == NULL)
673: pdu = varbind;
674: }
675:
676: snmp_trap(agent, &ts, &trapoid, pdu);
677:
678: return 0;
679: }
680:
681: int
682: snmpc_mibtree(int argc, char *argv[])
683: {
684: struct oid *oid;
685: char buf[BUFSIZ];
686:
687: for (oid = NULL; (oid = smi_foreach(oid, 0)) != NULL;) {
688: smi_oid2string(&oid->o_id, buf, sizeof(buf), oid_lookup);
689: printf("%s\n", buf);
690: }
691: return 0;
692: }
693:
694: int
695: snmpc_print(struct ber_element *elm)
696: {
697: struct ber_oid oid;
698: char oids[SNMP_MAX_OID_STRLEN];
699: char *value;
700:
701: elm = elm->be_sub;
702: if (ber_get_oid(elm, &oid) != 0) {
703: errno = EINVAL;
704: return 0;
705: }
706:
707: elm = elm->be_next;
708: value = smi_print_element(elm, smi_print_hint, output_string, oid_lookup);
709: if (value == NULL)
710: return 0;
711:
712: if (print_varbind_only)
713: printf("%s\n", value);
714: else if (print_equals) {
715: smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
716: printf("%s = %s\n", oids, value);
717: } else {
718: smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
719: printf("%s %s\n", oids, value);
720: }
721: free(value);
1.2 ! deraadt 722:
1.1 martijn 723: return 1;
724: }
725:
726: __dead void
727: snmpc_printerror(enum snmp_error error, char *oid)
728: {
1.2 ! deraadt 729: switch (error) {
1.1 martijn 730: case SNMP_ERROR_NONE:
731: errx(1, "No error, how did I get here?");
732: case SNMP_ERROR_TOOBIG:
733: errx(1, "Can't parse oid %s: Response too big", oid);
734: case SNMP_ERROR_NOSUCHNAME:
735: errx(1, "Can't parse oid %s: No such object", oid);
736: case SNMP_ERROR_BADVALUE:
737: errx(1, "Can't parse oid %s: Bad value", oid);
738: case SNMP_ERROR_READONLY:
739: errx(1, "Can't parse oid %s: Read only", oid);
740: case SNMP_ERROR_GENERR:
741: errx(1, "Can't parse oid %s: Generic error", oid);
742: case SNMP_ERROR_NOACCESS:
743: errx(1, "Can't parse oid %s: Access denied", oid);
744: case SNMP_ERROR_WRONGTYPE:
745: errx(1, "Can't parse oid %s: Wrong type", oid);
746: case SNMP_ERROR_WRONGLENGTH:
747: errx(1, "Can't parse oid %s: Wrong length", oid);
748: case SNMP_ERROR_WRONGENC:
749: errx(1, "Can't parse oid %s: Wrong encoding", oid);
750: case SNMP_ERROR_WRONGVALUE:
751: errx(1, "Can't parse oid %s: Wrong value", oid);
752: case SNMP_ERROR_NOCREATION:
753: errx(1, "Can't parse oid %s: Can't be created", oid);
754: case SNMP_ERROR_INCONVALUE:
755: errx(1, "Can't parse oid %s: Inconsistent value", oid);
756: case SNMP_ERROR_RESUNAVAIL:
757: errx(1, "Can't parse oid %s: Resource unavailable", oid);
758: case SNMP_ERROR_COMMITFAILED:
759: errx(1, "Can't parse oid %s: Commit failed", oid);
760: case SNMP_ERROR_UNDOFAILED:
761: errx(1, "Can't parse oid %s: Undo faild", oid);
762: case SNMP_ERROR_AUTHERROR:
763: errx(1, "Can't parse oid %s: Authorization error", oid);
764: case SNMP_ERROR_NOTWRITABLE:
765: errx(1, "Can't parse oid %s: Not writable", oid);
766: case SNMP_ERROR_INCONNAME:
767: errx(1, "Can't parse oid %s: Inconsistent name", oid);
768: }
769: errx(1, "Can't parse oid %s: Unknown error (%d)", oid, error);
770: }
771:
772: int
773: snmpc_parseagent(char *agent, char *defaultport)
774: {
775: struct addrinfo hints, *ai, *ai0 = NULL;
776: struct sockaddr_un saddr;
777: char *agentdup, *specifier, *hostname, *port = NULL;
778: int error;
779: int s;
780:
781: if ((agentdup = specifier = strdup(agent)) == NULL)
782: err(1, NULL);
783:
784: bzero(&hints, sizeof(hints));
785: if ((hostname = strchr(specifier, ':')) != NULL) {
786: *hostname++ = '\0';
787: if (strcasecmp(specifier, "udp") == 0) {
788: hints.ai_family = AF_INET;
789: hints.ai_socktype = SOCK_DGRAM;
790: } else if (strcasecmp(specifier, "tcp") == 0) {
791: hints.ai_family = AF_INET;
792: hints.ai_socktype = SOCK_STREAM;
793: } else if (strcasecmp(specifier, "udp6") == 0 ||
794: strcasecmp(specifier, "udpv6") == 0 ||
795: strcasecmp(specifier, "udpipv6") == 0) {
796: hints.ai_family = AF_INET6;
797: hints.ai_socktype = SOCK_DGRAM;
798: } else if (strcasecmp(specifier, "tcp6") == 0 ||
799: strcasecmp(specifier, "tcpv6") == 0 ||
800: strcasecmp(specifier, "tcpipv6") == 0) {
801: hints.ai_family = AF_INET6;
802: hints.ai_socktype = SOCK_STREAM;
803: } else if (strcasecmp(specifier, "unix") == 0) {
804: hints.ai_family = AF_UNIX;
805: hints.ai_socktype = SOCK_STREAM;
806: hints.ai_addr = (struct sockaddr *)&saddr;
807: hints.ai_addrlen = sizeof(saddr);
808: saddr.sun_len = sizeof(saddr);
809: saddr.sun_family = AF_UNIX;
810: if (strlcpy(saddr.sun_path, hostname,
811: sizeof(saddr.sun_path)) > sizeof(saddr.sun_path))
812: errx(1, "Hostname path too long");
813: ai = &hints;
814: } else {
815: port = hostname;
816: hostname = specifier;
817: specifier = NULL;
818: hints.ai_family = AF_INET;
819: hints.ai_socktype = SOCK_DGRAM;
820: }
821: if (port == NULL) {
822: if (hints.ai_family == AF_INET) {
823: if ((port = strchr(hostname, ':')) != NULL)
824: *port++ = '\0';
825: } else if (hints.ai_family == AF_INET6) {
826: if (hostname[0] == '[') {
827: hostname++;
828: if ((port = strchr(hostname, ']')) == NULL)
829: errx(1, "invalid agent");
830: *port++ = '\0';
831: if (port[0] == ':')
832: *port++ = '\0';
833: else
834: port = NULL;
835: } else {
836: if ((port = strrchr(hostname, ':')) == NULL)
837: errx(1, "invalid agent");
838: *port++ = '\0';
839: }
840: }
841: }
842: } else {
843: hostname = specifier;
844: hints.ai_family = AF_INET;
845: hints.ai_socktype = SOCK_DGRAM;
846: }
847:
848: if (hints.ai_family != AF_UNIX) {
849: if (port == NULL)
850: port = defaultport;
851: error = getaddrinfo(hostname, port, &hints, &ai0);
852: if (error)
853: errx(1, "%s", gai_strerror(error));
854: s = -1;
855: for (ai = ai0; ai != NULL; ai = ai->ai_next) {
856: if ((s = socket(ai->ai_family, ai->ai_socktype,
857: ai->ai_protocol)) == -1)
858: continue;
859: break;
860: }
861: } else
862: s = socket(hints.ai_family, hints.ai_socktype,
863: hints.ai_protocol);
864: if (s == -1)
865: err(1, "socket");
866:
867: if (connect(s, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) == -1)
868: err(1, "Can't connect to %s", agent);
869:
870: if (ai0 != NULL)
871: freeaddrinfo(ai0);
872: free(agentdup);
873: return s;
874: }
875:
876: __dead void
877: usage(void)
878: {
879: size_t i;
880:
881: extern char *__progname;
882:
883: if (snmp_app != NULL) {
884: fprintf(stderr, "usage: %s %s%s%s%s\n",
885: __progname, snmp_app->name,
886: snmp_app->usecommonopt ?
887: " [-c community] [-r retries] [-t timeout] "
888: "[-v protocol version] [-O afnqvxSQ]" : "",
889: snmp_app->usage == NULL ? "" : " ",
890: snmp_app->usage == NULL ? "" : snmp_app->usage);
891: exit(1);
892: }
893: fprintf(stderr, "usage: \n");
894: for (i = 0; i < (sizeof(snmp_apps)/sizeof(*snmp_apps)); i++) {
895: fprintf(stderr, "%*s %s%s%s%s\n",
896: (int) (sizeof("usage:") + strlen(__progname)),
897: __progname, snmp_apps[i].name,
898: snmp_apps[i].usecommonopt ?
899: " [-c community] [-r retries] [-t timeout] "
900: "[-v protocol version] [-O afnqvxSQ]" : "",
901: snmp_apps[i].usage == NULL ? "" : " ",
902: snmp_apps[i].usage == NULL ? "" : snmp_apps[i].usage);
903: }
904: exit(1);
905: }