diff options
Diffstat (limited to 'contrib/examples/snmp')
-rw-r--r-- | contrib/examples/snmp/snmp_example.c | 80 | ||||
-rw-r--r-- | contrib/examples/snmp/snmp_example.h | 43 | ||||
-rw-r--r-- | contrib/examples/snmp/snmp_private_mib/lwip_prvmib.c | 401 | ||||
-rw-r--r-- | contrib/examples/snmp/snmp_private_mib/private_mib.h | 26 | ||||
-rw-r--r-- | contrib/examples/snmp/snmp_v3/snmpv3_dummy.c | 395 | ||||
-rw-r--r-- | contrib/examples/snmp/snmp_v3/snmpv3_dummy.h | 53 |
6 files changed, 998 insertions, 0 deletions
diff --git a/contrib/examples/snmp/snmp_example.c b/contrib/examples/snmp/snmp_example.c new file mode 100644 index 00000000000..59524747980 --- /dev/null +++ b/contrib/examples/snmp/snmp_example.c @@ -0,0 +1,80 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier <dziegel@gmx.de> + * + */ + +#include "lwip/netif.h" +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_mib2.h" +#include "lwip/apps/snmpv3.h" +#include "lwip/apps/snmp_snmpv2_framework.h" +#include "lwip/apps/snmp_snmpv2_usm.h" +#include "examples/snmp/snmp_v3/snmpv3_dummy.h" +#include "examples/snmp/snmp_private_mib/private_mib.h" +#include "snmp_example.h" + +#if LWIP_SNMP +static const struct snmp_mib *mibs[] = { + &mib2, + &mib_private +#if LWIP_SNMP_V3 + , &snmpframeworkmib + , &snmpusmmib +#endif +}; +#endif /* LWIP_SNMP */ + +void +snmp_example_init(void) +{ +#if LWIP_SNMP + s32_t req_nr; + lwip_privmib_init(); +#if SNMP_LWIP_MIB2 +#if SNMP_USE_NETCONN + snmp_threadsync_init(&snmp_mib2_lwip_locks, snmp_mib2_lwip_synchronizer); +#endif /* SNMP_USE_NETCONN */ + snmp_mib2_set_syscontact_readonly((const u8_t*)"root", NULL); + snmp_mib2_set_syslocation_readonly((const u8_t*)"lwIP development PC", NULL); + snmp_mib2_set_sysdescr((const u8_t*)"lwIP example", NULL); +#endif /* SNMP_LWIP_MIB2 */ + +#if LWIP_SNMP_V3 + snmpv3_dummy_init(); +#endif + + snmp_set_mibs(mibs, LWIP_ARRAYSIZE(mibs)); + snmp_init(); + + snmp_trap_dst_ip_set(0, &netif_default->gw); + snmp_trap_dst_enable(0, 1); + + snmp_send_inform_generic(SNMP_GENTRAP_COLDSTART, NULL, &req_nr); + snmp_send_trap_generic(SNMP_GENTRAP_COLDSTART); + +#endif /* LWIP_SNMP */ +} diff --git a/contrib/examples/snmp/snmp_example.h b/contrib/examples/snmp/snmp_example.h new file mode 100644 index 00000000000..fafcd68f2b1 --- /dev/null +++ b/contrib/examples/snmp/snmp_example.h @@ -0,0 +1,43 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier <dziegel@gmx.de> + * + */ + +#ifndef SNMP_EXAMPLE_H +#define SNMP_EXAMPLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void snmp_example_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SNMP_EXAMPLE_H */ diff --git a/contrib/examples/snmp/snmp_private_mib/lwip_prvmib.c b/contrib/examples/snmp/snmp_private_mib/lwip_prvmib.c new file mode 100644 index 00000000000..51a49fe158a --- /dev/null +++ b/contrib/examples/snmp/snmp_private_mib/lwip_prvmib.c @@ -0,0 +1,401 @@ +/** + * @file + * lwip Private MIB + * + * @todo create MIB file for this example + * @note the lwip enterprise tree root (26381) is owned by the lwIP project. + * It is NOT allowed to allocate new objects under this ID (26381) without our, + * the lwip developers, permission! + * + * Please apply for your own ID with IANA: http://www.iana.org/numbers.html + * + * lwip OBJECT IDENTIFIER ::= { enterprises 26381 } + * example OBJECT IDENTIFIER ::= { lwip 1 } + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons <christiaan.simons@axon.tv> + */ + +#include "private_mib.h" + +#if LWIP_SNMP + +/** Directory where the sensor files are */ +#define SENSORS_DIR "w:\\sensors" +/** Set to 1 to read sensor values from files (in directory defined by SENSORS_DIR) */ +#define SENSORS_USE_FILES 0 +/** Set to 1 to search sensor files at startup (in directory defined by SENSORS_DIR) */ +#define SENSORS_SEARCH_FILES 0 + +#if SENSORS_SEARCH_FILES +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#endif /* SENSORS_SEARCH_FILES */ + +#include <string.h> +#include <stdio.h> + +#include "lwip/apps/snmp_table.h" +#include "lwip/apps/snmp_scalar.h" + +#if !SENSORS_USE_FILES || !SENSORS_SEARCH_FILES +/** When not using & searching files, defines the number of sensors */ +#define SENSOR_COUNT 4 +#endif /* !SENSORS_USE_FILES || !SENSORS_SEARCH_FILES */ + +/* + This example presents a table for a few (at most 10) sensors. + Sensor detection takes place at initialization (once only). + Sensors may and can not be added or removed after agent + has started. Note this is only a limitation of this crude example, + the agent does support dynamic object insertions and removals. + + You'll need to manually create a directory called "sensors" and + a few single line text files with an integer temperature value. + The files must be called [0..9].txt. + + ./sensors/0.txt [content: 20] + ./sensors/3.txt [content: 75] + + The sensor values may be changed in runtime by editing the + text files in the "sensors" directory. +*/ + +#define SENSOR_MAX 10 +#define SENSOR_NAME_LEN 20 + +struct sensor_inf +{ + u8_t num; + + char file[SENSOR_NAME_LEN + 1]; + +#if !SENSORS_USE_FILES + /** When not using files, contains the value of the sensor */ + s32_t value; +#endif /* !SENSORS_USE_FILES */ +}; + +static struct sensor_inf sensors[SENSOR_MAX]; + +static s16_t sensor_count_get_value(struct snmp_node_instance* instance, void* value); +static snmp_err_t sensor_table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance); +static snmp_err_t sensor_table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance); +static s16_t sensor_table_get_value(struct snmp_node_instance* instance, void* value); +static snmp_err_t sensor_table_set_value(struct snmp_node_instance* instance, u16_t len, void *value); + +/* sensorentry .1.3.6.1.4.1.26381.1.1.1 (.level0.level1) + where level 0 is the table column (temperature/file name) + and level 1 the table row (sensor index) */ +static const struct snmp_table_col_def sensor_table_columns[] = { + { 1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE }, + { 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY } +}; + +/* sensortable .1.3.6.1.4.1.26381.1.1 */ +static const struct snmp_table_node sensor_table = SNMP_TABLE_CREATE( + 1, sensor_table_columns, + sensor_table_get_cell_instance, sensor_table_get_next_cell_instance, + sensor_table_get_value, snmp_set_test_ok, sensor_table_set_value); + +/* sensorcount .1.3.6.1.4.1.26381.1.2 */ +static const struct snmp_scalar_node sensor_count = SNMP_SCALAR_CREATE_NODE_READONLY( + 2, SNMP_ASN1_TYPE_INTEGER, sensor_count_get_value); + +/* example .1.3.6.1.4.1.26381.1 */ +static const struct snmp_node* const example_nodes[] = { + &sensor_table.node.node, + &sensor_count.node.node +}; +static const struct snmp_tree_node example_node = SNMP_CREATE_TREE_NODE(1, example_nodes); + +static const u32_t prvmib_base_oid[] = { 1,3,6,1,4,1,26381,1 }; +const struct snmp_mib mib_private = SNMP_MIB_CREATE(prvmib_base_oid, &example_node.node); + +#if 0 +/* for reference: we could also have expressed it like this: */ + +/* lwip .1.3.6.1.4.1.26381 */ +static const struct snmp_node* const lwip_nodes[] = { + &example_node.node +}; +static const struct snmp_tree_node lwip_node = SNMP_CREATE_TREE_NODE(26381, lwip_nodes); + +/* enterprises .1.3.6.1.4.1 */ +static const struct snmp_node* const enterprises_nodes[] = { + &lwip_node.node +}; +static const struct snmp_tree_node enterprises_node = SNMP_CREATE_TREE_NODE(1, enterprises_nodes); + +/* private .1.3.6.1.4 */ +static const struct snmp_node* const private_nodes[] = { + &enterprises_node.node +}; +static const struct snmp_tree_node private_root = SNMP_CREATE_TREE_NODE(4, private_nodes); + +static const u32_t prvmib_base_oid[] = { 1,3,6,1,4 }; +const struct snmp_mib mib_private = SNMP_MIB_CREATE(prvmib_base_oid, &private_root.node); +#endif + +/** + * Initialises this private MIB before use. + * @see main.c + */ +void +lwip_privmib_init(void) +{ +#if SENSORS_USE_FILES && SENSORS_SEARCH_FILES + char *buf, *ebuf, *cp; + size_t bufsize; + int nbytes; + struct stat sb; + struct dirent *dp; + int fd; +#else /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */ + u8_t i; +#endif /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */ + + memset(sensors, 0, sizeof(sensors)); + + printf("SNMP private MIB start, detecting sensors.\n"); + +#if SENSORS_USE_FILES && SENSORS_SEARCH_FILES + /* look for sensors in sensors directory */ + fd = open(SENSORS_DIR, O_RDONLY); + if (fd > -1) + { + fstat(fd, &sb); + bufsize = sb.st_size; + if (bufsize < (size_t)sb.st_blksize) + { + bufsize = sb.st_blksize; + } + buf = (char*)malloc(bufsize); + if (buf != NULL) + { + do + { + long base; + + nbytes = getdirentries(fd, buf, bufsize, &base); + if (nbytes > 0) + { + ebuf = buf + nbytes; + cp = buf; + while (cp < ebuf) + { + dp = (struct dirent *)cp; + if (lwip_isdigit(dp->d_name[0])) + { + unsigned char idx = dp->d_name[0] - '0'; + + sensors[idx].num = idx+1; + strncpy(&sensors[idx].file[0], dp->d_name, SENSOR_NAME_LEN); + printf("%s\n", sensors[idx].file); + } + cp += dp->d_reclen; + } + } + } + while (nbytes > 0); + + free(buf); + } + close(fd); + } +#else /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */ + for (i = 0; i < SENSOR_COUNT; i++) { + sensors[i].num = (u8_t)(i + 1); + snprintf(sensors[i].file, sizeof(sensors[i].file), "%d.txt", i); + +#if !SENSORS_USE_FILES + /* initialize sensor value to != zero */ + sensors[i].value = 11 * (i+1); +#endif /* !SENSORS_USE_FILES */ + } +#endif /* SENSORS_USE_FILE && SENSORS_SEARCH_FILES */ +} + +/* sensorcount .1.3.6.1.4.1.26381.1.2 */ +static s16_t +sensor_count_get_value(struct snmp_node_instance* instance, void* value) +{ + size_t count = 0; + u32_t *uint_ptr = (u32_t*)value; + + LWIP_UNUSED_ARG(instance); + + for(count=0; count<LWIP_ARRAYSIZE(sensors); count++) { + if(sensors[count].num == 0) { + *uint_ptr = (u32_t)count; + return sizeof(*uint_ptr); + } + } + + return 0; +} + +/* sensortable .1.3.6.1.4.1.26381.1.1 */ +/* list of allowed value ranges for incoming OID */ +static const struct snmp_oid_range sensor_table_oid_ranges[] = { + { 1, SENSOR_MAX+1 } +}; + +static snmp_err_t +sensor_table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance) +{ + u32_t sensor_num; + size_t i; + + LWIP_UNUSED_ARG(column); + + /* check if incoming OID length and if values are in plausible range */ + if(!snmp_oid_in_range(row_oid, row_oid_len, sensor_table_oid_ranges, LWIP_ARRAYSIZE(sensor_table_oid_ranges))) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* get sensor index from incoming OID */ + sensor_num = row_oid[0]; + + /* find sensor with index */ + for(i=0; i<LWIP_ARRAYSIZE(sensors); i++) { + if(sensors[i].num != 0) { + if(sensors[i].num == sensor_num) { + /* store sensor index for subsequent operations (get/test/set) */ + cell_instance->reference.u32 = (u32_t)i; + return SNMP_ERR_NOERROR; + } + } + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static snmp_err_t +sensor_table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance) +{ + size_t i; + struct snmp_next_oid_state state; + u32_t result_temp[LWIP_ARRAYSIZE(sensor_table_oid_ranges)]; + + LWIP_UNUSED_ARG(column); + + /* init struct to search next oid */ + snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(sensor_table_oid_ranges)); + + /* iterate over all possible OIDs to find the next one */ + for(i=0; i<LWIP_ARRAYSIZE(sensors); i++) { + if(sensors[i].num != 0) { + u32_t test_oid[LWIP_ARRAYSIZE(sensor_table_oid_ranges)]; + + test_oid[0] = sensors[i].num; + + /* check generated OID: is it a candidate for the next one? */ + snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(sensor_table_oid_ranges), (void*)i); + } + } + + /* did we find a next one? */ + if(state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { + snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); + /* store sensor index for subsequent operations (get/test/set) */ + cell_instance->reference.u32 = LWIP_CONST_CAST(u32_t, state.reference); + return SNMP_ERR_NOERROR; + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static s16_t +sensor_table_get_value(struct snmp_node_instance* instance, void* value) +{ + u32_t i = instance->reference.u32; + s32_t *temperature = (s32_t *)value; + + switch (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id)) + { + case 1: /* sensor value */ +#if SENSORS_USE_FILES + FILE* sensf; + char senspath[sizeof(SENSORS_DIR)+1+SENSOR_NAME_LEN+1] = SENSORS_DIR"/"; + + strncpy(&senspath[sizeof(SENSORS_DIR)], + sensors[i].file, + SENSOR_NAME_LEN); + sensf = fopen(senspath,"r"); + if (sensf != NULL) + { + fscanf(sensf,"%"S32_F,temperature); + fclose(sensf); + } +#else /* SENSORS_USE_FILES */ + *temperature = sensors[i].value; +#endif /* SENSORS_USE_FILES */ + return sizeof(s32_t); + case 2: /* file name */ + MEMCPY(value, sensors[i].file, strlen(sensors[i].file)); + return (s16_t)strlen(sensors[i].file); + default: + return 0; + } +} + +static snmp_err_t +sensor_table_set_value(struct snmp_node_instance* instance, u16_t len, void *value) +{ + u32_t i = instance->reference.u32; + s32_t *temperature = (s32_t *)value; +#if SENSORS_USE_FILES + FILE* sensf; + char senspath[sizeof(SENSORS_DIR)+1+SENSOR_NAME_LEN+1] = SENSORS_DIR"/"; + + strncpy(&senspath[sizeof(SENSORS_DIR)], + sensors[i].file, + SENSOR_NAME_LEN); + sensf = fopen(senspath, "w"); + if (sensf != NULL) + { + fprintf(sensf, "%"S32_F, *temperature); + fclose(sensf); + } +#else /* SENSORS_USE_FILES */ + sensors[i].value = *temperature; +#endif /* SENSORS_USE_FILES */ + + LWIP_UNUSED_ARG(len); + + return SNMP_ERR_NOERROR; +} + +#endif /* LWIP_SNMP */ diff --git a/contrib/examples/snmp/snmp_private_mib/private_mib.h b/contrib/examples/snmp/snmp_private_mib/private_mib.h new file mode 100644 index 00000000000..69be8a4fc58 --- /dev/null +++ b/contrib/examples/snmp/snmp_private_mib/private_mib.h @@ -0,0 +1,26 @@ +/** + * @file + * Exports Private lwIP MIB + */ + +#ifndef LWIP_HDR_PRIVATE_MIB_H +#define LWIP_HDR_PRIVATE_MIB_H + +#include "lwip/apps/snmp_opts.h" + +#include "lwip/apps/snmp_core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* export MIB */ +extern const struct snmp_mib mib_private; + +void lwip_privmib_init(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/examples/snmp/snmp_v3/snmpv3_dummy.c b/contrib/examples/snmp/snmp_v3/snmpv3_dummy.c new file mode 100644 index 00000000000..a7c53ed73ac --- /dev/null +++ b/contrib/examples/snmp/snmp_v3/snmpv3_dummy.c @@ -0,0 +1,395 @@ +/** + * @file + * Dummy SNMPv3 functions. + */ + +/* + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Elias Oenal <lwip@eliasoenal.com> + * Dirk Ziegelmeier <dirk@ziegelmeier.net> + */ + +#include "lwip/apps/snmpv3.h" +#include "snmpv3_dummy.h" +#include <string.h> +#include "lwip/err.h" +#include "lwip/def.h" +#include "lwip/timeouts.h" + +#if LWIP_SNMP && LWIP_SNMP_V3 + +struct user_table_entry { + char username[32]; + snmpv3_auth_algo_t auth_algo; + u8_t auth_key[20]; + snmpv3_priv_algo_t priv_algo; + u8_t priv_key[20]; +}; + +static struct user_table_entry user_table[] = { + { "lwip", SNMP_V3_AUTH_ALGO_INVAL, "" , SNMP_V3_PRIV_ALGO_INVAL, "" }, + { "piwl", SNMP_V3_AUTH_ALGO_INVAL, "" , SNMP_V3_PRIV_ALGO_INVAL, "" }, + { "test", SNMP_V3_AUTH_ALGO_INVAL, "" , SNMP_V3_PRIV_ALGO_INVAL, "" } +}; + +static char snmpv3_engineid[32]; +static u8_t snmpv3_engineid_len; + +static u32_t enginetime = 0; + +/* In this implementation engineboots is volatile. In a real world application this value should be stored in non-volatile memory.*/ +static u32_t engineboots = 0; + +/** + * @brief Get the user table entry for the given username. + * + * @param[in] username pointer to the username + * + * @return pointer to the user table entry or NULL if not found. + */ +static struct user_table_entry* +get_user(const char *username) +{ + size_t i; + + for (i = 0; i < LWIP_ARRAYSIZE(user_table); i++) { + if (strnlen(username, 32) != strnlen(user_table[i].username, 32)) { + continue; + } + + if (memcmp(username, user_table[i].username, strnlen(username, 32)) == 0) { + return &user_table[i]; + } + } + + return NULL; +} + +u8_t +snmpv3_get_amount_of_users(void) +{ + return LWIP_ARRAYSIZE(user_table); +} + +/** + * @brief Get the username of a user number (index) + * @param username is a pointer to a string. + * @param index is the user index. + * @return ERR_OK if user is found, ERR_VAL is user is not found. + */ +err_t +snmpv3_get_username(char *username, u8_t index) +{ + if (index < LWIP_ARRAYSIZE(user_table)) { + MEMCPY(username, user_table[index].username, sizeof(user_table[0].username)); + return ERR_OK; + } + + return ERR_VAL; +} + +/** + * Timer callback function that increments enginetime and reschedules itself. + * + * @param arg unused argument + */ +static void +snmpv3_enginetime_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + + enginetime++; + + /* This handles the engine time reset */ + snmpv3_get_engine_time_internal(); + + /* restart timer */ + sys_timeout(1000, snmpv3_enginetime_timer, NULL); +} + +err_t +snmpv3_set_user_auth_algo(const char *username, snmpv3_auth_algo_t algo) +{ + struct user_table_entry *p = get_user(username); + + if (p) { + switch (algo) { + case SNMP_V3_AUTH_ALGO_INVAL: + if (p->priv_algo != SNMP_V3_PRIV_ALGO_INVAL) { + /* Privacy MUST be disabled before configuring authentication */ + break; + } else { + p->auth_algo = algo; + return ERR_OK; + } +#if LWIP_SNMP_V3_CRYPTO + case SNMP_V3_AUTH_ALGO_MD5: + case SNMP_V3_AUTH_ALGO_SHA: +#endif + p->auth_algo = algo; + return ERR_OK; + default: + break; + } + } + + return ERR_VAL; +} + +err_t +snmpv3_set_user_priv_algo(const char *username, snmpv3_priv_algo_t algo) +{ + struct user_table_entry *p = get_user(username); + + if (p) { + switch (algo) { +#if LWIP_SNMP_V3_CRYPTO + case SNMP_V3_PRIV_ALGO_AES: + case SNMP_V3_PRIV_ALGO_DES: + if (p->auth_algo == SNMP_V3_AUTH_ALGO_INVAL) { + /* Authentication MUST be enabled before configuring privacy */ + break; + } else { + p->priv_algo = algo; + return ERR_OK; + } +#endif + case SNMP_V3_PRIV_ALGO_INVAL: + p->priv_algo = algo; + return ERR_OK; + default: + break; + } + } + + return ERR_VAL; +} + +err_t +snmpv3_set_user_auth_key(const char *username, const char *password) +{ + struct user_table_entry *p = get_user(username); + const char *engineid; + u8_t engineid_len; + + if (p) { + /* password should be at least 8 characters long */ + if (strlen(password) >= 8) { + memset(p->auth_key, 0, sizeof(p->auth_key)); + snmpv3_get_engine_id(&engineid, &engineid_len); + switch (p->auth_algo) { + case SNMP_V3_AUTH_ALGO_INVAL: + return ERR_OK; +#if LWIP_SNMP_V3_CRYPTO + case SNMP_V3_AUTH_ALGO_MD5: + snmpv3_password_to_key_md5((const u8_t*)password, strlen(password), (const u8_t*)engineid, engineid_len, p->auth_key); + return ERR_OK; + case SNMP_V3_AUTH_ALGO_SHA: + snmpv3_password_to_key_sha((const u8_t*)password, strlen(password), (const u8_t*)engineid, engineid_len, p->auth_key); + return ERR_OK; +#endif + default: + return ERR_VAL; + } + } + } + + return ERR_VAL; +} + +err_t +snmpv3_set_user_priv_key(const char *username, const char *password) +{ + struct user_table_entry *p = get_user(username); + const char *engineid; + u8_t engineid_len; + + if (p) { + /* password should be at least 8 characters long */ + if (strlen(password) >= 8) { + memset(p->priv_key, 0, sizeof(p->priv_key)); + snmpv3_get_engine_id(&engineid, &engineid_len); + switch (p->auth_algo) { + case SNMP_V3_AUTH_ALGO_INVAL: + return ERR_OK; +#if LWIP_SNMP_V3_CRYPTO + case SNMP_V3_AUTH_ALGO_MD5: + snmpv3_password_to_key_md5((const u8_t*)password, strlen(password), (const u8_t*)engineid, engineid_len, p->priv_key); + return ERR_OK; + case SNMP_V3_AUTH_ALGO_SHA: + snmpv3_password_to_key_sha((const u8_t*)password, strlen(password), (const u8_t*)engineid, engineid_len, p->priv_key); + return ERR_OK; +#endif + default: + return ERR_VAL; + } + } + } + + return ERR_VAL; +} + +/** + * @brief Get the storage type of the given username. + * + * @param[in] username pointer to the username + * @param[out] type the storage type + * + * @return ERR_OK if the user was found, ERR_VAL if not. + */ +err_t +snmpv3_get_user_storagetype(const char *username, snmpv3_user_storagetype_t *type) +{ + if (get_user(username) != NULL) { + /* Found user in user table + * In this dummy implementation, storage is permanent because no user can be deleted. + * All changes to users are lost after a reboot.*/ + *type = SNMP_V3_USER_STORAGETYPE_PERMANENT; + return ERR_OK; + } + + return ERR_VAL; +} + +/** + * @param username is a pointer to a string. + * @param auth_algo is a pointer to u8_t. The implementation has to set this if user was found. + * @param auth_key is a pointer to a pointer to a string. Implementation has to set this if user was found. + * @param priv_algo is a pointer to u8_t. The implementation has to set this if user was found. + * @param priv_key is a pointer to a pointer to a string. Implementation has to set this if user was found. + */ +err_t +snmpv3_get_user(const char* username, snmpv3_auth_algo_t *auth_algo, u8_t *auth_key, snmpv3_priv_algo_t *priv_algo, u8_t *priv_key) +{ + const struct user_table_entry *p; + + /* The msgUserName specifies the user (principal) on whose behalf the + message is being exchanged. Note that a zero-length userName will + not match any user, but it can be used for snmpEngineID discovery. */ + if(strlen(username) == 0) { + return ERR_OK; + } + + p = get_user(username); + + if (!p) { + return ERR_VAL; + } + + if (auth_algo != NULL) { + *auth_algo = p->auth_algo; + } + if(auth_key != NULL) { + MEMCPY(auth_key, p->auth_key, sizeof(p->auth_key)); + } + if (priv_algo != NULL) { + *priv_algo = p->priv_algo; + } + if(priv_key != NULL) { + MEMCPY(priv_key, p->priv_key, sizeof(p->priv_key)); + } + return ERR_OK; +} + +/** + * Get engine ID from persistence + */ +void +snmpv3_get_engine_id(const char **id, u8_t *len) +{ + *id = snmpv3_engineid; + *len = snmpv3_engineid_len; +} + +/** + * Store engine ID in persistence + */ +err_t +snmpv3_set_engine_id(const char *id, u8_t len) +{ + MEMCPY(snmpv3_engineid, id, len); + snmpv3_engineid_len = len; + return ERR_OK; +} + +/** + * Get engine boots from persistence. Must be increased on each boot. + */ +u32_t +snmpv3_get_engine_boots(void) +{ + return engineboots; +} + +/** + * Store engine boots in persistence + */ +void +snmpv3_set_engine_boots(u32_t boots) +{ + engineboots = boots; +} + +/** + * RFC3414 2.2.2. + * Once the timer reaches 2147483647 it gets reset to zero and the + * engine boot ups get incremented. + */ +u32_t +snmpv3_get_engine_time(void) +{ + return enginetime; +} + +/** + * Reset current engine time to 0 + */ +void +snmpv3_reset_engine_time(void) +{ + enginetime = 0; +} + +/** + * Initialize dummy SNMPv3 implementation + */ +void +snmpv3_dummy_init(void) +{ + snmpv3_set_engine_id("FOO", 3); + + snmpv3_set_user_auth_algo("lwip", SNMP_V3_AUTH_ALGO_SHA); + snmpv3_set_user_auth_key("lwip", "maplesyrup"); + + snmpv3_set_user_priv_algo("lwip", SNMP_V3_PRIV_ALGO_DES); + snmpv3_set_user_priv_key("lwip", "maplesyrup"); + + /* Start the engine time timer */ + snmpv3_enginetime_timer(NULL); +} + +#endif /* LWIP_SNMP && LWIP_SNMP_V3 */ diff --git a/contrib/examples/snmp/snmp_v3/snmpv3_dummy.h b/contrib/examples/snmp/snmp_v3/snmpv3_dummy.h new file mode 100644 index 00000000000..ba25b6d7d58 --- /dev/null +++ b/contrib/examples/snmp/snmp_v3/snmpv3_dummy.h @@ -0,0 +1,53 @@ +/** + * @file + * Dummy SNMPv3 functions. + */ + +/* + * Copyright (c) 2017 Dirk Ziegelmeier. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dirk Ziegelmeier <dziegel@gmx.de> + */ + +#ifndef LWIP_HDR_APPS_SNMP_V3_DUMMY_H +#define LWIP_HDR_APPS_SNMP_V3_DUMMY_H + +#include "lwip/apps/snmp_opts.h" +#include "lwip/err.h" +#include "lwip/apps/snmpv3.h" + +#if LWIP_SNMP && LWIP_SNMP_V3 + +err_t snmpv3_set_user_auth_algo(const char *username, snmpv3_auth_algo_t algo); +err_t snmpv3_set_user_priv_algo(const char *username, snmpv3_priv_algo_t algo); +err_t snmpv3_set_user_auth_key(const char *username, const char *password); +err_t snmpv3_set_user_priv_key(const char *username, const char *password); + +void snmpv3_dummy_init(void); + +#endif /* LWIP_SNMP && LWIP_SNMP_V3 */ + +#endif /* LWIP_HDR_APPS_SNMP_V3_DUMMY_H */ |