Support list of IP for incoming connection request

This commit is contained in:
Suvendhu Hansa 2025-04-04 12:25:09 +00:00 committed by IOPSYS Dev
parent 21021a7134
commit dc2cf6979d
No known key found for this signature in database
14 changed files with 135 additions and 59 deletions

View file

@ -30,6 +30,8 @@ config cpe 'cpe'
option default_wan_interface 'wan'
option userid 'iopsys'
option exec_download '0'
list allowed_cr_ip '10.5.3.14/32'
list allowed_cr_ip '20.2.1.0/24'
config lwn 'lwn'
option enable '1'

View file

@ -4,6 +4,7 @@ PROJECT(libcwmpdm.so)
ADD_DEFINITIONS(-Wall -Werror -Wformat -g)
ADD_DEFINITIONS(-D_GNU_SOURCE)
ADD_DEFINITIONS(-DBBF_VENDOR_PREFIX="${BBF_VENDOR_PREFIX}")
# Compile and install libcwmpdm.so
ADD_LIBRARY(cwmpdm SHARED datamodel.c)

View file

@ -939,6 +939,40 @@ static int set_manageable_device_notification_limit(char *refparam, struct dmctx
return 0;
}
#ifdef ICWMP_ENABLE_VENDOR_EXTN
static int get_allowed_cr_ip(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
struct uci_list *uci_opt_list = NULL;
dmuci_get_option_value_list("cwmp", "cpe", "allowed_cr_ip", &uci_opt_list);
*value = dmuci_list_to_string(uci_opt_list, ",");
return 0;
}
static int set_allowed_cr_ip(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
size_t length, i;
int ret = 0;
char **arr;
switch (action) {
case VALUECHECK:
if (bbfdm_validate_string(ctx, value, -1, -1, NULL, NULL))
ret = FAULT_9007;
break;
case VALUESET:
dmuci_delete("cwmp", "cpe", "allowed_cr_ip", NULL);
arr = strsplit(value, ",", &length);
for (i = 0; i < length; i++) {
dmuci_add_list_value("cwmp", "cpe", "allowed_cr_ip", arr[i]);
}
break;
}
return ret;
}
#endif
static int get_heart_beat_policy_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = dmuci_get_option_value_fallback_def("cwmp", "acs", "heartbeat_enable", "0");
@ -1419,6 +1453,9 @@ DMLEAF tManagementServerParams[] = {
{"ManageableDeviceNumberOfEntries", &DMREAD, DMT_UNINT, get_manageable_device_number_of_entries, NULL, BBFDM_CWMP},
{"DefaultActiveNotificationThrottle", &DMWRITE, DMT_UNINT, get_default_active_notification_throttle, set_default_active_notification_throttle, BBFDM_CWMP},
{"ManageableDeviceNotificationLimit", &DMWRITE, DMT_UNINT, get_manageable_device_notification_limit, set_manageable_device_notification_limit, BBFDM_CWMP},
#ifdef ICWMP_ENABLE_VENDOR_EXTN
{BBF_VENDOR_PREFIX"AllowedConnectionRequestIP", &DMWRITE, DMT_STRING, get_allowed_cr_ip, set_allowed_cr_ip, BBFDM_CWMP},
#endif
{0}
};

View file

@ -917,10 +917,10 @@
</tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">incoming_rule</div>
<div class="td_row_odd">allowed_cr_ip</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">string</div>
<div class="td_row_odd">list</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
@ -929,7 +929,7 @@
<div class="td_row_odd"></div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">This configure firewall rules. Allowed values &lt;IP_Only/Port_Only/IP_Port&gt;. IP_Only means only acs ip as source ip used for firewall input rule, Port_Only means only destination port will be used and IP_Port or empty value meaning both ip and port will be used for firewall input rule.</div>
<div class="td_row_odd">List of subnets or ips from where incoming connection requests are allowed e.g 10.2.1.0/24 or 10.2.1.5/32. So connection requests are allowed with src IP in range of &lt10.2.1.1 - 10.2.1.254&gt or from 10.2.1.5 and with dest-port same as &ltport&gt; Empty value means only destination port will be used and connection requests on the valid port will be accepted irrespective of any src IP.</div>
</td>
</tr>
<tr>

View file

@ -109,6 +109,7 @@ function build_icwmp()
{
COV_CFLAGS='-g -O0 -fprofile-arcs -ftest-coverage'
COV_LDFLAGS='--coverage'
VENDOR_PREFIX='X_IOWRT_EU_'
BINP="${PWD}"
# clean icwmp
@ -117,7 +118,7 @@ function build_icwmp()
# compile icwmp
mkdir -p build
cd build
cmake ../ -DCMAKE_C_FLAGS="$COV_CFLAGS " -DCMAKE_EXE_LINKER_FLAGS="$COV_LDFLAGS" -DCMAKE_INSTALL_PREFIX=/
cmake ../ -DCMAKE_C_FLAGS="$COV_CFLAGS -DICWMP_ENABLE_VENDOR_EXTN" -DCMAKE_EXE_LINKER_FLAGS="$COV_LDFLAGS" -DCMAKE_INSTALL_PREFIX=/ -DBBF_VENDOR_PREFIX="$VENDOR_PREFIX"
exec_cmd make
echo "installing icwmpd binary and libcwmpdm.so library"

View file

@ -276,7 +276,14 @@
"type": "uinteger",
"required": "no",
"default": "7547",
"description": "The port used for connection request."
"description": "The port allowed for incoming connection request."
},
{
"name": "allowed_cr_ip",
"type": "list",
"required": "no",
"default": null,
"description": "List of subnets or ips from where incoming connection requests are allowed e.g 10.2.1.0/24 or 10.2.1.5/32. So connection requests are allowed with SRC IP in range of '10.2.1.1 - 10.2.1.254' or from 10.2.1.5 and with dest port same as <B>port</B>. Empty value means only destination port will be used and connection requests on the valid port will be accepted irrespective of any src IP."
},
{
"name": "path",
@ -285,6 +292,13 @@
"default": "/",
"description": "CPE Connection request URI path"
},
{
"name": "instance_mode",
"type": "string",
"required": "no",
"default": "InstanceNumber",
"description": "Configure the instance mode to use. Supported instance modes are : <B>InstanceNumber</B> and <B>InstanceAlias</B>."
},
{
"name": "provisioning_code",
"type": "string",
@ -299,13 +313,6 @@
"default": "5",
"description": "Configure the amendment version to use."
},
{
"name": "instance_mode",
"type": "string",
"required": "no",
"default": "InstanceNumber",
"description": "Configure the instance mode to use. Supported instance modes are : <B>InstanceNumber</B> and <B>InstanceNumber</B>."
},
{
"name": "session_timeout",
"type": "uinteger",
@ -355,13 +362,6 @@
"default": "",
"description": "Define absolute path of the JSON containing parameters on which notification get enabled as per the definition. See readme for examples."
},
{
"name": "incoming_rule",
"type": "string",
"required": "no",
"default": "",
"description": "This configure firewall rules. Allowed values <IP_Only/Port_Only/IP_Port>. IP_Only means only acs ip as source ip used for firewall input rule, Port_Only means only destination port will be used and IP_Port or empty value meaning both ip and port will be used for firewall input rule."
},
{
"name": "force_ipv4",
"type": "boolean",

View file

@ -1364,3 +1364,12 @@ void stop_service(void)
icwmp_ubus_invoke("service", "state", bb.head, NULL, NULL);
blob_buf_free(&bb);
}
void apply_allowed_cr_ip_port(void)
{
// Flawfinder: ignore
FILE *pp = popen(FIREWALL_CWMP, "r");
if (pp) {
pclose(pp);
}
}

View file

@ -75,7 +75,7 @@
#define ICWMP_TMP_PATH "/tmp/icwmp"
#define VENDOR_LOG_SCRIPT "/etc/icwmpd/vendor_log.sh"
#define FIREWALL_CWMP "/etc/icwmpd/firewall.cwmp"
#define FIREWALL_CWMP "/etc/icwmpd/firewall.cwmp cwmp"
#define DM_PPP_INTERFACE_PATH "Device\\.PPP\\.Interface\\."
#define DM_IP_INTERFACE_PATH "Device\\.IP\\.Interface\\."
#define DEFAULT_CR_TIMEOUT 5 /* In Seconds */
@ -135,6 +135,7 @@ typedef struct config {
bool acs_getrpc;
bool auto_tc_enable;
bool auto_cdu_enable;
bool cr_ip_port_change;
int retry_min_wait_interval;
int retry_interval_multiplier;
@ -172,6 +173,7 @@ typedef struct config {
char default_wan_iface[BUF_SIZE_32];
char cpe_client_cert[BUF_SIZE_256];
char cpe_client_key[BUF_SIZE_256];
char valid_cr_ip[BUF_SIZE_2048];
} config;
struct deviceid {
@ -182,12 +184,6 @@ struct deviceid {
char softwareversion[BUF_SIZE_64];
};
enum firewall_cr_policy {
CR_POLICY_Port_Only = 0,
CR_POLICY_IP_Only,
CR_POLICY_BOTH,
};
typedef struct cwmp {
struct env env;
struct config conf;
@ -227,7 +223,6 @@ typedef struct cwmp {
struct ubus_event_handler *ev;
struct ubus_event_handler *intf_ev;
bool throttle_session_triggered;
enum firewall_cr_policy cr_policy;
bool acs_changed;
int curr_delay_reboot;
time_t curr_schedule_reboot;
@ -650,7 +645,6 @@ bool folder_exists(const char *path);
bool file_exists(const char *path);
void cwmp_reboot(const char *command_key);
void cwmp_factory_reset();
void get_firewall_zone_name_by_wan_iface(char *if_wan, char **zone_name);
int download_file(const char *file_path, const char *url, const char *username, const char *password, const char *interface);
unsigned int get_file_size(const char *file_name);
int cwmp_check_image();
@ -706,4 +700,5 @@ bool end_session_reload_service(const char *service);
bool end_session_reload_pending(void);
void add_path_list(struct list_head *list, char *str);
void free_path_list(struct list_head *list);
void apply_allowed_cr_ip_port(void);
#endif

View file

@ -26,17 +26,6 @@
#include "heartbeat.h"
#include "cwmp_http.h"
static void set_cr_incoming_rule(const char *rule)
{
if (CWMP_LSTRCASECMP(rule, "ip_only") == 0) {
cwmp_ctx.cr_policy = CR_POLICY_IP_Only;
} else if (CWMP_LSTRCASECMP(rule, "ip_port") == 0) {
cwmp_ctx.cr_policy = CR_POLICY_BOTH;
} else {
cwmp_ctx.cr_policy = CR_POLICY_Port_Only; // Default case
}
}
int get_preinit_config()
{
char value[BUF_SIZE_256] = {0};
@ -64,9 +53,6 @@ int get_preinit_config()
CWMP_STRNCMP(cwmp_ctx.conf.default_wan_iface, "wan", sizeof(cwmp_ctx.conf.default_wan_iface));
}
get_uci_path_value(NULL, UCI_CPE_INCOMING_RULE, value, BUF_SIZE_256);
set_cr_incoming_rule(value);
cwmp_ctx.conf.amd_version = DEFAULT_AMD_VERSION;
get_uci_path_value(NULL, UCI_CPE_AMD_VERSION, value, BUF_SIZE_256);
if (CWMP_STRLEN(value) != 0) {

View file

@ -20,7 +20,6 @@
#define UCI_LOG_SEVERITY_PATH "cwmp.cpe.log_severity"
#define UCI_CPE_ENABLE_SYSLOG "cwmp.cpe.log_to_syslog"
#define UCI_CPE_DEFAULT_WAN_IFACE "cwmp.cpe.default_wan_interface"
#define UCI_CPE_INCOMING_RULE "cwmp.cpe.incoming_rule"
#define UCI_CPE_AMD_VERSION "cwmp.cpe.amd_version"
#define UCI_CPE_CERT_PATH "cwmp.cpe.client_cert_path"
#define UCI_CPE_KEY_PATH "cwmp.cpe.client_key_path"

View file

@ -352,6 +352,9 @@ int main(int argc, char **argv)
http_server_start();
apply_allowed_cr_ip_port();
cwmp_ctx.conf.cr_ip_port_change = false;
uloop_run();
uloop_done();

View file

@ -331,15 +331,6 @@ int icwmp_http_send_message(char *msg_out, int msg_out_len, char **msg_in)
} else {
set_uci_path_value(VARSTATE_CONFIG, "icwmp.acs.ip", cwmp_ctx.ip_acs);
}
// Trigger firewall to reload firewall.cwmp
if (cwmp_ctx.cr_policy != CR_POLICY_Port_Only) {
// Flawfinder: ignore
FILE *pp = popen(FIREWALL_CWMP, "r");
if (pp) {
pclose(pp);
}
}
}
}
@ -693,13 +684,8 @@ void icwmp_http_server_init(void)
snprintf(cr_port_str, 6, "%hu", cr_port);
cr_port_str[5] = '\0';
set_uci_path_value(NULL, "cwmp.cpe.port", cr_port_str);
// Flawfinder: ignore
FILE *pp = popen(FIREWALL_CWMP, "r");
if (pp) {
pclose(pp);
}
connection_request_port_value_change(cr_port);
cwmp_ctx.conf.cr_ip_port_change = true;
}
CWMP_LOG(INFO, "Connection Request server initiated with the port: %d", cr_port);

View file

@ -697,6 +697,12 @@ int run_session_end_func(void)
CWMP_LOG(ERROR, "config reload failed at session end");
}
if (cwmp_ctx.conf.cr_ip_port_change == true) {
CWMP_LOG(INFO, "Allowed CR IPs are changed");
apply_allowed_cr_ip_port();
cwmp_ctx.conf.cr_ip_port_change = false;
}
reinit_cwmp_periodic_session_feature();
reinit_heartbeat_procedures();

View file

@ -52,6 +52,45 @@ static char *get_value_from_uci_option(struct uci_option *tb)
return "";
}
static int get_value_from_uci_list(struct uci_option *tb, char *value, size_t size)
{
if (value == NULL)
return -1;
memset(value, 0, size);
if (tb == NULL)
return -1;
if (tb->type == UCI_TYPE_LIST) {
struct uci_element *e;
bool sep = false;
char *tmp = value;
size_t left = 0;
uci_foreach_element(&tb->v.list, e) {
if (sep) {
left = size - strlen(value);
if (left < 2)
break;
int rc = snprintf(tmp, left, "%s", ",");
tmp = tmp + rc;
}
left = size - strlen(value);
if (left <= strlen(e->name))
break;
int rc = snprintf(tmp, left, "%s", e->name);
tmp = tmp + rc;
sep = true;
}
}
return 0;
}
static void config_get_acs_elements(struct uci_section *s)
{
enum {
@ -243,6 +282,7 @@ static void config_get_cpe_elements(struct uci_section *s)
UCI_CPE_ENABLE,
UCI_CPE_USE_CURL_IFNAME,
UCI_CPE_DISABLE_DATATYPE_CHECK,
UCI_CPE_ALLOWED_CR_IP,
__MAX_NUM_UCI_CPE_ATTRS,
};
@ -269,7 +309,8 @@ static void config_get_cpe_elements(struct uci_section *s)
[UCI_CPE_CLOCK_SYNC_TIMEOUT] = { .name = "clock_sync_timeout", .type = UCI_TYPE_STRING },
[UCI_CPE_ENABLE] = { .name = "enable", .type = UCI_TYPE_STRING },
[UCI_CPE_USE_CURL_IFNAME] = { .name = "use_curl_ifname", .type = UCI_TYPE_STRING },
[UCI_CPE_DISABLE_DATATYPE_CHECK] = { .name = "disable_datatype_check", .type = UCI_TYPE_STRING }
[UCI_CPE_DISABLE_DATATYPE_CHECK] = { .name = "disable_datatype_check", .type = UCI_TYPE_STRING },
[UCI_CPE_ALLOWED_CR_IP] = { .name = "allowed_cr_ip", .type = UCI_TYPE_LIST },
};
struct uci_option *cpe_tb[__MAX_NUM_UCI_CPE_ATTRS];
@ -417,6 +458,16 @@ static void config_get_cpe_elements(struct uci_section *s)
cwmp_ctx.conf.cpe_disable_datatype_check = str_to_bool(get_value_from_uci_option(cpe_tb[UCI_CPE_DISABLE_DATATYPE_CHECK]));
CWMP_LOG(DEBUG, "CWMP CONFIG - cpe datatype validation: %d", cwmp_ctx.conf.cpe_disable_datatype_check);
char allowed_cr_ip[BUF_SIZE_2048] = {0};
get_value_from_uci_list(cpe_tb[UCI_CPE_ALLOWED_CR_IP], allowed_cr_ip, sizeof(allowed_cr_ip));
if (CWMP_STRCMP(cwmp_ctx.conf.valid_cr_ip, allowed_cr_ip) != 0) {
snprintf(cwmp_ctx.conf.valid_cr_ip, sizeof(cwmp_ctx.conf.valid_cr_ip), "%s", allowed_cr_ip);
cwmp_ctx.conf.cr_ip_port_change = true;
}
CWMP_LOG(DEBUG, "CWMP CONFIG - cpe allowed_cr_ip: %s", cwmp_ctx.conf.valid_cr_ip);
}
static void config_get_lwn_elements(struct uci_section *s)