mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-03 11:01:48 +00:00
lib: disallow access list duplicated values
Don't allow users to create multiple rules in the same list with the same value to keep the behavior previously to northbound migration. Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
This commit is contained in:
parent
057edd2e84
commit
f414129b0c
27
lib/filter.h
27
lib/filter.h
@ -176,6 +176,33 @@ enum yang_prefix_list_action {
|
||||
YPLA_PERMIT = 1,
|
||||
};
|
||||
|
||||
struct acl_dup_args {
|
||||
/** Access list type ("ipv4", "ipv6" or "mac"). */
|
||||
const char *ada_type;
|
||||
/** Access list name. */
|
||||
const char *ada_name;
|
||||
|
||||
#define ADA_MAX_VALUES 4
|
||||
/** Entry XPath for value. */
|
||||
const char *ada_xpath[ADA_MAX_VALUES];
|
||||
/** Entry value to match. */
|
||||
const char *ada_value[ADA_MAX_VALUES];
|
||||
|
||||
/** Duplicated entry found in list? */
|
||||
bool ada_found;
|
||||
|
||||
/** (Optional) Already existing `dnode`. */
|
||||
const struct lyd_node *ada_entry_dnode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check for duplicated entries using the candidate configuration.
|
||||
*
|
||||
* \param vty so we can get the candidate config.
|
||||
* \param ada the arguments to check.
|
||||
*/
|
||||
bool acl_is_dup(const struct lyd_node *dnode, struct acl_dup_args *ada);
|
||||
|
||||
/* filter_cli.c */
|
||||
struct lyd_node;
|
||||
struct vty;
|
||||
|
259
lib/filter_nb.c
259
lib/filter_nb.c
@ -133,6 +133,138 @@ static void cisco_unset_addr_mask(struct in_addr *addr, struct in_addr *mask)
|
||||
mask->s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
|
||||
}
|
||||
|
||||
static int _acl_is_dup(const struct lyd_node *dnode, void *arg)
|
||||
{
|
||||
struct acl_dup_args *ada = arg;
|
||||
int idx;
|
||||
|
||||
/* This entry is the caller, so skip it. */
|
||||
if (ada->ada_entry_dnode
|
||||
&& ada->ada_entry_dnode == dnode)
|
||||
return YANG_ITER_CONTINUE;
|
||||
|
||||
/* Check if all values match. */
|
||||
for (idx = 0; idx < ADA_MAX_VALUES; idx++) {
|
||||
/* No more values. */
|
||||
if (ada->ada_xpath[idx] == NULL)
|
||||
break;
|
||||
|
||||
/* Not same type, just skip it. */
|
||||
if (!yang_dnode_exists(dnode, ada->ada_xpath[idx]))
|
||||
return YANG_ITER_CONTINUE;
|
||||
|
||||
/* Check if different value. */
|
||||
if (strcmp(yang_dnode_get_string(dnode, ada->ada_xpath[idx]),
|
||||
ada->ada_value[idx]))
|
||||
return YANG_ITER_CONTINUE;
|
||||
}
|
||||
|
||||
ada->ada_found = true;
|
||||
|
||||
return YANG_ITER_STOP;
|
||||
}
|
||||
|
||||
bool acl_is_dup(const struct lyd_node *dnode, struct acl_dup_args *ada)
|
||||
{
|
||||
ada->ada_found = false;
|
||||
|
||||
yang_dnode_iterate(
|
||||
_acl_is_dup, ada, dnode,
|
||||
"/frr-filter:lib/access-list[type='%s'][name='%s']/entry",
|
||||
ada->ada_type, ada->ada_name);
|
||||
|
||||
return ada->ada_found;
|
||||
}
|
||||
|
||||
static bool acl_cisco_is_dup(const struct lyd_node *dnode)
|
||||
{
|
||||
const struct lyd_node *entry_dnode =
|
||||
yang_dnode_get_parent(dnode, "entry");
|
||||
struct acl_dup_args ada = {};
|
||||
int idx = 0, arg_idx = 0;
|
||||
static const char *cisco_entries[] = {
|
||||
"./host",
|
||||
"./network/address",
|
||||
"./network/mask",
|
||||
"./source-any",
|
||||
"./destination-host",
|
||||
"./destination-network/address",
|
||||
"./destination-network/mask",
|
||||
"./destination-any",
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Initialize. */
|
||||
ada.ada_type = "ipv4";
|
||||
ada.ada_name = yang_dnode_get_string(entry_dnode, "../name");
|
||||
ada.ada_entry_dnode = entry_dnode;
|
||||
|
||||
/* Load all values/XPaths. */
|
||||
while (cisco_entries[idx] != NULL) {
|
||||
if (!yang_dnode_exists(entry_dnode, cisco_entries[idx])) {
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
ada.ada_xpath[arg_idx] = cisco_entries[idx];
|
||||
ada.ada_value[arg_idx] =
|
||||
yang_dnode_get_string(entry_dnode, cisco_entries[idx]);
|
||||
arg_idx++;
|
||||
idx++;
|
||||
}
|
||||
|
||||
return acl_is_dup(entry_dnode, &ada);
|
||||
}
|
||||
|
||||
static bool acl_zebra_is_dup(const struct lyd_node *dnode,
|
||||
enum yang_access_list_type type)
|
||||
{
|
||||
const struct lyd_node *entry_dnode =
|
||||
yang_dnode_get_parent(dnode, "entry");
|
||||
struct acl_dup_args ada = {};
|
||||
int idx = 0, arg_idx = 0;
|
||||
static const char *zebra_entries[] = {
|
||||
"./ipv4-prefix",
|
||||
"./ipv4-exact-match",
|
||||
"./ipv6-prefix",
|
||||
"./ipv6-exact-match",
|
||||
"./mac",
|
||||
"./any",
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Initialize. */
|
||||
switch (type) {
|
||||
case YALT_IPV4:
|
||||
ada.ada_type = "ipv4";
|
||||
break;
|
||||
case YALT_IPV6:
|
||||
ada.ada_type = "ipv6";
|
||||
break;
|
||||
case YALT_MAC:
|
||||
ada.ada_type = "mac";
|
||||
break;
|
||||
}
|
||||
ada.ada_name = yang_dnode_get_string(entry_dnode, "../name");
|
||||
ada.ada_entry_dnode = entry_dnode;
|
||||
|
||||
/* Load all values/XPaths. */
|
||||
while (zebra_entries[idx] != NULL) {
|
||||
if (!yang_dnode_exists(entry_dnode, zebra_entries[idx])) {
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
ada.ada_xpath[arg_idx] = zebra_entries[idx];
|
||||
ada.ada_value[arg_idx] =
|
||||
yang_dnode_get_string(entry_dnode, zebra_entries[idx]);
|
||||
arg_idx++;
|
||||
idx++;
|
||||
}
|
||||
|
||||
return acl_is_dup(entry_dnode, &ada);
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-filter:lib/access-list
|
||||
*/
|
||||
@ -290,6 +422,19 @@ lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
|
||||
struct filter_zebra *fz;
|
||||
struct filter *f;
|
||||
|
||||
/* Don't allow duplicated values. */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
if (acl_zebra_is_dup(
|
||||
args->dnode,
|
||||
yang_dnode_get_enum(args->dnode, "../../type"))) {
|
||||
snprintfrr(args->errmsg, args->errmsg_len,
|
||||
"duplicated access list value: %s",
|
||||
yang_dnode_get_string(args->dnode, NULL));
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
@ -330,6 +475,19 @@ lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)
|
||||
struct filter_zebra *fz;
|
||||
struct filter *f;
|
||||
|
||||
/* Don't allow duplicated values. */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
if (acl_zebra_is_dup(
|
||||
args->dnode,
|
||||
yang_dnode_get_enum(args->dnode, "../../type"))) {
|
||||
snprintfrr(args->errmsg, args->errmsg_len,
|
||||
"duplicated access list value: %s",
|
||||
yang_dnode_get_string(args->dnode, NULL));
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
@ -369,6 +527,17 @@ lib_access_list_entry_host_modify(struct nb_cb_modify_args *args)
|
||||
struct filter_cisco *fc;
|
||||
struct filter *f;
|
||||
|
||||
/* Don't allow duplicated values. */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
if (acl_cisco_is_dup(args->dnode)) {
|
||||
snprintfrr(args->errmsg, args->errmsg_len,
|
||||
"duplicated access list value: %s",
|
||||
yang_dnode_get_string(args->dnode, NULL));
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
@ -410,6 +579,17 @@ lib_access_list_entry_network_address_modify(struct nb_cb_modify_args *args)
|
||||
struct filter_cisco *fc;
|
||||
struct filter *f;
|
||||
|
||||
/* Don't allow duplicated values. */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
if (acl_cisco_is_dup(args->dnode)) {
|
||||
snprintfrr(args->errmsg, args->errmsg_len,
|
||||
"duplicated access list value: %s",
|
||||
yang_dnode_get_string(args->dnode, NULL));
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
@ -432,6 +612,17 @@ lib_access_list_entry_network_mask_modify(struct nb_cb_modify_args *args)
|
||||
struct filter_cisco *fc;
|
||||
struct filter *f;
|
||||
|
||||
/* Don't allow duplicated values. */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
if (acl_cisco_is_dup(args->dnode)) {
|
||||
snprintfrr(args->errmsg, args->errmsg_len,
|
||||
"duplicated access list value: %s",
|
||||
yang_dnode_get_string(args->dnode, NULL));
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
@ -454,6 +645,17 @@ lib_access_list_entry_source_any_create(struct nb_cb_create_args *args)
|
||||
struct filter_cisco *fc;
|
||||
struct filter *f;
|
||||
|
||||
/* Don't allow duplicated values. */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
if (acl_cisco_is_dup(args->dnode)) {
|
||||
snprintfrr(args->errmsg, args->errmsg_len,
|
||||
"duplicated access list value: %s",
|
||||
yang_dnode_get_string(args->dnode, NULL));
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
@ -495,6 +697,17 @@ static int lib_access_list_entry_destination_host_modify(
|
||||
struct filter_cisco *fc;
|
||||
struct filter *f;
|
||||
|
||||
/* Don't allow duplicated values. */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
if (acl_cisco_is_dup(args->dnode)) {
|
||||
snprintfrr(args->errmsg, args->errmsg_len,
|
||||
"duplicated access list value: %s",
|
||||
yang_dnode_get_string(args->dnode, NULL));
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
@ -537,6 +750,17 @@ static int lib_access_list_entry_destination_network_address_modify(
|
||||
struct filter_cisco *fc;
|
||||
struct filter *f;
|
||||
|
||||
/* Don't allow duplicated values. */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
if (acl_cisco_is_dup(args->dnode)) {
|
||||
snprintfrr(args->errmsg, args->errmsg_len,
|
||||
"duplicated access list value: %s",
|
||||
yang_dnode_get_string(args->dnode, NULL));
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
@ -559,6 +783,17 @@ static int lib_access_list_entry_destination_network_mask_modify(
|
||||
struct filter_cisco *fc;
|
||||
struct filter *f;
|
||||
|
||||
/* Don't allow duplicated values. */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
if (acl_cisco_is_dup(args->dnode)) {
|
||||
snprintfrr(args->errmsg, args->errmsg_len,
|
||||
"duplicated access list value: %s",
|
||||
yang_dnode_get_string(args->dnode, NULL));
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
@ -581,6 +816,17 @@ static int lib_access_list_entry_destination_any_create(
|
||||
struct filter_cisco *fc;
|
||||
struct filter *f;
|
||||
|
||||
/* Don't allow duplicated values. */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
if (acl_cisco_is_dup(args->dnode)) {
|
||||
snprintfrr(args->errmsg, args->errmsg_len,
|
||||
"duplicated access list value: %s",
|
||||
yang_dnode_get_string(args->dnode, NULL));
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
@ -623,6 +869,19 @@ static int lib_access_list_entry_any_create(struct nb_cb_create_args *args)
|
||||
struct filter *f;
|
||||
int type;
|
||||
|
||||
/* Don't allow duplicated values. */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
if (acl_zebra_is_dup(
|
||||
args->dnode,
|
||||
yang_dnode_get_enum(args->dnode, "../../type"))) {
|
||||
snprintfrr(args->errmsg, args->errmsg_len,
|
||||
"duplicated access list value: %s",
|
||||
yang_dnode_get_string(args->dnode, NULL));
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user