Skip to content

Commit bf29c1e

Browse files
kristrevldir-EDB0
authored andcommitted
firewall3: ipset: Handle reload_set properly
The reload_set option was added in commit 509e673 ("firewall3: Improve ipset support"), and the purpose of the option is to control if a set should be flushed or not on a firewall reload. In some cases, the option unfortunately does not work properly. I had fixed the errors locally, but failed to submit a v2 of "Improve ipset support". This patch contains my local fixes, and after the following changes are applied then the option (as well as ipset support) works as at least I expect. The following errors have been fixed: * "family" was not written to the state file, causing all sets read from this file was considered as ipv4. Save family to ensure that sets are handled correctly on firewall reload. * The default value of "reload_set" is false, meaning that the reload-check in "fw3_create_ipsets()" is always true (on reload). A consequence of this is that new sets are never created on firewall reload. In order to ensure that new sets are created, only consider "reload_set" if the set exists. If a set (from configuration) does not exist, we always want to create it. * On reload and before "fw3_destroy_ipsets()" are called, we need to update run_state to ensure that sets are updated correctly. We need to check if the sets in run_state is found in cfg_state, if not the set should be destroyed (done by forcing reload_set to true). If the set is found, then we copy the value of reload_set to the set in run_state so that the elements are updated as the user expects. Since we now always copy the value of reload_set from cfg_state, there is no need to write reload_set to run_state. Signed-off-by: Kristian Evensen <[email protected]>
1 parent 509e673 commit bf29c1e

File tree

4 files changed

+55
-4
lines changed

4 files changed

+55
-4
lines changed

ipsets.c

+45-2
Original file line numberDiff line numberDiff line change
@@ -427,13 +427,16 @@ fw3_create_ipsets(struct fw3_state *state, enum fw3_family family,
427427
/* spawn ipsets */
428428
list_for_each_entry(ipset, &state->ipsets, list)
429429
{
430-
if (ipset->family != family ||
431-
(reload_set && !ipset->reload_set))
430+
if (ipset->family != family)
432431
continue;
433432

434433
if (ipset->external)
435434
continue;
436435

436+
if (fw3_check_ipset(ipset) &&
437+
(reload_set && !ipset->reload_set))
438+
continue;
439+
437440
if (!exec)
438441
{
439442
exec = fw3_command_pipe(false, "ipset", "-exist", "-");
@@ -568,3 +571,43 @@ fw3_check_ipset(struct fw3_ipset *set)
568571

569572
return rv;
570573
}
574+
575+
void
576+
fw3_ipsets_update_run_state(enum fw3_family family, struct fw3_state *run_state,
577+
struct fw3_state *cfg_state)
578+
{
579+
struct fw3_ipset *ipset_run, *ipset_cfg;
580+
bool in_cfg;
581+
582+
list_for_each_entry(ipset_run, &run_state->ipsets, list) {
583+
if (ipset_run->family != family)
584+
continue;
585+
586+
in_cfg = false;
587+
588+
list_for_each_entry(ipset_cfg, &cfg_state->ipsets, list) {
589+
if (ipset_cfg->family != family)
590+
continue;
591+
592+
if (strlen(ipset_run->name) ==
593+
strlen(ipset_cfg->name) &&
594+
!strcmp(ipset_run->name, ipset_cfg->name)) {
595+
in_cfg = true;
596+
break;
597+
}
598+
}
599+
600+
/* If a set is found in run_state, but not in cfg_state then the
601+
* set has been deleted/renamed. Set reload_set to true to force
602+
* the old set to be destroyed in the "stop" fase of the reload.
603+
* If the set is found, then copy the reload_set value from the
604+
* configuration state. This ensures that the elements are
605+
* always updated according to the configuration, and not the
606+
* runtime state (which the user might have forgotten).
607+
*/
608+
if (!in_cfg)
609+
ipset_run->reload_set = true;
610+
else
611+
ipset_run->reload_set = ipset_cfg->reload_set;
612+
}
613+
}

ipsets.h

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ struct fw3_ipset * fw3_lookup_ipset(struct fw3_state *state, const char *name);
3737

3838
bool fw3_check_ipset(struct fw3_ipset *set);
3939

40+
void
41+
fw3_ipsets_update_run_state(enum fw3_family family, struct fw3_state *run_state,
42+
struct fw3_state *cfg_state);
43+
4044
static inline void fw3_free_ipset(struct fw3_ipset *ipset)
4145
{
4246
list_del(&ipset->list);

main.c

+1
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ reload(void)
354354
fw3_ipt_close(handle);
355355
}
356356

357+
fw3_ipsets_update_run_state(family, run_state, cfg_state);
357358
fw3_destroy_ipsets(run_state, family, true);
358359

359360
family_set(run_state, family, false);

utils.c

+5-2
Original file line numberDiff line numberDiff line change
@@ -586,8 +586,11 @@ write_ipset_uci(struct uci_context *ctx, struct fw3_ipset *s,
586586
uci_set(ctx, &ptr);
587587

588588
ptr.o = NULL;
589-
ptr.option = "reload_set";
590-
ptr.value = s->reload_set ? "true" : "false";
589+
ptr.option = "family";
590+
if (s->family == FW3_FAMILY_V4)
591+
ptr.value = "ipv4";
592+
else
593+
ptr.value = "ipv6";
591594
uci_set(ctx, &ptr);
592595

593596
ptr.o = NULL;

0 commit comments

Comments
 (0)