{
char *name;
char *address;
- char *community;
int version;
+
+ /* snmpv1/2 options */
+ char *community;
+
+ /* snmpv3 security options */
+ char *username;
+ oid *auth_protocol;
+ size_t auth_protocol_len;
+ char *auth_passphrase;
+ oid *priv_protocol;
+ size_t priv_protocol_len;
+ char *priv_passphrase;
+ int security_level;
+ char *context;
+
void *sess_handle;
c_complain_t complaint;
cdtime_t interval;
*/
static void csnmp_oid_init (oid_t *dst, oid const *src, size_t n)
{
- assert (n <= STATIC_ARRAY_LEN (dst->oid));
+ assert (n <= STATIC_ARRAY_SIZE (dst->oid));
memcpy (dst->oid, src, sizeof (*src) * n);
dst->oid_len = n;
}
sfree (hd->name);
sfree (hd->address);
sfree (hd->community);
+ sfree (hd->username);
+ sfree (hd->auth_passphrase);
+ sfree (hd->priv_passphrase);
+ sfree (hd->context);
sfree (hd->data_list);
sfree (hd);
* +-> csnmp_config_add_host_community
* +-> csnmp_config_add_host_version
* +-> csnmp_config_add_host_collect
+ * +-> csnmp_config_add_host_username
+ * +-> csnmp_config_add_host_auth_protocol
+ * +-> csnmp_config_add_host_priv_protocol
+ * +-> csnmp_config_add_host_auth_passphrase
+ * +-> csnmp_config_add_host_priv_passphrase
+ * +-> csnmp_config_add_host_security_level
+ * +-> esnmp_config_add_host_context
*/
static void call_snmp_init_once (void)
{
}
version = (int) ci->values[0].value.number;
- if ((version != 1) && (version != 2))
+ if ((version < 1) || (version > 3))
{
- WARNING ("snmp plugin: `Version' must either be `1' or `2'.");
+ WARNING ("snmp plugin: `Version' must either be `1', `2', or `3'.");
return (-1);
}
return (0);
} /* int csnmp_config_add_host_collect */
+static int csnmp_config_add_host_username (host_definition_t *hd, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("snmp plugin: The `Username' config option needs exactly one string argument.");
+ return (-1);
+ }
+
+ free (hd->username);
+ hd->username = strdup (ci->values[0].value.string);
+ if (hd->username == NULL)
+ return (-1);
+
+ DEBUG ("snmp plugin: host = %s; host->username = %s;",
+ hd->name, hd->username);
+
+ return (0);
+} /* int csnmp_config_add_host_username */
+
+static int csnmp_config_add_host_auth_protocol (host_definition_t *hd, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING)
+ || ((strcasecmp("MD5", ci->values[0].value.string) != 0)
+ && (strcasecmp("SHA", ci->values[0].value.string) != 0)))
+ {
+ WARNING ("snmp plugin: The `AuthProtocol' config option must be `MD5' or `SHA'.");
+ return (-1);
+ }
+
+ if (strcasecmp("MD5", ci->values[0].value.string) == 0) {
+ hd->auth_protocol = usmHMACMD5AuthProtocol;
+ hd->auth_protocol_len = sizeof(usmHMACMD5AuthProtocol)/sizeof(oid);
+ }
+ else if (strcasecmp("SHA", ci->values[0].value.string) == 0) {
+ hd->auth_protocol = usmHMACSHA1AuthProtocol;
+ hd->auth_protocol_len = sizeof(usmHMACSHA1AuthProtocol)/sizeof(oid);
+ }
+
+ DEBUG ("snmp plugin: host = %s; host->auth_protocol = %s;",
+ hd->name, hd->auth_protocol == usmHMACMD5AuthProtocol ? "MD5" : "SHA");
+
+ return (0);
+} /* int csnmp_config_add_host_auth_protocol */
+
+static int csnmp_config_add_host_priv_protocol (host_definition_t *hd, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING)
+ || ((strcasecmp("AES", ci->values[0].value.string) != 0)
+ && (strcasecmp("DES", ci->values[0].value.string) != 0)))
+ {
+ WARNING ("snmp plugin: The `PrivProtocol' config option must be `AES' or `DES'.");
+ return (-1);
+ }
+
+ if (strcasecmp("AES", ci->values[0].value.string) == 0) {
+ hd->priv_protocol = usmAESPrivProtocol;
+ hd->priv_protocol_len = sizeof(usmAESPrivProtocol)/sizeof(oid);
+ }
+ else if (strcasecmp("DES", ci->values[0].value.string) == 0) {
+ hd->priv_protocol = usmDESPrivProtocol;
+ hd->priv_protocol_len = sizeof(usmDESPrivProtocol)/sizeof(oid);
+ }
+
+ DEBUG ("snmp plugin: host = %s; host->priv_protocol = %s;",
+ hd->name, hd->priv_protocol == usmAESPrivProtocol ? "AES" : "DES");
+
+ return (0);
+} /* int csnmp_config_add_host_priv_protocol */
+
+static int csnmp_config_add_host_auth_passphrase (host_definition_t *hd, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("snmp plugin: The `AuthPassphrase' config option needs exactly one string argument.");
+ return (-1);
+ }
+
+ free (hd->auth_passphrase);
+ hd->auth_passphrase = strdup (ci->values[0].value.string);
+ if (hd->auth_passphrase == NULL)
+ return (-1);
+
+ DEBUG ("snmp plugin: host = %s; host->auth_passphrase = %s;",
+ hd->name, hd->auth_passphrase);
+
+ return (0);
+} /* int csnmp_config_add_host_auth_passphrase */
+
+static int csnmp_config_add_host_priv_passphrase (host_definition_t *hd, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("snmp plugin: The `PrivacyPassphrase' config option needs exactly one string argument.");
+ return (-1);
+ }
+
+ free (hd->priv_passphrase);
+ hd->priv_passphrase = strdup (ci->values[0].value.string);
+ if (hd->priv_passphrase == NULL)
+ return (-1);
+
+ DEBUG ("snmp plugin: host = %s; host->priv_passphrase = %s;",
+ hd->name, hd->priv_passphrase);
+
+ return (0);
+} /* int csnmp_config_add_host_priv_passphrase */
+
+static int csnmp_config_add_host_security_level (host_definition_t *hd, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING)
+ || ((strcasecmp("noAuthNoPriv", ci->values[0].value.string) != 0)
+ && (strcasecmp("authNoPriv", ci->values[0].value.string) != 0)
+ && (strcasecmp("authPriv", ci->values[0].value.string) != 0)))
+ {
+ WARNING ("snmp plugin: The `SecurityLevel' config option must be `noAuthNoPriv', `authNoPriv', or `authPriv'.");
+ return (-1);
+ }
+
+ if (strcasecmp("noAuthNoPriv", ci->values[0].value.string) == 0)
+ hd->security_level = SNMP_SEC_LEVEL_NOAUTH;
+ else if (strcasecmp("authNoPriv", ci->values[0].value.string) == 0)
+ hd->security_level = SNMP_SEC_LEVEL_AUTHNOPRIV;
+ else if (strcasecmp("authPriv", ci->values[0].value.string) == 0)
+ hd->security_level = SNMP_SEC_LEVEL_AUTHPRIV;
+
+ DEBUG ("snmp plugin: host = %s; host->security_level = %d;",
+ hd->name, hd->security_level);
+
+ return (0);
+} /* int csnmp_config_add_host_security_level */
+
+static int csnmp_config_add_host_context (host_definition_t *hd, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("snmp plugin: The `Context' config option needs exactly one string argument.");
+ return (-1);
+ }
+
+ free (hd->context);
+ hd->context = strdup (ci->values[0].value.string);
+ if (hd->context == NULL)
+ return (-1);
+
+ DEBUG ("snmp plugin: host = %s; host->context = %s;",
+ hd->name, hd->context);
+
+ return (0);
+} /* int csnmp_config_add_host_context */
+
+// fooooo
+
static int csnmp_config_add_host (oconfig_item_t *ci)
{
host_definition_t *hd;
csnmp_config_add_host_collect (hd, option);
else if (strcasecmp ("Interval", option->key) == 0)
cf_util_get_cdtime (option, &hd->interval);
+ else if (strcasecmp ("Username", option->key) == 0)
+ status = csnmp_config_add_host_username (hd, option);
+ else if (strcasecmp ("AuthProtocol", option->key) == 0)
+ status = csnmp_config_add_host_auth_protocol (hd, option);
+ else if (strcasecmp ("PrivacyProtocol", option->key) == 0)
+ status = csnmp_config_add_host_priv_protocol (hd, option);
+ else if (strcasecmp ("AuthPassphrase", option->key) == 0)
+ status = csnmp_config_add_host_auth_passphrase (hd, option);
+ else if (strcasecmp ("PrivacyPassphrase", option->key) == 0)
+ status = csnmp_config_add_host_priv_passphrase (hd, option);
+ else if (strcasecmp ("SecurityLevel", option->key) == 0)
+ status = csnmp_config_add_host_security_level (hd, option);
+ else if (strcasecmp ("Context", option->key) == 0)
+ status = csnmp_config_add_host_context (hd, option);
else
{
WARNING ("snmp plugin: csnmp_config_add_host: Option `%s' not allowed here.", option->key);
status = -1;
break;
}
- if (hd->community == NULL)
+ if (hd->community == NULL && hd->version < 3)
{
WARNING ("snmp plugin: `Community' not given for host `%s'", hd->name);
status = -1;
break;
}
+ if (hd->version == 3)
+ {
+ if (hd->username == NULL)
+ {
+ WARNING ("snmp plugin: `Username' not given for host `%s'", hd->name);
+ status = -1;
+ break;
+ }
+ if (hd->security_level == 0)
+ {
+ WARNING ("snmp plugin: `SecurityLevel' not given for host `%s'", hd->name);
+ status = -1;
+ break;
+ }
+ if (hd->security_level == SNMP_SEC_LEVEL_AUTHNOPRIV || hd->security_level == SNMP_SEC_LEVEL_AUTHPRIV)
+ {
+ if (hd->auth_protocol == NULL)
+ {
+ WARNING ("snmp plugin: `AuthProtocol' not given for host `%s'", hd->name);
+ status = -1;
+ break;
+ }
+ if (hd->auth_passphrase == NULL)
+ {
+ WARNING ("snmp plugin: `AuthPassphrase' not given for host `%s'", hd->name);
+ status = -1;
+ break;
+ }
+ }
+ if (hd->security_level == SNMP_SEC_LEVEL_AUTHPRIV)
+ {
+ if (hd->priv_protocol == NULL)
+ {
+ WARNING ("snmp plugin: `PrivacyProtocol' not given for host `%s'", hd->name);
+ status = -1;
+ break;
+ }
+ if (hd->priv_passphrase == NULL)
+ {
+ WARNING ("snmp plugin: `PrivacyPassphrase' not given for host `%s'", hd->name);
+ status = -1;
+ break;
+ }
+ }
+ }
break;
} /* while (status == 0) */
static void csnmp_host_open_session (host_definition_t *host)
{
struct snmp_session sess;
+ int error;
if (host->sess_handle != NULL)
csnmp_host_close_session (host);
snmp_sess_init (&sess);
sess.peername = host->address;
- sess.community = (u_char *) host->community;
- sess.community_len = strlen (host->community);
- sess.version = (host->version == 1) ? SNMP_VERSION_1 : SNMP_VERSION_2c;
+ switch (host->version)
+ {
+ case 1:
+ sess.version = SNMP_VERSION_1;
+ break;
+ case 3:
+ sess.version = SNMP_VERSION_3;
+ break;
+ default:
+ sess.version = SNMP_VERSION_2c;
+ break;
+ }
+
+ if (host->version == 3)
+ {
+ sess.securityName = host->username;
+ sess.securityNameLen = strlen (host->username);
+ sess.securityLevel = host->security_level;
+
+ if (sess.securityLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || sess.securityLevel == SNMP_SEC_LEVEL_AUTHPRIV)
+ {
+ sess.securityAuthProto = host->auth_protocol;
+ sess.securityAuthProtoLen = host->auth_protocol_len;
+ sess.securityAuthKeyLen = USM_AUTH_KU_LEN;
+ error = generate_Ku (sess.securityAuthProto,
+ sess.securityAuthProtoLen,
+ (u_char *) host->auth_passphrase,
+ strlen(host->auth_passphrase),
+ sess.securityAuthKey,
+ &sess.securityAuthKeyLen);
+ if (error != SNMPERR_SUCCESS) {
+ ERROR ("snmp plugin: host %s: Error generating Ku from auth_passphrase. (Error %d)", host->name, error);
+ }
+ }
+
+ if (sess.securityLevel == SNMP_SEC_LEVEL_AUTHPRIV)
+ {
+ sess.securityPrivProto = host->priv_protocol;
+ sess.securityPrivProtoLen = host->priv_protocol_len;
+ sess.securityPrivKeyLen = USM_PRIV_KU_LEN;
+ error = generate_Ku (sess.securityAuthProto,
+ sess.securityAuthProtoLen,
+ (u_char *) host->priv_passphrase,
+ strlen(host->priv_passphrase),
+ sess.securityPrivKey,
+ &sess.securityPrivKeyLen);
+ if (error != SNMPERR_SUCCESS) {
+ ERROR ("snmp plugin: host %s: Error generating Ku from priv_passphrase. (Error %d)", host->name, error);
+ }
+ }
+
+ if (host->context != NULL)
+ {
+ sess.contextName = host->context;
+ sess.contextNameLen = strlen (host->context);
+ }
+ }
+ else /* SNMPv1/2 "authenticates" with community string */
+ {
+ sess.community = (u_char *) host->community;
+ sess.community_len = strlen (host->community);
+ }
/* snmp_sess_open will copy the `struct snmp_session *'. */
host->sess_handle = snmp_sess_open (&sess);
struct variable_list *vb;
const data_set_t *ds;
- oid_t *oid_list;
- uint32_t oid_list_len;
+
+ uint32_t oid_list_len = (uint32_t) (data->values_len + 1);
+ /* Holds the last OID returned by the device. We use this in the GETNEXT
+ * request to proceed. */
+ oid_t oid_list[oid_list_len];
+ /* Set to false when an OID has left its subtree so we don't re-request it
+ * again. */
+ _Bool oid_list_todo[oid_list_len];
int status;
- int i, j;
+ int i;
+ uint32_t j;
/* `value_list_head' and `value_list_tail' implement a linked list for each
* value. `instance_list_head' and `instance_list_tail' implement a linked list of
}
/* We need a copy of all the OIDs, because GETNEXT will destroy them. */
- oid_list_len = data->values_len + 1;
- oid_list = (oid_t *) malloc (sizeof (oid_t) * (oid_list_len));
- if (oid_list == NULL)
- {
- ERROR ("snmp plugin: csnmp_read_table: malloc failed.");
- return (-1);
- }
memcpy (oid_list, data->values, data->values_len * sizeof (oid_t));
if (data->instance.oid.oid_len > 0)
memcpy (oid_list + data->values_len, &data->instance.oid, sizeof (oid_t));
- else
+ else /* no InstanceFrom option specified. */
oid_list_len--;
- /* We also need a 0(=finished)|1(=todo) mask for a todo list */
- int oid_todo_list[oid_list_len];
- for (i=0;i<oid_list_len;i++)
- oid_todo_list[i] = 1;
+ for (j = 0; j < oid_list_len; j++)
+ oid_list_todo[j] = 1;
/* We're going to construct n linked lists, one for each "value".
* value_list_head will contain pointers to the heads of these linked lists,
if ((value_list_head == NULL) || (value_list_tail == NULL))
{
ERROR ("snmp plugin: csnmp_read_table: calloc failed.");
- sfree (oid_list);
sfree (value_list_head);
sfree (value_list_tail);
return (-1);
status = 0;
while (status == 0)
{
+ int oid_list_todo_num;
+
req = snmp_pdu_create (SNMP_MSG_GETNEXT);
if (req == NULL)
{
break;
}
- for (i = 0, j = 0; (uint32_t) i < oid_list_len; i++) {
+ oid_list_todo_num = 0;
+ for (j = 0; j < oid_list_len; j++)
+ {
/* Do not rerequest already finished OIDs */
- if ( oid_todo_list[i] == 0 )
+ if (!oid_list_todo[j])
continue;
- j++;
- snmp_add_null_var (req, oid_list[i].oid, oid_list[i].oid_len);
+ oid_list_todo_num++;
+ snmp_add_null_var (req, oid_list[j].oid, oid_list[j].oid_len);
}
- if ( j == 0 ) {
+ if (oid_list_todo_num == 0)
+ {
/* The request is still empty - so we are finished */
DEBUG ("snmp plugin: all variables have left their subtree");
status = 0;
res = NULL;
status = snmp_sess_synch_response (host->sess_handle, req, &res);
-
if ((status != STAT_SUCCESS) || (res == NULL))
{
char *errstr = NULL;
status = -1;
break;
}
+
status = 0;
assert (res != NULL);
c_release (LOG_INFO, &host->complaint,
for (vb = res->variables, i = 0; (vb != NULL); vb = vb->next_variable, i++)
{
/* Calculate value index from todo list */
- while(oid_todo_list[i] == 0 && i < oid_list_len)
+ while (!oid_list_todo[i] && (i < oid_list_len))
i++;
- /* An instance is configured and the res variable we process is the instance value (last index) */
- if (data->instance.oid.oid_len > 0 && i == data->values_len) {
-
- if ((vb->type == SNMP_ENDOFMIBVIEW)
- || (snmp_oid_ncompare (data->instance.oid.oid,
- data->instance.oid.oid_len,
- vb->name, vb->name_length,
- data->instance.oid.oid_len) != 0))
+ /* An instance is configured and the res variable we process is the
+ * instance value (last index) */
+ if ((data->instance.oid.oid_len > 0) && (i == data->values_len))
{
- DEBUG ("snmp plugin: host = %s; data = %s; Instance left its subtree.",
- host->name, data->name);
- oid_todo_list[i] = 0;
- continue;
- }
+ if ((vb->type == SNMP_ENDOFMIBVIEW)
+ || (snmp_oid_ncompare (data->instance.oid.oid,
+ data->instance.oid.oid_len,
+ vb->name, vb->name_length,
+ data->instance.oid.oid_len) != 0))
+ {
+ DEBUG ("snmp plugin: host = %s; data = %s; Instance left its subtree.",
+ host->name, data->name);
+ oid_list_todo[i] = 0;
+ continue;
+ }
- /* Allocate a new `csnmp_list_instances_t', insert the instance name and
- * add it to the list */
- if (csnmp_instance_list_add (&instance_list_head, &instance_list_tail,
- res, host, data) != 0)
- {
- ERROR ("snmp plugin: csnmp_instance_list_add failed.");
- status = -1;
- break;
+ /* Allocate a new `csnmp_list_instances_t', insert the instance name and
+ * add it to the list */
+ if (csnmp_instance_list_add (&instance_list_head, &instance_list_tail,
+ res, host, data) != 0)
+ {
+ ERROR ("snmp plugin: csnmp_instance_list_add failed.");
+ status = -1;
+ break;
+ }
}
-
- /* The variable we are processing is a normal value */
- } else {
-
+ else /* The variable we are processing is a normal value */
+ {
csnmp_table_values_t *vt;
oid_t vb_name;
oid_t suffix;
/* Calculate the current suffix. This is later used to check that the
* suffix is increasing. This also checks if we left the subtree */
- int ret;
- ret = csnmp_oid_suffix (&suffix, &vb_name, data->values + i);
- if (ret != 0)
+ status = csnmp_oid_suffix (&suffix, &vb_name, data->values + i);
+ if (status != 0)
{
DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
"Value probably left its subtree.",
host->name, data->name, i);
- oid_todo_list[i] = 0;
+ oid_list_todo[i] = 0;
continue;
- }
+ }
/* Make sure the OIDs returned by the agent are increasing. Otherwise our
* table matching algorithm will get confused. */
DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
"Suffix is not increasing.",
host->name, data->name, i);
- oid_todo_list[i] = 0;
+ oid_list_todo[i] = 0;
continue;
}
- vt = malloc (sizeof (*vt));
- if (vt == NULL)
- {
- ERROR ("snmp plugin: malloc failed.");
- status = -1;
- break;
- }
- memset (vt, 0, sizeof (*vt));
-
- vt->value = csnmp_value_list_to_value (vb, ds->ds[i].type,
- data->scale, data->shift, host->name, data->name);
- memcpy (&vt->suffix, &suffix, sizeof (vt->suffix));
- vt->next = NULL;
-
- if (value_list_tail[i] == NULL)
- value_list_head[i] = vt;
- else
- value_list_tail[i]->next = vt;
- value_list_tail[i] = vt;
+ vt = malloc (sizeof (*vt));
+ if (vt == NULL)
+ {
+ ERROR ("snmp plugin: malloc failed.");
+ status = -1;
+ break;
+ }
+ memset (vt, 0, sizeof (*vt));
+ vt->value = csnmp_value_list_to_value (vb, ds->ds[i].type,
+ data->scale, data->shift, host->name, data->name);
+ memcpy (&vt->suffix, &suffix, sizeof (vt->suffix));
+ vt->next = NULL;
+
+ if (value_list_tail[i] == NULL)
+ value_list_head[i] = vt;
+ else
+ value_list_tail[i]->next = vt;
+ value_list_tail[i] = vt;
}
+
/* Copy OID to oid_list[i] */
memcpy (oid_list[i].oid, vb->name, sizeof (oid) * vb->name_length);
oid_list[i].oid_len = vb->name_length;
sfree (value_list_head);
sfree (value_list_tail);
- sfree (oid_list);
return (0);
} /* int csnmp_read_table */
host = ud->data;
if (host->interval == 0)
- host->interval = interval_g;
+ host->interval = plugin_get_interval ();
time_start = cdtime ();
if ((time_end - time_start) > host->interval)
{
WARNING ("snmp plugin: Host `%s' should be queried every %.3f "
- "seconds, but reading all values takes %.3f seconds.",
- host->name,
- CDTIME_T_TO_DOUBLE (host->interval),
- CDTIME_T_TO_DOUBLE (time_end - time_start));
+ "seconds, but reading all values takes %.3f seconds.",
+ host->name,
+ CDTIME_T_TO_DOUBLE (host->interval),
+ CDTIME_T_TO_DOUBLE (time_end - time_start));
}
if (success == 0)