void
fw3_flush_rules(enum fw3_table table, enum fw3_family family,
- bool pass2, struct list_head *statefile)
+ bool pass2, struct fw3_state *state)
{
- struct fw3_statefile_entry *e;
+ struct fw3_defaults *d = &state->running_defaults;
- list_for_each_entry(e, statefile, list)
+ if (!hasbit(d->flags, family))
+ return;
+
+ if (!pass2)
{
- if (e->type != FW3_TYPE_DEFAULTS)
- continue;
+ reset_policy(table);
- if (!pass2)
- {
- reset_policy(table);
+ print_chains(table, family, "-D %s\n", state->running_defaults.flags,
+ toplevel_rules, ARRAY_SIZE(toplevel_rules));
- print_chains(table, family, "-D %s\n", e->flags[0],
- toplevel_rules, ARRAY_SIZE(toplevel_rules));
+ print_chains(table, family, "-F %s\n", state->running_defaults.flags,
+ default_chains, ARRAY_SIZE(default_chains));
+ }
+ else
+ {
+ print_chains(table, family, "-X %s\n", state->running_defaults.flags,
+ default_chains, ARRAY_SIZE(default_chains));
- print_chains(table, family, "-F %s\n", e->flags[0],
- default_chains, ARRAY_SIZE(default_chains));
- }
- else
- {
- print_chains(table, family, "-X %s\n", e->flags[0],
- default_chains, ARRAY_SIZE(default_chains));
- }
+ delbit(d->flags, family);
}
}
struct fw3_state *state);
void fw3_flush_rules(enum fw3_table table, enum fw3_family family,
- bool pass2, struct list_head *statefile);
+ bool pass2, struct fw3_state *state);
void fw3_flush_all(enum fw3_table table);
continue;
}
else if (forward->src.set && !forward->src.any &&
- !(forward->_src = fw3_lookup_zone(state, forward->src.name)))
+ !(forward->_src = fw3_lookup_zone(state, forward->src.name, false)))
{
warn_elem(e, "refers to not existing zone '%s'", forward->src.name);
fw3_free_forward(forward);
continue;
}
else if (forward->dest.set && !forward->dest.any &&
- !(forward->_dest = fw3_lookup_zone(state, forward->dest.name)))
+ !(forward->_dest = fw3_lookup_zone(state, forward->dest.name, false)))
{
warn_elem(e, "refers to not existing zone '%s'", forward->dest.name);
fw3_free_forward(forward);
return false;
}
+struct fw3_ipset *
+fw3_alloc_ipset(void)
+{
+ struct fw3_ipset *ipset;
+
+ ipset = malloc(sizeof(*ipset));
+
+ if (!ipset)
+ return NULL;
+
+ memset(ipset, 0, sizeof(*ipset));
+
+ INIT_LIST_HEAD(&ipset->datatypes);
+ INIT_LIST_HEAD(&ipset->iprange);
+
+ return ipset;
+}
+
void
fw3_load_ipsets(struct fw3_state *state, struct uci_package *p)
{
if (strcmp(s->type, "ipset"))
continue;
- ipset = malloc(sizeof(*ipset));
+ ipset = fw3_alloc_ipset();
if (!ipset)
continue;
- memset(ipset, 0, sizeof(*ipset));
-
- INIT_LIST_HEAD(&ipset->datatypes);
- INIT_LIST_HEAD(&ipset->iprange);
-
fw3_parse_options(ipset, ipset_opts, ARRAY_SIZE(ipset_opts), s);
if (!ipset->name || !*ipset->name)
static void
-create_ipset(struct fw3_ipset *ipset)
+create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
{
bool first = true;
char s[INET6_ADDRSTRLEN];
fw3_pr(" hashsize %u", ipset->hashsize);
fw3_pr("\n");
-}
-
-static bool
-ipset_loaded(struct list_head *statefile, const char *name)
-{
- struct fw3_statefile_entry *e;
- int mask = (1 << FW3_FAMILY_V4) | (1 << FW3_FAMILY_V6);
-
- if (!statefile)
- return false;
- list_for_each_entry(e, statefile, list)
- {
- if (e->type != FW3_TYPE_IPSET)
- continue;
-
- if (!strcmp(e->name, name) && (e->flags[0] & mask))
- return true;
- }
-
- return false;
+ fw3_set_running(ipset, &state->running_ipsets);
}
void
-fw3_create_ipsets(struct fw3_state *state, struct list_head *statefile)
+fw3_create_ipsets(struct fw3_state *state)
{
struct fw3_ipset *ipset;
return;
list_for_each_entry(ipset, &state->ipsets, list)
- if (!ipset_loaded(statefile, ipset->name))
- create_ipset(ipset);
+ if (!fw3_lookup_ipset(state, ipset->name, true))
+ create_ipset(ipset, state);
fw3_pr("quit\n");
}
void
-fw3_destroy_ipsets(struct fw3_state *state, struct list_head *statefile)
+fw3_destroy_ipsets(struct fw3_state *state)
{
- struct fw3_ipset *s;
- struct fw3_statefile_entry *e;
+ struct fw3_ipset *s, *tmp;
int mask = (1 << FW3_FAMILY_V4) | (1 << FW3_FAMILY_V6);
- if (!statefile)
- return;
-
- list_for_each_entry(e, statefile, list)
+ list_for_each_entry_safe(s, tmp, &state->running_ipsets, running_list)
{
- if (e->type != FW3_TYPE_IPSET)
- continue;
-
if (!hasbit(state->defaults.flags, FW3_FAMILY_V4))
- delbit(e->flags[0], FW3_FAMILY_V4);
+ delbit(s->flags, FW3_FAMILY_V4);
if (!hasbit(state->defaults.flags, FW3_FAMILY_V6))
- delbit(e->flags[0], FW3_FAMILY_V6);
+ delbit(s->flags, FW3_FAMILY_V6);
- if ((s = fw3_lookup_ipset(state, e->name)) != NULL)
- s->flags = e->flags[0];
-
- if (!(e->flags[0] & mask))
+ if (!(s->flags & mask))
{
- info("Deleting ipset %s", e->name);
+ info("Deleting ipset %s", s->name);
+
+ fw3_pr("flush %s\n", s->name);
+ fw3_pr("destroy %s\n", s->name);
- fw3_pr("flush %s\n", e->name);
- fw3_pr("destroy %s\n", e->name);
+ fw3_set_running(s, NULL);
}
}
}
}
struct fw3_ipset *
-fw3_lookup_ipset(struct fw3_state *state, const char *name)
+fw3_lookup_ipset(struct fw3_state *state, const char *name, bool running)
{
- struct fw3_ipset *ipset;
+ struct fw3_ipset *s;
if (list_empty(&state->ipsets))
return NULL;
- list_for_each_entry(ipset, &state->ipsets, list)
- if (!strcmp(ipset->name, name))
- return ipset;
+ list_for_each_entry(s, &state->ipsets, list)
+ {
+ if (strcmp(s->name, name))
+ continue;
+
+ if (!running || s->running_list.next)
+ return s;
+
+ break;
+ }
return NULL;
}
uint8_t optional;
};
+struct fw3_ipset * fw3_alloc_ipset(void);
void fw3_load_ipsets(struct fw3_state *state, struct uci_package *p);
-void fw3_create_ipsets(struct fw3_state *state, struct list_head *statefile);
-void fw3_destroy_ipsets(struct fw3_state *state, struct list_head *statefile);
+void fw3_create_ipsets(struct fw3_state *state);
+void fw3_destroy_ipsets(struct fw3_state *state);
void fw3_free_ipset(struct fw3_ipset *ipset);
-struct fw3_ipset * fw3_lookup_ipset(struct fw3_state *state, const char *name);
+struct fw3_ipset * fw3_lookup_ipset(struct fw3_state *state, const char *name,
+ bool running);
#endif
state->disable_ipsets = true;
}
+ INIT_LIST_HEAD(&state->running_zones);
+ INIT_LIST_HEAD(&state->running_ipsets);
+
fw3_load_defaults(state, p);
fw3_load_ipsets(state, p);
fw3_load_zones(state, p);
fw3_load_redirects(state, p);
fw3_load_forwards(state, p);
+ state->statefile = fw3_read_statefile(state);
+
return state;
}
list_for_each_safe(cur, tmp, &state->forwards)
fw3_free_forward((struct fw3_forward *)cur);
+ list_for_each_safe(cur, tmp, &state->ipsets)
+ fw3_free_ipset((struct fw3_ipset *)cur);
+
uci_free_context(state->uci);
free(state);
}
static bool
-family_running(struct list_head *statefile, enum fw3_family family)
+family_running(struct fw3_state *state, enum fw3_family family)
{
- struct fw3_statefile_entry *e;
-
- if (statefile)
- {
- list_for_each_entry(e, statefile, list)
- {
- if (e->type != FW3_TYPE_DEFAULTS)
- continue;
-
- return hasbit(e->flags[0], family);
- }
- }
-
- return false;
+ return hasbit(state->running_defaults.flags, family);
}
static bool
enum fw3_family family;
enum fw3_table table;
- struct list_head *statefile = fw3_read_statefile();
-
- if (!complete && !statefile)
+ if (!complete && !state->statefile)
{
if (!restart)
warn("The firewall appears to be stopped. "
for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
{
- if (!complete && !family_running(statefile, family))
+ if (!complete && !family_running(state, family))
continue;
if (!family_used(family) || !restore_pipe(family, true))
else
{
/* pass 1 */
- fw3_flush_rules(table, family, false, statefile);
- fw3_flush_zones(table, family, false, statefile);
+ fw3_flush_rules(table, family, false, state);
+ fw3_flush_zones(table, family, false, state);
/* pass 2 */
- fw3_flush_rules(table, family, true, statefile);
- fw3_flush_zones(table, family, true, statefile);
+ fw3_flush_rules(table, family, true, state);
+ fw3_flush_zones(table, family, true, state);
}
fw3_pr("COMMIT\n");
if (!restart && fw3_command_pipe(false, "ipset", "-exist", "-"))
{
- fw3_destroy_ipsets(state, statefile);
+ fw3_destroy_ipsets(state);
fw3_command_close();
}
- fw3_free_statefile(statefile);
-
if (!rv)
fw3_write_statefile(state);
enum fw3_family family;
enum fw3_table table;
- struct list_head *statefile = fw3_read_statefile();
-
if (!print_rules && !restart &&
fw3_command_pipe(false, "ipset", "-exist", "-"))
{
- fw3_create_ipsets(state, statefile);
+ fw3_create_ipsets(state);
fw3_command_close();
}
if (!family_used(family))
continue;
- if (!family_loaded(state, family) || !restore_pipe(family, false))
- continue;
-
- if (!print_rules && !restart && family_running(statefile, family))
+ if (!print_rules && !restart && family_running(state, family))
{
warn("The %s firewall appears to be started already. "
"If it is indeed empty, remove the %s file and retry.",
continue;
}
+ if (!family_loaded(state, family) || !restore_pipe(family, false))
+ continue;
+
info("Constructing %s rules ...", fw3_flag_names[family]);
for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
rv = 0;
}
- fw3_free_statefile(statefile);
-
if (!rv && !print_rules)
fw3_write_statefile(state);
struct fw3_zone
{
struct list_head list;
+ struct list_head running_list;
const char *name;
struct fw3_ipset
{
struct list_head list;
+ struct list_head running_list;
const char *name;
enum fw3_family family;
struct list_head forwards;
struct list_head ipsets;
+ struct fw3_defaults running_defaults;
+ struct list_head running_zones;
+ struct list_head running_ipsets;
+
bool disable_ipsets;
+ bool statefile;
};
continue;
}
else if (redir->src.set && !redir->src.any &&
- !(redir->_src = fw3_lookup_zone(state, redir->src.name)))
+ !(redir->_src = fw3_lookup_zone(state, redir->src.name, false)))
{
warn_elem(e, "refers to not existing zone '%s'", redir->src.name);
fw3_free_redirect(redir);
continue;
}
else if (redir->dest.set && !redir->dest.any &&
- !(redir->_dest = fw3_lookup_zone(state, redir->dest.name)))
+ !(redir->_dest = fw3_lookup_zone(state, redir->dest.name, false)))
{
warn_elem(e, "refers to not existing zone '%s'", redir->dest.name);
fw3_free_redirect(redir);
continue;
}
else if (redir->ipset.set && !redir->ipset.any &&
- !(redir->_ipset = fw3_lookup_ipset(state, redir->ipset.name)))
+ !(redir->_ipset = fw3_lookup_ipset(state, redir->ipset.name, false)))
{
warn_elem(e, "refers to unknown ipset '%s'", redir->ipset.name);
fw3_free_redirect(redir);
continue;
}
else if (rule->src.set && !rule->src.any &&
- !(rule->_src = fw3_lookup_zone(state, rule->src.name)))
+ !(rule->_src = fw3_lookup_zone(state, rule->src.name, false)))
{
warn_elem(e, "refers to not existing zone '%s'", rule->src.name);
fw3_free_rule(rule);
continue;
}
else if (rule->dest.set && !rule->dest.any &&
- !(rule->_dest = fw3_lookup_zone(state, rule->dest.name)))
+ !(rule->_dest = fw3_lookup_zone(state, rule->dest.name, false)))
{
warn_elem(e, "refers to not existing zone '%s'", rule->dest.name);
fw3_free_rule(rule);
continue;
}
else if (rule->ipset.set && !rule->ipset.any &&
- !(rule->_ipset = fw3_lookup_ipset(state, rule->ipset.name)))
+ !(rule->_ipset = fw3_lookup_ipset(state, rule->ipset.name, false)))
{
warn_elem(e, "refers to unknown ipset '%s'", rule->ipset.name);
fw3_free_rule(rule);
#include "utils.h"
#include "options.h"
+#include "zones.h"
+#include "ipsets.h"
+
+
static int lock_fd = -1;
static pid_t pipe_pid = -1;
static FILE *pipe_fd = NULL;
}
-struct list_head *
-fw3_read_statefile(void)
+bool
+fw3_read_statefile(void *state)
{
FILE *sf;
- int n;
+ int n, type;
char line[128];
- const char *p;
+ const char *p, *name;
- struct list_head *state;
- struct fw3_statefile_entry *entry;
+ uint16_t flags[2];
+
+ struct fw3_state *s = state;
+ struct fw3_zone *zone;
+ struct fw3_ipset *ipset;
sf = fopen(FW3_STATEFILE, "r");
if (!sf)
- return NULL;
-
- state = malloc(sizeof(*state));
-
- if (!state)
- return NULL;
-
- INIT_LIST_HEAD(state);
+ return false;
while (fgets(line, sizeof(line), sf))
{
- entry = malloc(sizeof(*entry));
-
- if (!entry)
- continue;
-
- memset(entry, 0, sizeof(*entry));
-
p = strtok(line, " \t\n");
if (!p)
continue;
- entry->type = strtoul(p, NULL, 10);
-
- p = strtok(NULL, " \t\n");
+ type = strtoul(p, NULL, 10);
+ name = strtok(NULL, " \t\n");
- if (!p)
+ if (!name)
continue;
- entry->name = strdup(p);
-
for (n = 0, p = strtok(NULL, " \t\n");
- n < ARRAY_SIZE(entry->flags) && p != NULL;
+ n < ARRAY_SIZE(flags) && p != NULL;
n++, p = strtok(NULL, " \t\n"))
{
- entry->flags[n] = strtoul(p, NULL, 10);
+ flags[n] = strtoul(p, NULL, 10);
}
- list_add_tail(&entry->list, state);
+ switch (type)
+ {
+ case FW3_TYPE_DEFAULTS:
+ s->running_defaults.flags = flags[0];
+ break;
+
+ case FW3_TYPE_ZONE:
+ if (!(zone = fw3_lookup_zone(state, name, false)))
+ {
+ zone = fw3_alloc_zone();
+
+ if (!zone)
+ continue;
+
+ zone->name = strdup(name);
+ list_add_tail(&zone->list, &s->zones);
+ }
+
+ zone->src_flags = flags[0];
+ zone->dst_flags = flags[1];
+ list_add_tail(&zone->running_list, &s->running_zones);
+ break;
+
+ case FW3_TYPE_IPSET:
+ if (!(ipset = fw3_lookup_ipset(state, name, false)))
+ {
+ ipset = fw3_alloc_ipset();
+
+ if (!ipset)
+ continue;
+
+ ipset->name = strdup(name);
+ list_add_tail(&ipset->list, &s->ipsets);
+ }
+
+ ipset->flags = flags[0];
+ list_add_tail(&ipset->running_list, &s->running_ipsets);
+ break;
+ }
}
fclose(sf);
- return state;
+ return true;
}
void
fprintf(sf, "%u - %u\n", FW3_TYPE_DEFAULTS, d->flags);
- list_for_each_entry(z, &s->zones, list)
+ list_for_each_entry(z, &s->running_zones, running_list)
{
fprintf(sf, "%u %s %u %u\n", FW3_TYPE_ZONE,
z->name, z->src_flags, z->dst_flags);
}
- list_for_each_entry(i, &s->ipsets, list)
+ list_for_each_entry(i, &s->running_ipsets, running_list)
{
- if (i->external && *i->external)
- continue;
-
- if (!i->flags)
- continue;
-
fprintf(sf, "%u %s %u\n", FW3_TYPE_IPSET, i->name, i->flags);
}
fclose(sf);
}
-void
-fw3_free_statefile(struct list_head *statefile)
-{
- struct fw3_statefile_entry *e, *tmp;
- if (!statefile)
- return;
+struct object_list_heads
+{
+ struct list_head list;
+ struct list_head running_list;
+};
- list_for_each_entry_safe(e, tmp, statefile, list)
- {
- list_del(&e->list);
- free(e->name);
- free(e);
- }
+void
+fw3_set_running(void *object, struct list_head *dest)
+{
+ struct object_list_heads *o = object;
- free(statefile);
+ if (dest && !o->running_list.next)
+ list_add_tail(&o->running_list, dest);
+ else if (!dest && o->running_list.next)
+ list_del(&o->running_list);
}
FW3_TYPE_IPSET = 2,
};
-struct fw3_statefile_entry
-{
- struct list_head list;
- enum fw3_statefile_type type;
- char *name;
- uint32_t flags[2];
-};
-
-struct list_head * fw3_read_statefile(void);
+bool fw3_read_statefile(void *state);
void fw3_write_statefile(void *state);
-void fw3_free_statefile(struct list_head *statefile);
+
+void fw3_set_running(void *object, struct list_head *dest);
#endif
}
}
+struct fw3_zone *
+fw3_alloc_zone(void)
+{
+ struct fw3_zone *zone;
+
+ zone = malloc(sizeof(*zone));
+
+ if (!zone)
+ return NULL;
+
+ memset(zone, 0, sizeof(*zone));
+
+ INIT_LIST_HEAD(&zone->networks);
+ INIT_LIST_HEAD(&zone->devices);
+ INIT_LIST_HEAD(&zone->subnets);
+ INIT_LIST_HEAD(&zone->masq_src);
+ INIT_LIST_HEAD(&zone->masq_dest);
+
+ zone->log_limit.rate = 10;
+
+ return zone;
+}
+
void
fw3_load_zones(struct fw3_state *state, struct uci_package *p)
{
if (strcmp(s->type, "zone"))
continue;
- zone = malloc(sizeof(*zone));
+ zone = fw3_alloc_zone();
if (!zone)
continue;
- memset(zone, 0, sizeof(*zone));
-
- INIT_LIST_HEAD(&zone->networks);
- INIT_LIST_HEAD(&zone->devices);
- INIT_LIST_HEAD(&zone->subnets);
- INIT_LIST_HEAD(&zone->masq_src);
- INIT_LIST_HEAD(&zone->masq_dest);
-
- zone->log_limit.rate = 10;
-
fw3_parse_options(zone, zone_opts, ARRAY_SIZE(zone_opts), s);
if (!zone->extra_dest)
static void
print_zone_chain(enum fw3_table table, enum fw3_family family,
- struct fw3_zone *zone, bool disable_notrack)
+ struct fw3_zone *zone, struct fw3_state *state)
{
bool s, d;
setbit(zone->dst_flags, family);
- if (!zone->conntrack && !disable_notrack)
+ if (!zone->conntrack && !state->defaults.drop_invalid)
setbit(zone->dst_flags, FW3_TARGET_NOTRACK);
s = print_chains(table, family, ":%s - [0:0]\n", zone->name,
zone->dst_flags, dst_chains, ARRAY_SIZE(dst_chains));
if (s || d)
+ {
info(" * Zone '%s'", zone->name);
+ fw3_set_running(zone, &state->running_zones);
+ }
}
static void
struct fw3_zone *zone;
list_for_each_entry(zone, &state->zones, list)
- print_zone_chain(table, family, zone, state->defaults.drop_invalid);
+ print_zone_chain(table, family, zone, state);
}
void
void
fw3_flush_zones(enum fw3_table table, enum fw3_family family,
- bool pass2, struct list_head *statefile)
+ bool pass2, struct fw3_state *state)
{
- struct fw3_statefile_entry *e;
+ struct fw3_zone *z, *tmp;
+ int mask = (1 << FW3_FAMILY_V4) | (1 << FW3_FAMILY_V6);
- list_for_each_entry(e, statefile, list)
+ list_for_each_entry_safe(z, tmp, &state->running_zones, running_list)
{
- if (e->type != FW3_TYPE_ZONE)
- continue;
-
- if (!hasbit(e->flags[1], family))
+ if (!hasbit(z->dst_flags, family))
continue;
print_chains(table, family, pass2 ? "-X %s\n" : "-F %s\n",
- e->name, e->flags[0], src_chains, ARRAY_SIZE(src_chains));
+ z->name, z->src_flags, src_chains, ARRAY_SIZE(src_chains));
print_chains(table, family, pass2 ? "-X %s\n" : "-F %s\n",
- e->name, e->flags[1], dst_chains, ARRAY_SIZE(dst_chains));
+ z->name, z->dst_flags, dst_chains, ARRAY_SIZE(dst_chains));
+
+ if (pass2)
+ {
+ delbit(z->dst_flags, family);
+
+ if (!(z->dst_flags & mask))
+ fw3_set_running(z, NULL);
+ }
}
}
struct fw3_zone *
-fw3_lookup_zone(struct fw3_state *state, const char *name)
+fw3_lookup_zone(struct fw3_state *state, const char *name, bool running)
{
struct fw3_zone *z;
return NULL;
list_for_each_entry(z, &state->zones, list)
- if (!strcmp(z->name, name))
+ {
+ if (strcmp(z->name, name))
+ continue;
+
+ if (!running || z->running_list.next)
return z;
+ break;
+ }
+
return NULL;
}
#include "options.h"
+struct fw3_zone * fw3_alloc_zone(void);
+
void fw3_load_zones(struct fw3_state *state, struct uci_package *p);
void fw3_print_zone_chains(enum fw3_table table, enum fw3_family family,
struct fw3_state *state);
void fw3_flush_zones(enum fw3_table table, enum fw3_family family,
- bool pass2, struct list_head *statefile);
+ bool pass2, struct fw3_state *state);
-struct fw3_zone * fw3_lookup_zone(struct fw3_state *state, const char *name);
+struct fw3_zone * fw3_lookup_zone(struct fw3_state *state, const char *name,
+ bool running);
void fw3_free_zone(struct fw3_zone *zone);