version 1.8, 2019/09/18 09:44:38 |
version 1.9, 2019/09/18 09:48:14 |
|
|
#include <arpa/inet.h> |
#include <arpa/inet.h> |
|
|
#include <ber.h> |
#include <ber.h> |
|
#include <ctype.h> |
#include <err.h> |
#include <err.h> |
#include <errno.h> |
#include <errno.h> |
#include <netdb.h> |
#include <netdb.h> |
|
|
|
|
#include "smi.h" |
#include "smi.h" |
#include "snmp.h" |
#include "snmp.h" |
|
#include "usm.h" |
|
|
#define GETOPT_COMMON "c:r:t:v:O:" |
#define GETOPT_COMMON "c:E:e:n:O:r:t:u:v:Z:" |
|
|
int snmpc_get(int, char *[]); |
int snmpc_get(int, char *[]); |
int snmpc_walk(int, char *[]); |
int snmpc_walk(int, char *[]); |
|
|
int snmpc_parseagent(char *, char *); |
int snmpc_parseagent(char *, char *); |
int snmpc_print(struct ber_element *); |
int snmpc_print(struct ber_element *); |
__dead void snmpc_printerror(enum snmp_error, char *); |
__dead void snmpc_printerror(enum snmp_error, char *); |
|
char *snmpc_hex2bin(char *, size_t *); |
void usage(void); |
void usage(void); |
|
|
struct snmp_app { |
struct snmp_app { |
|
|
struct snmp_app *snmp_app = NULL; |
struct snmp_app *snmp_app = NULL; |
|
|
char *community = "public"; |
char *community = "public"; |
|
struct snmp_v3 *v3; |
char *mib = "mib_2"; |
char *mib = "mib_2"; |
int retries = 5; |
int retries = 5; |
int timeout = 1; |
int timeout = 1; |
int version = SNMP_V2C; |
enum snmp_version version = SNMP_V2C; |
int print_equals = 1; |
int print_equals = 1; |
int print_varbind_only = 0; |
int print_varbind_only = 0; |
int print_summary = 0; |
int print_summary = 0; |
|
|
int |
int |
main(int argc, char *argv[]) |
main(int argc, char *argv[]) |
{ |
{ |
|
struct snmp_sec *sec; |
|
char *user = NULL; |
|
int seclevel = SNMP_MSGFLAG_REPORT; |
|
char *ctxname = NULL; |
|
char *ctxengineid = NULL, *secengineid = NULL; |
|
size_t ctxengineidlen, secengineidlen; |
|
int zflag = 0; |
|
long long boots, time; |
char optstr[BUFSIZ]; |
char optstr[BUFSIZ]; |
const char *errstr; |
const char *errstr; |
char *strtolp; |
char *strtolp; |
|
|
case 'c': |
case 'c': |
community = optarg; |
community = optarg; |
break; |
break; |
|
case 'E': |
|
ctxengineid = snmpc_hex2bin(optarg, |
|
&ctxengineidlen); |
|
if (ctxengineid == NULL) { |
|
if (errno == EINVAL) |
|
errx(1, "Bad engine ID value " |
|
"after -3E flag."); |
|
err(1, "-3E"); |
|
} |
|
break; |
|
case 'e': |
|
secengineid = snmpc_hex2bin(optarg, |
|
&secengineidlen); |
|
if (secengineid == NULL) { |
|
if (errno == EINVAL) |
|
errx(1, "Bad engine ID value " |
|
"after -3e flag."); |
|
err(1, "-3e"); |
|
} |
|
break; |
|
case 'n': |
|
ctxname = optarg; |
|
break; |
case 'r': |
case 'r': |
if ((retries = strtonum(optarg, 0, INT_MAX, |
if ((retries = strtonum(optarg, 0, INT_MAX, |
&errstr)) == 0) { |
&errstr)) == 0) { |
|
|
errx(1, "-t: %s argument", errstr); |
errx(1, "-t: %s argument", errstr); |
} |
} |
break; |
break; |
|
case 'u': |
|
user = optarg; |
|
break; |
case 'v': |
case 'v': |
if (strcmp(optarg, "1") == 0) |
if (strcmp(optarg, "1") == 0) |
version = SNMP_V1; |
version = SNMP_V1; |
else if (strcmp(optarg, "2c") == 0) |
else if (strcmp(optarg, "2c") == 0) |
version = SNMP_V2C; |
version = SNMP_V2C; |
|
else if (strcmp(optarg, "3") == 0) |
|
version = SNMP_V3; |
else |
else |
errc(1, EINVAL, "-v"); |
errc(1, EINVAL, "-v"); |
break; |
break; |
|
|
} |
} |
} |
} |
break; |
break; |
|
case 'Z': |
|
boots = strtoll(optarg, &strtolp, 10); |
|
if (boots < 0 || strtolp == optarg || strtolp[0] != ',') |
|
usage(); |
|
strtolp++; |
|
while (strtolp[0] == ' ' && strtolp[0] == '\t') |
|
strtolp++; |
|
time = strtoll(strtolp, &strtolp, 10); |
|
if (boots < 0 || strtolp == optarg) |
|
usage(); |
|
zflag = 1; |
|
break; |
default: |
default: |
usage(); |
usage(); |
} |
} |
|
|
argc -= optind; |
argc -= optind; |
argv += optind; |
argv += optind; |
|
|
|
if (version == SNMP_V3) { |
|
/* Setup USM */ |
|
if (user == NULL || user[0] == '\0') |
|
errx(1, "No securityName specified"); |
|
if ((sec = usm_init(user, strlen(user))) == NULL) |
|
err(1, "usm_init"); |
|
if (secengineid != NULL) { |
|
if (usm_setengineid(sec, secengineid, |
|
secengineidlen) == -1) |
|
err(1, "Can't set secengineid"); |
|
} |
|
if (zflag) |
|
if (usm_setbootstime(sec, boots, time) == -1) |
|
err(1, "Can't set boots/time"); |
|
v3 = snmp_v3_init(seclevel, ctxname, ctxname == NULL ? 0 : |
|
strlen(ctxname), sec); |
|
if (v3 == NULL) |
|
err(1, "snmp_v3_init"); |
|
if (ctxengineid != NULL) { |
|
if (snmp_v3_setengineid(v3, ctxengineid, |
|
ctxengineidlen) == -1) |
|
err(1, "Can't set ctxengineid"); |
|
} |
|
} |
|
|
|
|
return snmp_app->exec(argc, argv); |
return snmp_app->exec(argc, argv); |
} |
} |
|
|
|
|
struct snmp_agent *agent; |
struct snmp_agent *agent; |
int errorstatus, errorindex; |
int errorstatus, errorindex; |
int i; |
int i; |
|
int class; |
|
unsigned type; |
|
|
if (argc < 2) |
if (argc < 2) |
usage(); |
usage(); |
|
|
err(1, "get"); |
err(1, "get"); |
} |
} |
|
|
(void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus, &errorindex, |
(void) ber_scanf_elements(pdu, "t{Sdd{e", &class, &type, &errorstatus, |
&varbind); |
&errorindex, &varbind); |
if (errorstatus != 0) |
if (errorstatus != 0) |
snmpc_printerror((enum snmp_error) errorstatus, |
snmpc_printerror((enum snmp_error) errorstatus, |
argv[errorindex - 1]); |
argv[errorindex - 1]); |
|
|
|
if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) |
|
printf("Received report:\n"); |
for (; varbind != NULL; varbind = varbind->be_next) { |
for (; varbind != NULL; varbind = varbind->be_next) { |
if (!snmpc_print(varbind)) |
if (!snmpc_print(varbind)) |
err(1, "Can't print response"); |
err(1, "Can't print response"); |
|
|
char oidstr[SNMP_MAX_OID_STRLEN]; |
char oidstr[SNMP_MAX_OID_STRLEN]; |
int n = 0, prev_cmp; |
int n = 0, prev_cmp; |
int errorstatus, errorindex; |
int errorstatus, errorindex; |
|
int class; |
|
unsigned type; |
|
|
if (strcmp(snmp_app->name, "bulkwalk") == 0 && version < SNMP_V2C) |
if (strcmp(snmp_app->name, "bulkwalk") == 0 && version < SNMP_V2C) |
errx(1, "Cannot send V2 PDU on V1 session"); |
errx(1, "Cannot send V2 PDU on V1 session"); |
|
|
if ((pdu = snmp_get(agent, &oid, 1)) == NULL) |
if ((pdu = snmp_get(agent, &oid, 1)) == NULL) |
err(1, "%s", snmp_app->name); |
err(1, "%s", snmp_app->name); |
|
|
(void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus, |
(void) ber_scanf_elements(pdu, "t{Sdd{e", &class, &type, |
&errorindex, &varbind); |
&errorstatus, &errorindex, &varbind); |
if (errorstatus != 0) |
if (errorstatus != 0) |
snmpc_printerror((enum snmp_error) errorstatus, |
snmpc_printerror((enum snmp_error) errorstatus, |
argv[errorindex - 1]); |
argv[errorindex - 1]); |
|
|
|
if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) |
|
printf("Received report:\n"); |
if (!snmpc_print(varbind)) |
if (!snmpc_print(varbind)) |
err(1, "Can't print response"); |
err(1, "Can't print response"); |
ber_free_element(pdu); |
ber_free_element(pdu); |
|
if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) |
|
return 1; |
n++; |
n++; |
} |
} |
while (1) { |
while (1) { |
|
|
err(1, "walk"); |
err(1, "walk"); |
} |
} |
|
|
(void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus, |
(void) ber_scanf_elements(pdu, "t{Sdd{e", &class, &type, |
&errorindex, &varbind); |
&errorstatus, &errorindex, &varbind); |
if (errorstatus != 0) { |
if (errorstatus != 0) { |
smi_oid2string(&noid, oidstr, sizeof(oidstr), |
smi_oid2string(&noid, oidstr, sizeof(oidstr), |
oid_lookup); |
oid_lookup); |
snmpc_printerror((enum snmp_error) errorstatus, oidstr); |
snmpc_printerror((enum snmp_error) errorstatus, oidstr); |
} |
} |
|
|
|
if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) |
|
printf("Received report:\n"); |
for (; varbind != NULL; varbind = varbind->be_next) { |
for (; varbind != NULL; varbind = varbind->be_next) { |
(void) ber_scanf_elements(varbind, "{oe}", &noid, |
(void) ber_scanf_elements(varbind, "{oe}", &noid, |
&value); |
&value); |
|
|
n++; |
n++; |
} |
} |
ber_free_elements(pdu); |
ber_free_elements(pdu); |
|
if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) |
|
return 1; |
if (varbind != NULL) |
if (varbind != NULL) |
break; |
break; |
} |
} |
|
|
if ((pdu = snmp_get(agent, &oid, 1)) == NULL) |
if ((pdu = snmp_get(agent, &oid, 1)) == NULL) |
err(1, "%s", snmp_app->name); |
err(1, "%s", snmp_app->name); |
|
|
(void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus, |
(void) ber_scanf_elements(pdu, "t{Sdd{e", &class, &type, |
&errorindex, &varbind); |
&errorstatus, &errorindex, &varbind); |
if (errorstatus != 0) |
if (errorstatus != 0) |
snmpc_printerror((enum snmp_error) errorstatus, |
snmpc_printerror((enum snmp_error) errorstatus, |
argv[errorindex - 1]); |
argv[errorindex - 1]); |
|
|
|
if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) |
|
printf("Received report:\n"); |
if (!snmpc_print(varbind)) |
if (!snmpc_print(varbind)) |
err(1, "Can't print response"); |
err(1, "Can't print response"); |
ber_free_element(pdu); |
ber_free_element(pdu); |
|
if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) |
|
return 1; |
n++; |
n++; |
} |
} |
if (print_time) |
if (print_time) |
|
|
case SNMP_V2C: |
case SNMP_V2C: |
return snmp_connect_v12(snmpc_parseagent(host, port), version, |
return snmp_connect_v12(snmpc_parseagent(host, port), version, |
community); |
community); |
|
case SNMP_V3: |
|
return snmp_connect_v3(snmpc_parseagent(host, port), v3); |
} |
} |
return NULL; |
return NULL; |
} |
} |
|
|
return s; |
return s; |
} |
} |
|
|
|
char * |
|
snmpc_hex2bin(char *hexstr, size_t *binlen) |
|
{ |
|
char *decstr; |
|
|
|
if (hexstr[0] == '0' && hexstr[1] == 'x') |
|
hexstr += 2; |
|
while (hexstr[0] == ' ' || hexstr[0] == '\t') |
|
hexstr++; |
|
|
|
if ((decstr = malloc((strlen(hexstr) / 2) + 1)) == NULL) |
|
return NULL; |
|
|
|
for (*binlen = 0; hexstr[0] != '\0'; (*binlen)++) { |
|
hexstr[0] = toupper(hexstr[0]); |
|
hexstr[1] = toupper(hexstr[1]); |
|
if (hexstr[0] >= '0' && hexstr[0] <= '9') |
|
decstr[*binlen] = (hexstr[0] - '0') << 4; |
|
else if (hexstr[0] >= 'A' && hexstr[0] <= 'F') |
|
decstr[*binlen] = ((hexstr[0] - 'A') + 10) << 4; |
|
else |
|
goto fail; |
|
if (hexstr[1] >= '0' && hexstr[1] <= '9') |
|
decstr[*binlen] |= (hexstr[1] - '0'); |
|
else if (hexstr[1] >= 'A' && hexstr[1] <= 'F') |
|
decstr[*binlen] |= (hexstr[1] - 'A') + 10; |
|
else |
|
goto fail; |
|
|
|
hexstr += 2; |
|
while (hexstr[0] == ' ' || hexstr[0] == '\t') |
|
hexstr++; |
|
} |
|
|
|
return decstr; |
|
fail: |
|
errno = EINVAL; |
|
free(decstr); |
|
return NULL; |
|
} |
|
|
__dead void |
__dead void |
usage(void) |
usage(void) |
{ |
{ |
size_t i; |
size_t i; |
|
|
if (snmp_app != NULL) { |
if (snmp_app != NULL) { |
fprintf(stderr, "usage: snmp %s%s%s%s\n", |
fprintf(stderr, "usage: snmp %s%s%s\n", |
snmp_app->name, |
snmp_app->name, |
snmp_app->usecommonopt ? |
snmp_app->usecommonopt ? |
" [-c community] [-r retries] [-t timeout] [-v version]\n" |
" [-c community] [-e secengineid] [-E ctxengineid] [-n ctxname]\n" |
" [-O afnqvxSQ]" : "", |
" [-O afnqvxSQ] [-r retries] [-t timeout] [-u user] [-v version]\n" |
snmp_app->usage == NULL ? "" : " ", |
" [-Z boots,time]\n" |
|
" " : "", |
snmp_app->usage == NULL ? "" : snmp_app->usage); |
snmp_app->usage == NULL ? "" : snmp_app->usage); |
exit(1); |
exit(1); |
} |
} |
|
|
fprintf(stderr, "snmp %s%s %s\n", |
fprintf(stderr, "snmp %s%s %s\n", |
snmp_apps[i].name, |
snmp_apps[i].name, |
snmp_apps[i].usecommonopt ? |
snmp_apps[i].usecommonopt ? |
" [-c community] [-r retries] [-t timeout] [-v version]\n" |
" [common options]" : "", |
" [-O afnqvxSQ]" : "", |
|
snmp_apps[i].usage ? snmp_apps[i].usage : ""); |
snmp_apps[i].usage ? snmp_apps[i].usage : ""); |
} |
} |
exit(1); |
exit(1); |