diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..fcea03516ec5c098ce4fc2f0dbfbfd3e037a7f10 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,13 @@ +include: + - project: 'iopsys/gitlab-ci-pipeline' + file: '/static-code-analysis.yml' + ref: '0.31' + +stages: + - static_code_analysis + +variables: + DEBUG: 'TRUE' + SOURCE_FOLDER: "./bbf_plugin" + CPPCHECK_OPTIONS: "--enable=all --error-exitcode=1 ." + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59536805e59ad69447b519a36558f898cd6c354c --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +CC=gcc + +PLUGIN = bbf_plugin + + +PROG_CFLAGS = $(CFLAGS) -Wall -Werror -fstrict-aliasing +PROG_LDFLAGS = $(LDFLAGS) +PROG_LIBS += -luci -ljson-c -lblobmsg_json + +%.o: %.c + (CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $< + +.PHONY: all clean + +all: + $(MAKE) -C ./bbf_plugin + +clean: + rm -rf *.o *.so diff --git a/bbf_plugin/Makefile b/bbf_plugin/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bcd8adb71bbeaffb36e2fb69c3ef23a800ae660e --- /dev/null +++ b/bbf_plugin/Makefile @@ -0,0 +1,21 @@ +LIB_PORTTRIGGER := libporttrigger.so + +OBJS := nat_porttrigger.o + +LIB_CFLAGS = $(CFLAGS) -Wall -Werror -fstrict-aliasing +LIB_LDFLAGS = $(LDFLAGS) +FPIC := -fPIC + +.PHONY: all + +%.o: %.c + $(CC) $(LIB_CFLAGS) $(FPIC) -c -o $@ $< + +all: $(LIB_PORTTRIGGER) + +$(LIB_PORTTRIGGER): $(OBJS) + $(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^ + +clean: + rm -f *.o $(LIB_PORTTRIGGER) + diff --git a/bbf_plugin/nat_porttrigger.c b/bbf_plugin/nat_porttrigger.c new file mode 100644 index 0000000000000000000000000000000000000000..de76eaed919db1f39965fd5db438aa7609a440fb --- /dev/null +++ b/bbf_plugin/nat_porttrigger.c @@ -0,0 +1,538 @@ +/* + * Copyright (C) 2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amit Kumar <amit.kumar@iopsys.eu> + * + */ + +#include "libbbfdm-api/dmcommon.h" + +/************************************************************* +* ENTRY METHOD +**************************************************************/ + +/*#Device.NAT.PortTrigger.{i}.!UCI:port-trigger/port_trigger/dmmap_port_trigger*/ +static int browseNATPortTriggerInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + int inst = 0; + struct uci_section *p = NULL; + struct dm_data data = {0}; + char *name = NULL; + char *buf = NULL; + + uci_foreach_sections("port-trigger", "port_trigger", p) { + dmuci_get_section_name(section_name(p),&name); + if (name) { + sscanf(name, "port_trigger_%d",&inst); + if (inst == 0) { + continue; + } + dmasprintf(&buf, "%d", inst); + data.config_section = p; + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&data, buf) == DM_STOP) + break; + } + } + + return 0; +} + +static int browseNATPortTriggerRuleInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct uci_section *p = NULL; + struct dm_data data = {0}; + int inst = 0; + int ptg_inst = 0; + char *name = NULL; + char *buf = NULL; + int parent_inst = 0; + parent_inst = atoi(prev_instance); + + uci_foreach_sections("port-trigger", "rule", p) { + dmuci_get_section_name(section_name(p),&name); + if (name) { + sscanf(name, "port_trigger_%d_rule_%d",&ptg_inst,&inst); + if ((inst == 0) || (ptg_inst != parent_inst)) + continue; + dmasprintf(&buf, "%d", inst); + data.config_section = p; + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&data, buf) == DM_STOP) + break; + } + } + return 0; +} + +/************************************************************* +* ADD & DEL OBJ +**************************************************************/ +static int addObjNATPortTrigger(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + struct uci_section *s = NULL; + char port_trigger_name[16] = {0}; + char name[16] = {0}; + + snprintf(port_trigger_name, sizeof(port_trigger_name), "port_trigger_%s", *instance); + snprintf(name, sizeof(name), "trigger_%s", *instance); + + dmuci_add_section("port-trigger", "port_trigger", &s); + dmuci_rename_section_by_section(s, port_trigger_name); + dmuci_set_value_by_section(s, "name", name); + + return 0; +} + +static int delObjNATPortTrigger(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + struct uci_section *s = NULL, *stmp = NULL; + char *name; + + switch (del_action) { + case DEL_INST: + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &name); + uci_foreach_option_eq_safe("port-trigger", "rule", "port_trigger", name, stmp, s) { + dmuci_delete_by_section(s, NULL, NULL); + } + + dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL); + break; + case DEL_ALL: + uci_foreach_sections_safe("port-trigger", "port_trigger", stmp, s) { + + dmuci_delete_by_section(s, NULL, NULL); + } + uci_foreach_sections_safe("port-trigger", "rule", stmp, s) { + + dmuci_delete_by_section(s, NULL, NULL); + } + break; + } + return 0; +} + +static int addObjNATPortTriggerRule(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + struct uci_section *port_trigger = ((struct dm_data *)data)->config_section; + struct uci_section *s = NULL; + char s_name[50] = {0}; + char *name = NULL; + + snprintf(s_name, sizeof(s_name), "%s_rule_%s", section_name(port_trigger),*instance); + + dmuci_add_section("port-trigger", "rule", &s); + dmuci_rename_section_by_section(s, s_name); + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &name); + dmuci_set_value_by_section(s, "port_trigger", name); + + return 0; +} + +static int delObjNATPortTriggerRule(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + struct uci_section *s = NULL, *stmp = NULL; + char *name; + + switch (del_action) { + case DEL_INST: + dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL); + break; + case DEL_ALL: + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &name); + uci_foreach_option_eq_safe("port-trigger", "rule", "port_trigger", name, stmp, s) { + dmuci_delete_by_section(s, NULL, NULL); + } + break; + } + return 0; +} + +/************************************************************* +* GET & SET PARAM +**************************************************************/ +/*#Device.NAT.PortTriggerNumberOfEntries!UCI:port-trigger/port_trigger/*/ +static int get_NAT_PortTriggerNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseNATPortTriggerInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_NATPortTrigger_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_section_name(section_name(((struct dm_data *)data)->config_section),value); + return 0; +} + +static int get_NATPortTrigger_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "enable", "0"); + *value = (**value == 'n' || **value == '0' ) ? "0" : "1"; + return 0; +} + +static int set_NATPortTrigger_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + time_t now = time(NULL); + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "enable", b ? "1" : "0"); + + if (b == 1) { + char activation_date[32] = {0}; + + strftime(activation_date, sizeof(activation_date), "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "activation_date", activation_date); + } + break; + } + return 0; +} + +static int get_NATPortTrigger_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + /*return the admin state of port trigger rule + * running status to be updated in later changes*/ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "enable", "0"); + *value = (**value == 'n' || **value == '0' ) ? "Disabled" : "Enabled"; + return 0; +} + +static int get_NATPortTrigger_Origin(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "origin", "Controller"); + return 0; +} + +static int set_NATPortTrigger_Origin(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *Origin[] = {"User", "System", "Controller", NULL}; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, -1, Origin, NULL)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "origin", value); + break; + } + return 0; +} + +static int get_NATPortTrigger_Description(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "description", value); + return 0; +} + +static int set_NATPortTrigger_Description(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 256, NULL, NULL)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "description", value); + break; + } + return 0; +} + +static int get_NATPortTrigger_Interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *interf = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "src", &interf); + + adm_entry_get_reference_param(ctx, "Device.IP.Interface.*.Name", interf, value); + + return 0; +} + +static int set_NATPortTrigger_Interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *allowed_objects[] = {"Device.IP.Interface.", NULL}; + struct dm_reference reference = {0}; + + bbf_get_reference_args(value, &reference); + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, reference.path, -1, 256, NULL, NULL)) + return FAULT_9007; + + if (dm_validate_allowed_objects(ctx, &reference, allowed_objects)) + return FAULT_9007; + + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "src", reference.value); + break; + } + return 0; +} + +static int get_NATPortTrigger_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "port", "0"); + return 0; +} + +static int set_NATPortTrigger_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"0","65535"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "port", value); + break; + } + return 0; +} + +static int get_NATPortTrigger_PortEndRange(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "port_end_range", "0"); + return 0; +} + +static int set_NATPortTrigger_PortEndRange(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *port; + uint16_t s_port, end_port; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "port", &port); + s_port = DM_STRTOL(port); + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"0","65535"}}, 1)) + return FAULT_9007; + end_port = DM_STRTOL(value); + if (s_port > end_port) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "port_end_range", value); + break; + } + return 0; +} + +static int get_NATPortTrigger_AutoDisableDuration(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "auto_disable_duration", value); + return 0; +} + +static int set_NATPortTrigger_AutoDisableDuration(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "auto_disable_duration", value); + break; + } + return 0; +} + +static int get_NATPortTrigger_ActivationDate(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "activation_date", "0001-01-01T00:00:00Z"); + return 0; +} + +static int set_NATPortTrigger_ActivationDate(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char activation_date[16] = {0}; + struct tm tm; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_dateTime(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + strptime(value, "%Y-%m-%dT%H:%M:%SZ", &tm); + snprintf(activation_date, sizeof(activation_date), "%lld", (long long)timegm(&tm)); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "activation_date", activation_date); + break; + } + return 0; +} + +static int get_NATPortTrigger_Protocol(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "protocol", value); + return 0; +} + +static int set_NATPortTrigger_Protocol(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, -1, NATProtocol, NULL)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "protocol", value); + break; + } + return 0; +} + +static int get_NATPortTrigger_RuleNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseNATPortTriggerRuleInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_NATPortTriggerRule_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_section_name(section_name(((struct dm_data *)data)->config_section),value); + return 0; +} + +static int get_NATPortTriggerRule_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "port", "0"); + return 0; +} + +static int set_NATPortTriggerRule_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"0","65535"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "port", value); + break; + } + return 0; +} + +static int get_NATPortTriggerRule_PortEndRange(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "port_end_range", "0"); + return 0; +} + +static int set_NATPortTriggerRule_PortEndRange(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + + char *port; + uint16_t s_port, end_port; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "port", &port); + s_port = DM_STRTOL(port); + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"0","65535"}}, 1)) + return FAULT_9007; + end_port = DM_STRTOL(value); + if (s_port > end_port) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "port_end_range", value); + break; + } + return 0; +} + +static int get_NATPortTriggerRule_Protocol(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "protocol", value); + return 0; +} + +static int set_NATPortTriggerRule_Protocol(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, -1, NATProtocol, NULL)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "protocol", value); + break; + } + return 0; +} + +/********************************************************************************************************************************** +* OBJ & PARAM DEFINITION +***********************************************************************************************************************************/ + +DMLEAF tNATPortTriggerParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */ +{"Alias", &DMREAD, DMT_STRING, get_NATPortTrigger_Alias, NULL, BBFDM_BOTH}, +{"Enable", &DMWRITE, DMT_BOOL, get_NATPortTrigger_Enable, set_NATPortTrigger_Enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_NATPortTrigger_Status, NULL, BBFDM_BOTH}, +{"Origin", &DMWRITE, DMT_STRING, get_NATPortTrigger_Origin, set_NATPortTrigger_Origin, BBFDM_BOTH}, +{"Description", &DMWRITE, DMT_STRING, get_NATPortTrigger_Description, set_NATPortTrigger_Description, BBFDM_BOTH}, +{"Interface", &DMWRITE, DMT_STRING, get_NATPortTrigger_Interface, set_NATPortTrigger_Interface, BBFDM_BOTH, DM_FLAG_REFERENCE}, +{"Port", &DMWRITE, DMT_UNINT, get_NATPortTrigger_Port, set_NATPortTrigger_Port, BBFDM_BOTH}, +{"PortEndRange", &DMWRITE, DMT_UNINT, get_NATPortTrigger_PortEndRange, set_NATPortTrigger_PortEndRange, BBFDM_BOTH}, +{"AutoDisableDuration", &DMWRITE, DMT_UNINT, get_NATPortTrigger_AutoDisableDuration, set_NATPortTrigger_AutoDisableDuration, BBFDM_BOTH}, +{"ActivationDate", &DMWRITE, DMT_TIME, get_NATPortTrigger_ActivationDate, set_NATPortTrigger_ActivationDate, BBFDM_BOTH}, +{"Protocol", &DMWRITE, DMT_STRING, get_NATPortTrigger_Protocol, set_NATPortTrigger_Protocol, BBFDM_BOTH}, +{"RuleNumberOfEntries", &DMREAD, DMT_UNINT, get_NATPortTrigger_RuleNumberOfEntries, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.NAT.PortTrigger.{i}.Rule.{i}. *** */ +DMLEAF tNATPortTriggerRuleParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */ +{"Alias", &DMREAD, DMT_STRING, get_NATPortTriggerRule_Alias, NULL, BBFDM_BOTH}, +{"Port", &DMWRITE, DMT_UNINT, get_NATPortTriggerRule_Port, set_NATPortTriggerRule_Port, BBFDM_BOTH}, +{"PortEndRange", &DMWRITE, DMT_UNINT, get_NATPortTriggerRule_PortEndRange, set_NATPortTriggerRule_PortEndRange, BBFDM_BOTH}, +{"Protocol", &DMWRITE, DMT_STRING, get_NATPortTriggerRule_Protocol, set_NATPortTriggerRule_Protocol, BBFDM_BOTH}, +{0} +}; + +DMLEAF tDeviceNATPortTriggerParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/ +{"PortTriggerNumberOfEntries", &DMREAD, DMT_UNINT, get_NAT_PortTriggerNumberOfEntries, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.NAT.PortTrigger.{i}. *** */ +DMOBJ tNATPortTriggerObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys */ +{"Rule", &DMWRITE, addObjNATPortTriggerRule, delObjNATPortTriggerRule, NULL, browseNATPortTriggerRuleInst, NULL, NULL, NULL, tNATPortTriggerRuleParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +/* *** Device.NAT. *** */ +DMOBJ tDeviceNATPortTriggerObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/ +{"PortTrigger", &DMWRITE, addObjNATPortTrigger, delObjNATPortTrigger, NULL, browseNATPortTriggerInst, NULL, NULL, tNATPortTriggerObj, tNATPortTriggerParams, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.NAT.PortTrigger. *** */ +DM_MAP_OBJ tDynamicObj[] = { +/* parentobj, nextobject, parameter */ +{"Device.NAT.", tDeviceNATPortTriggerObj, tDeviceNATPortTriggerParams}, +{0} +};