separate state and lock files, use state file information to purge ipsets
authorJo-Philipp Wich <jow@openwrt.org>
Sun, 17 Feb 2013 19:22:18 +0000 (20:22 +0100)
committerJo-Philipp Wich <jow@openwrt.org>
Sun, 17 Feb 2013 19:22:18 +0000 (20:22 +0100)
ipsets.c
main.c
utils.c
utils.h

index 3d659e2c03039bdb7dc591536e102433ea082626..6d7ff78bd753d5864c0a23170038c3ada1c7749f 100644 (file)
--- 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 ddbd24d60656c5600a0bce0fddddb6ab053daeee..a260d7d827c3f3cb222ed36911c99d8dea20ec5a 100644 (file)
--- 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 9899d4d5d507471848cf0f16b6937f6e467bee82..5198305214ccf0435f0c71c5cc131ef016e06454 100644 (file)
--- 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 efce382a5df616bdfd2147ba7103a540784005e4..90d7c9adba0d06f6b52a66cabca6cbd131f8807e 100644 (file)
--- a/utils.h
+++ b/utils.h
@@ -32,7 +32,8 @@
 #include <uci.h>
 
 
-#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