Added chain_exists() check to fwknopd SPA rule creation
authorMichael Rash <mbr@cipherdyne.org>
Tue, 13 Nov 2012 02:48:26 +0000 (21:48 -0500)
committerMichael Rash <mbr@cipherdyne.org>
Tue, 13 Nov 2012 02:48:26 +0000 (21:48 -0500)
Added chain_exists() check to SPA rule creation so that if any
of the fwknop chains are deleted out from under fwknopd they will be
recreated on the fly.  This mitigates scenarios where fwknopd might be
started before a system level firewall policy is applied due to init
script ordering, or if an iptables policy is re-applied without
restarting fwknopd.

ChangeLog
server/fw_util_iptables.c
server/fw_util_iptables.h

index df0453c..2a0805d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -66,6 +66,12 @@ fwknop-2.0.4 (11//2012):
     - [server] Added a new '--pcap-file <file>' option to allow pcap files to
       be processed directly by fwknopd instead of sniffing an interface.  This
       feature is mostly intended for debugging purposes.
+    - [server] Added chain_exists() check to SPA rule creation so that if any
+      of the fwknop chains are deleted out from under fwknopd they will be
+      recreated on the fly.  This mitigates scenarios where fwknopd might be
+      started before a system level firewall policy is applied due to init
+      script ordering, or if an iptables policy is re-applied without
+      restarting fwknopd.
 
 fwknop-2.0.3 (09/03/2012):
     - [server] Fernando Arnaboldi from IOActive found several DoS/code
index 929becd..1f203b0 100644 (file)
@@ -148,6 +148,35 @@ add_jump_rule(const fko_srv_options_t *opts, const int chain_num)
 }
 
 static int
+chain_exists(const fko_srv_options_t *opts, const int chain_num)
+{
+    int res = 0;
+
+    zero_cmd_buffers();
+
+    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHAIN_EXISTS_ARGS,
+        fwc.fw_command,
+        fwc.chain[chain_num].table,
+        fwc.chain[chain_num].to_chain
+    );
+
+    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
+
+    if (opts->verbose)
+        log_msg(LOG_INFO, "chain_exists() CMD: '%s' (res: %d, err: %s)",
+            cmd_buf, res, err_buf);
+
+    if(EXTCMD_IS_SUCCESS(res))
+        log_msg(LOG_INFO, "'%s' table '%s' chain exists",
+            fwc.chain[chain_num].table,
+            fwc.chain[chain_num].to_chain);
+    else
+        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
+
+    return res;
+}
+
+static int
 jump_rule_exists(const int chain_num)
 {
     int     num, pos = 0;
@@ -344,49 +373,59 @@ delete_all_chains(const fko_srv_options_t *opts)
     }
 }
 
+static int
+create_chain(const fko_srv_options_t *opts, const int chain_num)
+{
+    int res = 0;
+
+    zero_cmd_buffers();
+
+    /* Create the custom chain.
+    */
+    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS,
+        fwc.fw_command,
+        fwc.chain[chain_num].table,
+        fwc.chain[chain_num].to_chain
+    );
+
+    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
+
+    if (opts->verbose)
+        log_msg(LOG_INFO, "create_chain() CMD: '%s' (res: %d, err: %s)",
+            cmd_buf, res, err_buf);
+
+    /* Expect full success on this */
+    if(! EXTCMD_IS_SUCCESS(res))
+        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
+
+    return res;
+}
+
 /* Create the fwknop custom chains (at least those that are configured).
 */
 static int
 create_fw_chains(const fko_srv_options_t *opts)
 {
-    int     i;
-    int     res, got_err = 0;
+    int     i, got_err = 0;
 
     for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
     {
         if(fwc.chain[i].target[0] == '\0')
             continue;
 
-        zero_cmd_buffers();
-
-        /* Create the custom chain.
-        */
-        snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS,
-            fwc.fw_command,
-            fwc.chain[i].table,
-            fwc.chain[i].to_chain
-        );
-
-        res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
-
-        if (opts->verbose)
-            log_msg(LOG_INFO, "create_fw_chains() CMD: '%s' (res: %d, err: %s)",
-                cmd_buf, res, err_buf);
-
-        /* Expect full success on this */
-        if(! EXTCMD_IS_SUCCESS(res))
+        if(chain_exists(opts, i) == 0)
         {
-            log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
-            got_err++;
-        }
 
-        /* Then create the jump rule to that chain.
-        */
-        res = add_jump_rule(opts, i);
+            /* Create the chain
+            */
+            if(! EXTCMD_IS_SUCCESS(create_chain(opts, i)))
+                got_err++;
 
-        /* Expect full success on this */
-        if(! EXTCMD_IS_SUCCESS(res))
-            got_err++;
+            /* Then create the jump rule to that chain.
+            */
+            if(! EXTCMD_IS_SUCCESS(add_jump_rule(opts, i)))
+                got_err++;
+        }
     }
 
     return(got_err);
@@ -612,12 +651,20 @@ process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_
         /* Check to make sure that the jump rules exist for each
          * required chain
         */
+        if(chain_exists(opts, IPT_INPUT_ACCESS) == 0)
+            create_chain(opts, IPT_INPUT_ACCESS);
+
         if(jump_rule_exists(IPT_INPUT_ACCESS) == 0)
             add_jump_rule(opts, IPT_INPUT_ACCESS);
 
         if(out_chain->to_chain != NULL && strlen(out_chain->to_chain))
+        {
+            if(chain_exists(opts, IPT_OUTPUT_ACCESS) == 0)
+                create_chain(opts, IPT_OUTPUT_ACCESS);
+
             if(jump_rule_exists(IPT_OUTPUT_ACCESS) == 0)
                 add_jump_rule(opts, IPT_OUTPUT_ACCESS);
+        }
 
         /* Create an access command for each proto/port for the source ip.
         */
@@ -776,8 +823,11 @@ process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_
         else if(fwd_chain->to_chain != NULL && strlen(fwd_chain->to_chain))
         {
             /* Make our FORWARD and NAT rules, and make sure the
-             * required jump rule exists
+             * required chain and jump rule exists
             */
+            if(chain_exists(opts, IPT_FORWARD_ACCESS) == 0)
+                create_chain(opts, IPT_FORWARD_ACCESS);
+
             if (jump_rule_exists(IPT_FORWARD_ACCESS) == 0)
                 add_jump_rule(opts, IPT_FORWARD_ACCESS);
 
@@ -823,8 +873,11 @@ process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_
         if(dnat_chain->to_chain != NULL && strlen(dnat_chain->to_chain))
         {
 
-            /* Make sure the required jump rule exists
+            /* Make sure the required chain and jump rule exists
             */
+            if(chain_exists(opts, IPT_DNAT_ACCESS) == 0)
+                create_chain(opts, IPT_DNAT_ACCESS);
+
             if (jump_rule_exists(IPT_DNAT_ACCESS) == 0)
                 add_jump_rule(opts, IPT_DNAT_ACCESS);
 
index 9c706e5..04af230 100644 (file)
@@ -44,6 +44,7 @@
 #define IPT_DEL_RULE_ARGS       "-t %s -D %s %i 2>&1"
 #define IPT_NEW_CHAIN_ARGS      "-t %s -N %s 2>&1"
 #define IPT_FLUSH_CHAIN_ARGS    "-t %s -F %s 2>&1"
+#define IPT_CHAIN_EXISTS_ARGS   "-t %s -L %s -n 2>&1"
 #define IPT_DEL_CHAIN_ARGS      "-t %s -X %s 2>&1"
 #define IPT_ADD_JUMP_RULE_ARGS  "-t %s -I %s %i -j %s 2>&1"
 #define IPT_LIST_RULES_ARGS     "-t %s -L %s --line-numbers -n 2>&1"