From a32e331a11034403df2e26807df9195435b6fb8a Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sun, 17 Feb 2013 20:22:18 +0100 Subject: [PATCH] separate state and lock files, use state file information to purge ipsets --- ipsets.c | 24 ++++++++++---- main.c | 39 +++++++++++++++------- utils.c | 98 ++++++++++++++++++++++++++++++++------------------------ utils.h | 12 ++++--- 4 files changed, 110 insertions(+), 63 deletions(-) diff --git a/ipsets.c b/ipsets.c index 3d659e2..6d7ff78 100644 --- a/ipsets.c +++ b/ipsets.c @@ -353,22 +353,32 @@ fw3_create_ipsets(struct fw3_state *state) void fw3_destroy_ipsets(struct fw3_state *state) { - struct fw3_ipset *ipset; + FILE *sf; - if (state->disable_ipsets) + char *p; + char line[128]; + + sf = fopen(FW3_STATEFILE, "r"); + + if (!sf) return; info("Destroying ipsets ..."); - list_for_each_entry(ipset, &state->ipsets, list) + while (fgets(line, sizeof(line), sf)) { - if (ipset->external && *ipset->external) + if (strncmp(line, "ipset ", 6)) + continue; + + p = strtok(line+6, " \t\n"); + + if (!p || !strlen(p)) continue; - info(" * %s", ipset->name); + info(" * %s", p); - fw3_pr("flush %s\n", ipset->name); - fw3_pr("destroy %s\n", ipset->name); + fw3_pr("flush %s\n", p); + fw3_pr("destroy %s\n", p); } fw3_pr("quit\n"); diff --git a/main.c b/main.c index ddbd24d..a260d7d 100644 --- a/main.c +++ b/main.c @@ -306,6 +306,9 @@ int main(int argc, char **argv) state = build_state(); + if (!fw3_lock()) + goto out; + if (optind >= argc) { rv = usage(); @@ -314,6 +317,8 @@ int main(int argc, char **argv) if (!strcmp(argv[optind], "print")) { + freopen("/dev/null", "w", stderr); + state->disable_ipsets = true; print_rules = true; @@ -324,38 +329,48 @@ int main(int argc, char **argv) } else if (!strcmp(argv[optind], "start")) { - if (!fw3_check_statefile(false)) + if (fw3_has_state()) + { + warn("The firewall appears to be started already. " + "If it is indeed empty, remove the %s file and retry.", + FW3_STATEFILE); + goto out; + } rv = start(state); - fw3_close_statefile(); + fw3_write_state(state); } else if (!strcmp(argv[optind], "stop")) { - if (!fw3_check_statefile(true)) + if (!fw3_has_state()) + { + warn("The firewall appears to be stopped. " + "Use the 'flush' command to forcefully purge all rules."); + goto out; + } rv = stop(state, false); - fw3_remove_statefile(); + fw3_remove_state(); } else if (!strcmp(argv[optind], "flush")) { rv = stop(state, true); - fw3_remove_statefile(); + + if (fw3_has_state()) + fw3_remove_state(); } else if (!strcmp(argv[optind], "restart")) { - if (fw3_check_statefile(true)) + if (fw3_has_state()) { stop(state, false); - fw3_remove_statefile(); + fw3_remove_state(); } - if (!fw3_check_statefile(false)) - goto out; - rv = start(state); - fw3_close_statefile(); + fw3_write_state(state); } else if (!strcmp(argv[optind], "network") && (optind + 1) < argc) { @@ -374,5 +389,7 @@ out: if (state) free_state(state); + fw3_unlock(); + return rv; } diff --git a/utils.c b/utils.c index 9899d4d..5198305 100644 --- a/utils.c +++ b/utils.c @@ -295,70 +295,86 @@ fw3_has_table(bool ipv6, const char *table) return seen; } + bool -fw3_check_statefile(bool test_exists) +fw3_lock(void) { - struct stat s; + lock_fd = open(FW3_LOCKFILE, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); - if (!stat(FW3_STATEFILE, &s)) + if (lock_fd < 0) { - if (test_exists) - return true; - - warn("The firewall appears to be started already. " - "If it is indeed empty, remove the %s file and retry.", - FW3_STATEFILE); - + warn("Cannot create lock file %s: %s", FW3_LOCKFILE, strerror(errno)); return false; } - else if (test_exists) + + if (flock(lock_fd, LOCK_EX)) { - warn("The firewall appears to stopped already."); + warn("Cannot acquire exclusive lock: %s", strerror(errno)); return false; } - lock_fd = open(FW3_STATEFILE, O_CREAT | O_RDWR); + return true; +} +void +fw3_unlock(void) +{ if (lock_fd < 0) + return; + + if (flock(lock_fd, LOCK_UN)) + warn("Cannot release exclusive lock: %s", strerror(errno)); + + close(lock_fd); + unlink(FW3_LOCKFILE); + + lock_fd = -1; +} + + +bool fw3_has_state(void) +{ + struct stat s; + return !stat(FW3_STATEFILE, &s); +} + +void fw3_write_state(void *state) +{ + int fd; + struct fw3_state *s = state; + struct fw3_zone *z; + struct fw3_ipset *i; + + fd = open(FW3_STATEFILE, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR); + + if (fd < 0) { - warn("Unable to create %s file", FW3_STATEFILE); - goto fail; + warn("Cannot create state %s: %s", FW3_STATEFILE, strerror(errno)); + return; } - if (flock(lock_fd, LOCK_EX)) + list_for_each_entry(z, &s->zones, list) { - warn("Unable to acquire exclusive lock on %s file", FW3_STATEFILE); - goto fail; - + write(fd, "zone ", 5); + write(fd, z->name, strlen(z->name)); + write(fd, "\n", 1); } - return true; - -fail: - if (lock_fd > -1) + list_for_each_entry(i, &s->ipsets, list) { - close(lock_fd); - lock_fd = -1; + if (i->external && *i->external) + continue; + + write(fd, "ipset ", 6); + write(fd, i->name, strlen(i->name)); + write(fd, "\n", 1); } - return false; + close(fd); } -void -fw3_remove_statefile(void) +void fw3_remove_state(void) { - if (lock_fd > -1) - fw3_close_statefile(); - if (unlink(FW3_STATEFILE)) - warn("Unable to delete %s file", FW3_STATEFILE); -} - -void -fw3_close_statefile(void) -{ - flock(lock_fd, LOCK_UN); - close(lock_fd); - - lock_fd = -1; + warn("Unable to remove state %s: %s", FW3_STATEFILE, strerror(errno)); } diff --git a/utils.h b/utils.h index efce382..90d7c9a 100644 --- a/utils.h +++ b/utils.h @@ -32,7 +32,8 @@ #include -#define FW3_STATEFILE "/var/run/fw3.lock" +#define FW3_STATEFILE "/var/run/fw3.state" +#define FW3_LOCKFILE "/var/run/fw3.lock" void warn_elem(struct uci_element *e, const char *format, ...); void warn(const char *format, ...); @@ -71,8 +72,11 @@ void fw3_pr(const char *fmt, ...); bool fw3_has_table(bool ipv6, const char *table); -bool fw3_check_statefile(bool test_exists); -void fw3_remove_statefile(void); -void fw3_close_statefile(void); +bool fw3_lock(void); +void fw3_unlock(void); + +bool fw3_has_state(void); +void fw3_write_state(void *state); +void fw3_remove_state(void); #endif -- 2.25.1