]> Kevux Git Server - fll/commitdiff
Update: fix firewall utility and utilize recently added functionality
authorKevin Day <thekevinday@gmail.com>
Sun, 21 Jul 2019 21:06:13 +0000 (16:06 -0500)
committerKevin Day <thekevinday@gmail.com>
Sun, 21 Jul 2019 21:06:46 +0000 (16:06 -0500)
There were a few logic flaws in regards to the processing and memory management.
Switch to new logic where f_new_* and f_clear_* is utilized.
Update accodingly to the fll_execute changes.

Update the default configuration files.

Update the debugging code to work as expected.

Replace string cuntions with memory functions, such as replacing strncat with memcpy.

Add some new helper macros.

Delete all custom chains when rewriting rules to prevent problems.
Iptables unfortunately does not provide a way to check and see if a chain already exists.

level_3/firewall/c/firewall.c
level_3/firewall/c/firewall.h
level_3/firewall/c/main.c
level_3/firewall/c/private-firewall.c
level_3/firewall/c/private-firewall.h
level_3/firewall/data/settings/firewall-first
level_3/firewall/data/settings/firewall-last

index 5e66d634afc2eb1ec3ddf2c7ba7e2b93da013727..27c00bbb73249a3373bf879474d8001c33fdfd65 100644 (file)
@@ -267,23 +267,21 @@ extern "C"{
             fl_print_color_line(f_standard_output, data->context.standout, data->context.reset, " ============================");
             fflush(f_standard_output);
 
-            arguments.used = 7;
+            arguments.used = 6;
 
-            arguments.array[0].string = (f_string) firewall_tool_iptables;
-            arguments.array[1].string = (f_string) "-x";
-            arguments.array[2].string = (f_string) "-v";
-            arguments.array[3].string = (f_string) "-t";
-            arguments.array[4].string = (f_string) "nat";
-            arguments.array[5].string = (f_string) "--numeric";
-            arguments.array[6].string = (f_string) "--list";
+            arguments.array[0].string = (f_string) "-x";
+            arguments.array[1].string = (f_string) "-v";
+            arguments.array[2].string = (f_string) "-t";
+            arguments.array[3].string = (f_string) "nat";
+            arguments.array[4].string = (f_string) "--numeric";
+            arguments.array[5].string = (f_string) "--list";
 
-            arguments.array[0].used = firewall_tool_iptables_length;
+            arguments.array[0].used = 2;
             arguments.array[1].used = 2;
             arguments.array[2].used = 2;
-            arguments.array[3].used = 2;
-            arguments.array[4].used = 3;
-            arguments.array[5].used = 9;
-            arguments.array[6].used = 6;
+            arguments.array[3].used = 3;
+            arguments.array[4].used = 9;
+            arguments.array[5].used = 6;
 
             status = fll_execute_program((f_string) firewall_tool_iptables, arguments, &results);
 
@@ -297,23 +295,21 @@ extern "C"{
             fl_print_color_line(f_standard_output, data->context.standout, data->context.reset, " ==========================");
             fflush(f_standard_output);
 
-            arguments.used = 7;
+            arguments.used = 6;
 
-            arguments.array[0].string = (f_string) firewall_tool_iptables;
-            arguments.array[1].string = (f_string) "-x";
-            arguments.array[2].string = (f_string) "-v";
-            arguments.array[3].string = (f_string) "-t";
-            arguments.array[4].string = (f_string) "mangle";
-            arguments.array[5].string = (f_string) "--numeric";
-            arguments.array[6].string = (f_string) "--list";
+            arguments.array[0].string = (f_string) "-x";
+            arguments.array[1].string = (f_string) "-v";
+            arguments.array[2].string = (f_string) "-t";
+            arguments.array[3].string = (f_string) "mangle";
+            arguments.array[4].string = (f_string) "--numeric";
+            arguments.array[5].string = (f_string) "--list";
 
-            arguments.array[0].used = firewall_tool_iptables_length;
+            arguments.array[0].used = 2;
             arguments.array[1].used = 2;
             arguments.array[2].used = 2;
-            arguments.array[3].used = 2;
-            arguments.array[4].used = 3;
-            arguments.array[5].used = 9;
-            arguments.array[6].used = 6;
+            arguments.array[3].used = 6;
+            arguments.array[4].used = 9;
+            arguments.array[5].used = 6;
 
             status = fll_execute_program((f_string) firewall_tool_iptables, arguments, &results);
 
@@ -327,19 +323,17 @@ extern "C"{
             fl_print_color_line(f_standard_output, data->context.standout, data->context.reset, " ===========================");
             fflush(f_standard_output);
 
-            arguments.used = 5;
+            arguments.used = 4;
 
-            arguments.array[0].string = (f_string) firewall_tool_iptables;
-            arguments.array[1].string = (f_string) "-x";
-            arguments.array[2].string = (f_string) "-v";
-            arguments.array[3].string = (f_string) "--numeric";
-            arguments.array[4].string = (f_string) "--list";
+            arguments.array[0].string = (f_string) "-x";
+            arguments.array[1].string = (f_string) "-v";
+            arguments.array[2].string = (f_string) "--numeric";
+            arguments.array[3].string = (f_string) "--list";
 
-            arguments.array[0].used = firewall_tool_iptables_length;
+            arguments.array[0].used = 2;
             arguments.array[1].used = 2;
-            arguments.array[2].used = 2;
-            arguments.array[3].used = 9;
-            arguments.array[4].used = 6;
+            arguments.array[2].used = 9;
+            arguments.array[3].used = 6;
 
             status = fll_execute_program((f_string) firewall_tool_iptables, arguments, &results);
 
@@ -458,6 +452,14 @@ extern "C"{
 
           if (command == firewall_parameter_command_lock) {
             if (reserved.has_lock) {
+              status = firewall_delete_chains(*data);
+
+              if (f_error_is_error(status)) {
+                firewall_delete_local_data(&local);
+                firewall_delete_data(data);
+                return status;
+              }
+
               local.is_main = f_false;
               local.is_stop = f_false;
               local.is_lock = f_true;
@@ -471,7 +473,8 @@ extern "C"{
               firewall_delete_local_data(&local);
               firewall_delete_data(data);
               return status;
-            } else {
+            }
+            else {
               fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Failed to perform lock request because the lock instructions are missing from: %s.", network_path firewall_file_other);
 
               firewall_delete_local_data(&local);
@@ -482,6 +485,14 @@ extern "C"{
 
           if (command == firewall_parameter_command_stop || command == firewall_parameter_command_restart) {
             if (reserved.has_stop) {
+              status = firewall_delete_chains(*data);
+
+              if (f_error_is_error(status)) {
+                firewall_delete_local_data(&local);
+                firewall_delete_data(data);
+                return status;
+              }
+
               local.is_global = f_true;
               local.is_main = f_false;
               local.is_stop = f_true;
@@ -498,7 +509,8 @@ extern "C"{
                 firewall_delete_data(data);
                 return status;
               }
-            } else {
+            }
+            else {
               fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Failed to perform stop request because the lock instructions are missing from: %s.", network_path firewall_file_other);
 
               firewall_delete_local_data(&local);
@@ -519,6 +531,16 @@ extern "C"{
             return status;
           };
 
+          if (command == firewall_parameter_command_start) {
+            status = firewall_delete_chains(*data);
+
+            if (f_error_is_error(status)) {
+              firewall_delete_local_data(&local);
+              firewall_delete_data(data);
+              return status;
+            }
+          }
+
           status = firewall_create_custom_chains(&reserved, &local, data);
 
           if (f_error_is_error(status)) {
@@ -559,7 +581,7 @@ extern "C"{
             {
               f_dynamic_string file_path = f_dynamic_string_initialize;
 
-              f_resize_dynamic_string(status, file_path, network_path_length + data->devices.array[i].used  + firewall_file_suffix_length + 1);
+              f_resize_dynamic_string(status, file_path, network_path_length + data->devices.array[i].used + firewall_file_suffix_length + 1);
 
               if (f_error_is_error(status)) {
                 fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory.");
@@ -568,10 +590,11 @@ extern "C"{
                 return status;
               }
 
-              strncat(file_path.string, network_path, network_path_length);
-              strncat(file_path.string + network_path_length, data->devices.array[i].string, data->devices.array[i].used);
-              strncat(file_path.string, firewall_file_suffix, firewall_file_suffix_length);
-              file_path.used = file_path.size;
+              memcpy((void *)file_path.string, network_path, sizeof(f_autochar) * network_path_length);
+              memcpy((void *)(file_path.string + network_path_length), data->devices.array[i].string, sizeof(f_autochar) * data->devices.array[i].used);
+              memcpy((void *)(file_path.string + network_path_length + data->devices.array[i].used), firewall_file_suffix, sizeof(f_autochar) * firewall_file_suffix_length);
+
+              file_path.used = network_path_length + data->devices.array[i].used + firewall_file_suffix_length;
               file_path.string[file_path.used] = 0;
 
               status = firewall_buffer_rules(file_path.string, f_true, &local, data);
index 034f43d5b518992b6bd1e9dc139b8c33eceeaa34..a37580da32ee62137cab672054f07f5da2ec9f8a 100644 (file)
@@ -190,14 +190,14 @@ extern "C"{
   #define firewall_protocol_length      8
   #define firewall_protocol_none_length 4
 
-  #define firewall_protocol_command       "-p"
+  #define firewall_protocol_command        "-p"
   #define firewall_protocol_command_length 2
 
-  #define firewall_chain_create_command  "-N"
-  #define firewall_chain_unchain_command "-X"
+  #define firewall_chain_create_command "-N"
+  #define firewall_chain_delete_command "-X"
 
-  #define firewall_chain_create_command_length  2
-  #define firewall_chain_unchain_command_length 2
+  #define firewall_chain_create_command_length 2
+  #define firewall_chain_delete_command_length 2
 
   enum {
     firewall_program_none,
index fbac576f1b1afff58abc2fc7abef70a2bce06010..fcae1eedd2915b19be1afaff34901136ee66c613 100644 (file)
@@ -1,7 +1,12 @@
+#include <level_0/errors.h>
 #include <level_3/firewall.h>
 
 int main(const f_s_int argc, const f_string argv[]) {
   firewall_data data = firewall_data_initialize;
 
-  return firewall_main(argc, argv, &data);
+  if (f_error_is_error(firewall_main(argc, argv, &data))) {
+    return 1;
+  }
+
+  return 0;
 }
index aba5dbe7f71f9bdb4fa0c8a86bad2cd6c898bfd2..d503837afb09dff9cad48d1b41bbc31efc535707 100644 (file)
@@ -10,8 +10,8 @@
     f_status status2 = f_none;
 
     f_string_length i = 0;
-    f_dynamic_string argument = f_dynamic_string_initialize;
     f_dynamic_strings arguments = f_dynamic_strings_initialize;
+    f_dynamic_string argument = f_dynamic_string_initialize;
 
     f_s_int results = 0;
     f_string_length length = 0;
@@ -41,7 +41,7 @@
       device_all = f_true;
     } else {
       if (data.devices.array[local.device].used > 0) {
-        f_resize_dynamic_string(status, device, data.devices.array[local.device].used);
+        f_new_dynamic_string(status, device, data.devices.array[local.device].used);
 
         if (f_error_is_error(status)) {
           f_delete_dynamic_string(status2, device);
           return status;
         }
 
-        strncat(device.string, data.devices.array[local.device].string, data.devices.array[local.device].used);
+        firewall_macro_concat_string(device.string, data.devices.array[local.device].string, data.devices.array[local.device].used);
+        device.used = data.devices.array[local.device].used;
       }
-
-      device.used = data.devices.array[local.device].used;
     }
 
     // for custom chains, the chain command may not be specified.
@@ -61,7 +60,7 @@
     }
 
     for (; i < local.rule_objects.used; i++) {
-      length  = (local.rule_objects.array[i].stop - local.rule_objects.array[i].start) + 1;
+      length  = firewall_macro_structure_size(local.rule_objects, i);
       invalid = f_false;
 
       is_ip_list        = f_false;
       if (length >= firewall_chain_length && fl_compare_strings(local.buffer.string + local.rule_objects.array[i].start, (f_string) firewall_chain, length, firewall_chain_length) == f_equal_to) {
         if (chain == firewall_chain_custom_id) {
           // custom chains can only apply to themselves, so silently ignore chain commands specified within a custom chain.
-          fprintf(f_standard_warning, "WARNING: At line %u, the chain option is meaningless inside of a custom chain.", (unsigned int) i);
+          fprintf(f_standard_warning, "WARNING: At line %i, the chain option is meaningle ss inside of a custom chain.", i);
           continue;
         }
 
-        length = (local.rule_contents.array[i].array[0].stop - local.rule_contents.array[i].array[0].start) + 1;
+        length = firewall_macro_structure_size(local.rule_contents.array[i], 0);
 
-        if (local.rule_contents.array[i].used <= 0 || local.rule_contents.array[i].used > 1) {
+        if (firewall_macro_rule_contents_has_incorrect_items(i, 1)) {
           invalid = f_true;
         }
         else if (length >= firewall_chain_input_length && fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_chain_input, length, firewall_chain_input_length) == f_equal_to) {
       }
       // process direction rule
       else if (length >= firewall_direction_length && fl_compare_strings(local.buffer.string + local.rule_objects.array[i].start, (f_string) firewall_direction, length, firewall_direction_length) == f_equal_to) {
-        length = (local.rule_contents.array[i].array[0].stop - local.rule_contents.array[i].array[0].start) + 1;
+        length = firewall_macro_structure_size(local.rule_contents.array[i], 0);
 
-        if (local.rule_contents.array[i].used <= 0 || local.rule_contents.array[i].used > 1) {
+        if (firewall_macro_rule_contents_has_incorrect_items(i, 1)) {
           invalid = f_true;
         }
         else if (length >= firewall_direction_input_length && fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_direction_input, length, firewall_direction_input_length) == f_equal_to) {
       }
       // process device rule.
       else if (length >= firewall_device_length && fl_compare_strings(local.buffer.string + local.rule_objects.array[i].start, (f_string) firewall_device, length, firewall_device_length) == f_equal_to) {
-        length = (local.rule_contents.array[i].array[0].stop - local.rule_contents.array[i].array[0].start) + 1;
+        length = firewall_macro_structure_size(local.rule_contents.array[i], 0);
 
-        if (local.rule_contents.array[i].used <= 0 || local.rule_contents.array[i].used > 1) {
+        if (firewall_macro_rule_contents_has_incorrect_items(i, 1)) {
           invalid = f_true;
         } else if (length >= firewall_device_all_length && fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_device_all, length, firewall_device_all_length) == f_equal_to) {
           f_delete_dynamic_string(status, device);
           device_all = f_true;
           continue;
         } else if (length >= firewall_device_this_length && fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_device_this, length, firewall_device_this_length) == f_equal_to) {
-          f_delete_dynamic_string(status, device);
-
           if (data.devices.array[local.device].used > 0) {
-            f_resize_dynamic_string(status, device, data.devices.array[local.device].used);
+            if (data.devices.array[local.device].used > device.size) {
+              f_resize_dynamic_string(status, device, data.devices.array[local.device].used);
 
-            if (f_error_is_error(status)) break;
+              if (f_error_is_error(status)) break;
+            }
+
+            firewall_macro_concat_string(device.string, data.devices.array[local.device].string, data.devices.array[local.device].used);
 
-            strncat(device.string, data.devices.array[local.device].string, data.devices.array[local.device].used);
+            device.used = data.devices.array[local.device].used;
+          }
+          else {
+            f_delete_dynamic_string(status, device);
           }
 
-          device.used = data.devices.array[local.device].used;
-          device_all  = f_false;
+          device_all = f_false;
           continue;
         }
 
         if (!invalid) {
-          f_delete_dynamic_string(status, device);
-
           if (length > 0) {
-            f_resize_dynamic_string(status, device, length);
+            if (length > device.size) {
+              f_resize_dynamic_string(status, device, length);
 
-            if (f_error_is_error(status)) break;
+              if (f_error_is_error(status)) break;
+            }
 
-            strncat(device.string, local.buffer.string + local.rule_contents.array[i].array[0].start, length);
+            firewall_macro_concat_string(device.string, local.buffer.string + local.rule_contents.array[i].array[0].start, length);
+            device.used = length;
+          }
+          else {
+            f_delete_dynamic_string(status, device);
           }
 
-          device.used = length;
-          device_all  = f_false;
+          device_all = f_false;
           continue;
         }
       }
       // process action rule.
       else if (length >= firewall_action_length && fl_compare_strings(local.buffer.string + local.rule_objects.array[i].start, (f_string) firewall_action, length, firewall_action_length) == f_equal_to) {
-        length = (local.rule_contents.array[i].array[0].stop - local.rule_contents.array[i].array[0].start) + 1;
+        length = firewall_macro_structure_size(local.rule_contents.array[i], 0);
 
-        if (local.rule_contents.array[i].used <= 0 || local.rule_contents.array[i].used > 1) {
+        if (firewall_macro_rule_contents_has_incorrect_items(i, 1)) {
           invalid = f_true;
         }
         else if (length >= firewall_action_append_length && fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_action_append, length, firewall_action_append_length) == f_equal_to) {
       }
       // process ip_list rule.
       else if (length >= firewall_ip_list_length && fl_compare_strings(local.buffer.string + local.rule_objects.array[i].start, (f_string) firewall_ip_list, length, firewall_ip_list_length) == f_equal_to) {
-        length = (local.rule_contents.array[i].array[0].stop - local.rule_contents.array[i].array[0].start) + 1;
+        length = firewall_macro_structure_size(local.rule_contents.array[i], 0);
         is_ip_list = f_true;
 
         if (length >= firewall_ip_list_source_length && fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_ip_list_source, length, firewall_ip_list_source_length) == f_equal_to) {
           ip_list_direction = f_false;
-        } else if (length >= firewall_ip_list_destination_length && fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_ip_list_destination, length, firewall_ip_list_destination_length) == f_equal_to) {
+        }
+        else if (length >= firewall_ip_list_destination_length && fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_ip_list_destination, length, firewall_ip_list_destination_length) == f_equal_to) {
           ip_list_direction = f_true;
-        } else {
+        }
+        else {
           invalid = f_true;
         }
-      } else if (length >= firewall_protocol_length && fl_compare_strings(local.buffer.string + local.rule_objects.array[i].start, (f_string) firewall_protocol, length, firewall_protocol_length) == f_equal_to) {
-        length = (local.rule_contents.array[i].array[0].stop - local.rule_contents.array[i].array[0].start) + 1;
+      }
+      else if (length >= firewall_protocol_length && fl_compare_strings(local.buffer.string + local.rule_objects.array[i].start, (f_string) firewall_protocol, length, firewall_protocol_length) == f_equal_to) {
+        length = firewall_macro_structure_size(local.rule_contents.array[i], 0);
 
-        if (local.rule_contents.array[i].used <= 0 || local.rule_contents.array[i].used > 1) {
+        if (firewall_macro_rule_contents_has_incorrect_items(i, 1)) {
           invalid = f_true;
-        } else {
-          f_delete_dynamic_string(status, protocol);
-
-          if (length > 0) {
-            f_resize_dynamic_string(status, protocol, length);
+        }
+        else {
+          if (fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_protocol_none, length, firewall_protocol_none_length) == f_equal_to) {
+            use_protocol = f_false;
+          }
+          else if (length > 0) {
+            f_delete_dynamic_string(status, protocol);
+            f_new_dynamic_string(status, protocol, length);
 
             if (f_error_is_error(status)) break;
-          }
 
-          if (fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_protocol_none, length, firewall_protocol_none_length) == f_equal_to) {
-            use_protocol = f_false;
-          } else {
-            if (length > 0) {
-              strncat(protocol.string, local.buffer.string + local.rule_contents.array[i].array[0].start, length);
-            }
+            firewall_macro_concat_string(protocol.string, local.buffer.string + local.rule_contents.array[i].array[0].start, length);
             protocol.used = length;
             use_protocol = f_true;
           }
+          else {
+            use_protocol = f_false;
+          }
 
           continue;
         }
       }
       // process tool rule.
       else if (length >= firewall_tool_length && fl_compare_strings(local.buffer.string + local.rule_objects.array[i].start, (f_string) firewall_tool, length, firewall_tool_length) == f_equal_to) {
-        length = (local.rule_contents.array[i].array[0].stop - local.rule_contents.array[i].array[0].start) + 1;
+        length = firewall_macro_structure_size(local.rule_contents.array[i], 0);
 
-        if (local.rule_contents.array[i].used <= 0 || local.rule_contents.array[i].used > 1) {
+        if (firewall_macro_rule_contents_has_incorrect_items(i, 1)) {
           invalid = f_true;
         } else {
           if (fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_tool_iptables, length, firewall_tool_iptables_length) == f_equal_to) {
       else if (length < firewall_rule_length || fl_compare_strings(local.buffer.string + local.rule_objects.array[i].start, (f_string) firewall_rule, length, firewall_rule_length) == f_not_equal_to) {
         if (length > 0) {
           fl_print_color_code(f_standard_warning, data.context.warning);
-          fprintf(f_standard_warning, "WARNING: At line %u, the object '", (unsigned int) i);
+          fprintf(f_standard_warning, "WARNING: At line %i, the object '", i);
           f_print_string(f_standard_warning, local.buffer.string + local.rule_objects.array[i].start, length);
           fprintf(f_standard_warning, "' is invalid");
           fl_print_color_code(f_standard_warning, data.context.reset);
         } else {
-          fprintf(f_standard_warning, "WARNING: At line %u, the object is missing", (unsigned int) i);
+          fprintf(f_standard_warning, "WARNING: At line %i, the object is missing", i);
         }
 
         fprintf(f_standard_warning, "\n");
       }
 
       if (invalid) {
-        length = (local.rule_objects.array[i].stop - local.rule_objects.array[i].start) + 1;
+        length = firewall_macro_structure_size(local.rule_objects, i);
 
         if (length > 0) {
           fl_print_color_code(f_standard_warning, data.context.warning);
-          fprintf(f_standard_warning, "WARNING: At line %u, the object '", (unsigned int) i);
+          fprintf(f_standard_warning, "WARNING: At line %i, the object '", i);
           f_print_string(f_standard_warning, local.buffer.string + local.rule_objects.array[i].start, length);
           fprintf(f_standard_warning, "' has invalid content '");
-          f_print_string(f_standard_warning, local.buffer.string + local.rule_contents.array[i].array[0].start, local.rule_contents.array[i].array[0].stop - local.rule_contents.array[i].array[0].start + 1);
+          f_print_string(f_standard_warning, local.buffer.string + local.rule_contents.array[i].array[0].start, firewall_macro_structure_size(local.rule_contents.array[i], 0));
           fprintf(f_standard_warning, "'");
           fl_print_color_code(f_standard_warning, data.context.reset);
           fprintf(f_standard_warning, "\n");
         } else {
-          fl_print_color_line(f_standard_warning, data.context.warning, data.context.reset, "WARNING: At line %u, the object has no content", (unsigned int) i);
+          fl_print_color_line(f_standard_warning, data.context.warning, data.context.reset, "WARNING: At line %i, the object has no content", i);
         }
 
         continue;
       for (r = repeat; r > 0; r--) {
         // first add the program name
         f_delete_dynamic_strings(status, arguments);
-        f_resize_dynamic_strings(status, arguments, arguments.used + firewall_default_allocation_step);
+        f_new_dynamic_strings(status, arguments, firewall_default_allocation_step);
 
         if (f_error_is_error(status)) break;
 
           }
         }
 
-        f_resize_dynamic_string(status, argument, current_tool_length);
+        f_delete_dynamic_string(status, argument);
 
         if (f_error_is_error(status)) break;
 
-        strncat(argument.string, current_tool, current_tool_length);
-        argument.used = current_tool_length;
-
-        arguments.array[arguments.used].string = argument.string;
-        arguments.array[arguments.used].size   = argument.size;
-        arguments.array[arguments.used].used   = argument.used;
-        arguments.used++;
-        argument.string = f_null;
-        argument.size   = 0;
-        argument.used   = 0;
-
-
-        // FIXME: (this issue is probably everywhere) Implement an strncat function for dynamic strings or if I already have one implement, make sure it is used in every applicable place
-        //        (this way I can automatically handle updating the used buffer)
-        //        also look into auto-allocated space if necessary with the said function
-
         // process the action when a non-none chain is specified.
         if (chain != firewall_chain_none_id && action != firewall_action_none_id) {
           if (action == firewall_action_append_id) {
-            f_resize_dynamic_string(status, argument, firewall_action_append_command_length);
+            f_new_dynamic_string(status, argument, firewall_action_append_command_length);
 
             if (f_error_is_error(status)) break;
 
-            strncat(argument.string, firewall_action_append_command, firewall_action_append_command_length);
+            firewall_macro_concat_string(argument.string, firewall_action_append_command, firewall_action_append_command_length);
             argument.used = firewall_action_append_command_length;
-          } else if (action == firewall_action_insert_id) {
-            f_resize_dynamic_string(status, argument, firewall_action_insert_command_length);
+          }
+          else if (action == firewall_action_insert_id) {
+            f_new_dynamic_string(status, argument, firewall_action_insert_command_length);
 
             if (f_error_is_error(status)) break;
 
-            strncat(argument.string, firewall_action_insert_command, firewall_action_insert_command_length);
+            firewall_macro_concat_string(argument.string, firewall_action_insert_command, firewall_action_insert_command_length);
             argument.used = firewall_action_insert_command_length;
-          } else if (action == firewall_action_policy_id) {
-            f_resize_dynamic_string(status, argument, firewall_action_policy_command_length);
+          }
+          else if (action == firewall_action_policy_id) {
+            f_new_dynamic_string(status, argument, firewall_action_policy_command_length);
 
             if (f_error_is_error(status)) break;
 
-            strncat(argument.string, firewall_action_policy_command, firewall_action_policy_command_length);
+            firewall_macro_concat_string(argument.string, firewall_action_policy_command, firewall_action_policy_command_length);
             argument.used = firewall_action_policy_command_length;
           }
 
           if (argument.used > 0) {
-            f_resize_dynamic_strings(status, arguments, arguments.used + firewall_default_allocation_step);
-
-            if (f_error_is_error(status)) break;
-
-            arguments.array[arguments.used].string = argument.string;
-            arguments.array[arguments.used].size   = argument.size;
-            arguments.array[arguments.used].used   = argument.used;
-            arguments.used++;
-            argument.string = f_null;
-            argument.size   = 0;
-            argument.used   = 0;
+            firewall_macro_append_argument_to_arguments(status, arguments, argument)
+            if (f_error_is_error(status)) {
+              f_delete_dynamic_string(status2, argument);
+              break;
+            }
 
             // process the chain, which is required by the action.
             if (chain == firewall_chain_custom_id) {
               if (data.chains.array[local.chain_ids.array[local.chain]].used > 0) {
-                f_resize_dynamic_string(status, argument, data.chains.array[local.chain_ids.array[local.chain]].used);
+                f_new_dynamic_string(status, argument, data.chains.array[local.chain_ids.array[local.chain]].used);
 
                 if (f_error_is_error(status)) break;
 
-                strncat(argument.string, data.chains.array[local.chain_ids.array[local.chain]].string, data.chains.array[local.chain_ids.array[local.chain]].used);
+                firewall_macro_concat_string(argument.string, data.chains.array[local.chain_ids.array[local.chain]].string, data.chains.array[local.chain_ids.array[local.chain]].used);
+                argument.used = data.chains.array[local.chain_ids.array[local.chain]].used;
               }
-              argument.used = data.chains.array[local.chain].used;
-            } else if (chain == firewall_chain_forward_id) {
-              f_resize_dynamic_string(status, argument, firewall_chain_forward_length);
+            }
+            else if (chain == firewall_chain_forward_id) {
+              f_new_dynamic_string(status, argument, firewall_chain_forward_length);
+
               if (f_error_is_error(status)) break;
 
-              strncat(argument.string, firewall_chain_forward, firewall_chain_forward_length);
+              firewall_macro_concat_string(argument.string, firewall_chain_forward, firewall_chain_forward_length);
               argument.used = firewall_chain_forward_length;
-            } else if (chain == firewall_chain_postrouting_id) {
-              f_resize_dynamic_string(status, argument, firewall_chain_postrouting_length);
+            }
+            else if (chain == firewall_chain_postrouting_id) {
+              f_new_dynamic_string(status, argument, firewall_chain_postrouting_length);
+
               if (f_error_is_error(status)) break;
 
-              strncat(argument.string, firewall_chain_postrouting, firewall_chain_postrouting_length);
+              firewall_macro_concat_string(argument.string, firewall_chain_postrouting, firewall_chain_postrouting_length);
               argument.used += firewall_chain_postrouting_length;
             } else if (chain == firewall_chain_prerouting_id) {
-              f_resize_dynamic_string(status, argument, firewall_chain_prerouting_length);
+              f_new_dynamic_string(status, argument, firewall_chain_prerouting_length);
+
               if (f_error_is_error(status)) break;
 
-              strncat(argument.string, firewall_chain_prerouting, firewall_chain_prerouting_length);
+              firewall_macro_concat_string(argument.string, firewall_chain_prerouting, firewall_chain_prerouting_length);
               argument.used = firewall_chain_prerouting_length;
             } else if (chain == firewall_chain_input_id) {
-              f_resize_dynamic_string(status, argument, firewall_chain_input_length);
+              f_new_dynamic_string(status, argument, firewall_chain_input_length);
+
               if (f_error_is_error(status)) break;
 
-              strncat(argument.string, firewall_chain_input, firewall_chain_input_length);
+              firewall_macro_concat_string(argument.string, firewall_chain_input, firewall_chain_input_length);
               argument.used = firewall_chain_input_length;
             } else if (chain == firewall_chain_output_id) {
-              f_resize_dynamic_string(status, argument, firewall_chain_output_length);
+              f_new_dynamic_string(status, argument, firewall_chain_output_length);
+
               if (f_error_is_error(status)) break;
 
-              strncat(argument.string, firewall_chain_output, firewall_chain_output_length);
+              firewall_macro_concat_string(argument.string, firewall_chain_output, firewall_chain_output_length);
               argument.used = firewall_chain_output_length;
             }
 
             if (argument.used > 0) {
-              f_resize_dynamic_strings(status, arguments, arguments.used + firewall_default_allocation_step);
-
-              if (f_error_is_error(status)) break;
-
-              arguments.array[arguments.used].string = argument.string;
-              arguments.array[arguments.used].size   = argument.size;
-              arguments.array[arguments.used].used   = argument.used;
-              arguments.used++;
-              argument.string = f_null;
-              argument.size   = 0;
-              argument.used   = 0;
+              firewall_macro_append_argument_to_arguments(status, arguments, argument)
+              if (f_error_is_error(status)) {
+                break;
+              }
             }
           }
         }
         if (device.used > 0 && (direction == firewall_direction_input_id || direction == firewall_direction_output_id)) {
           if (length < firewall_device_all_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_device_all, length, firewall_device_all_length) == f_not_equal_to) {
             if (direction == firewall_direction_input_id) {
-              f_resize_dynamic_string(status, argument, firewall_device_input_command_length);
+              f_new_dynamic_string(status, argument, firewall_device_input_command_length);
               if (f_error_is_error(status)) break;
 
-              strncat(argument.string, firewall_device_input_command, firewall_device_input_command_length);
+              firewall_macro_concat_string(argument.string, firewall_device_input_command, firewall_device_input_command_length);
               argument.used = firewall_device_input_command_length;
             }
             else if (direction == firewall_direction_output_id) {
-              f_resize_dynamic_string(status, argument, firewall_device_output_command_length);
+              f_new_dynamic_string(status, argument, firewall_device_output_command_length);
               if (f_error_is_error(status)) break;
 
-              strncat(argument.string, firewall_device_output_command, firewall_device_output_command_length);
+              firewall_macro_concat_string(argument.string, firewall_device_output_command, firewall_device_output_command_length);
               argument.used = firewall_device_output_command_length;
             }
 
             if (argument.used > 0) {
-              f_resize_dynamic_strings(status, arguments, arguments.used + firewall_default_allocation_step);
-
-              if (f_error_is_error(status)) break;
-
-              arguments.array[arguments.used].string = argument.string;
-              arguments.array[arguments.used].size   = argument.size;
-              arguments.array[arguments.used].used   = argument.used;
-              arguments.used++;
-              argument.string = f_null;
-              argument.size   = 0;
-              argument.used   = 0;
+              firewall_macro_append_argument_to_arguments(status, arguments, argument)
+              if (f_error_is_error(status)) {
+                break;
+              }
             }
           }
 
           // add the device.
           if (device.used > 0) {
-            f_resize_dynamic_string(status, argument, device.used);
-            if (f_error_is_error(status)) break;
-
-            strncat(argument.string, device.string, device.used);
-          }
-
-          argument.used = device.used;
-
-          if (argument.used > 0) {
-            f_resize_dynamic_strings(status, arguments, arguments.used + firewall_default_allocation_step);
+            f_new_dynamic_string(status, argument, device.used);
 
             if (f_error_is_error(status)) break;
 
-            arguments.array[arguments.used].string = argument.string;
-            arguments.array[arguments.used].size   = argument.size;
-            arguments.array[arguments.used].used   = argument.used;
-            arguments.used++;
-            argument.string = f_null;
-            argument.size   = 0;
-            argument.used   = 0;
+            firewall_macro_concat_string(argument.string, device.string, device.used);
+            argument.used = device.used;
+
+            firewall_macro_append_argument_to_arguments(status, arguments, argument)
+            if (f_error_is_error(status)) {
+              break;
+            }
           }
         }
 
         if (use_protocol) {
-          f_resize_dynamic_string(status, argument, firewall_protocol_command_length);
+          f_new_dynamic_string(status, argument, firewall_protocol_command_length);
+
           if (f_error_is_error(status)) break;
 
-          strncat(argument.string, firewall_protocol_command, firewall_protocol_command_length);
+          firewall_macro_concat_string(argument.string, firewall_protocol_command, firewall_protocol_command_length);
           argument.used = firewall_protocol_command_length;
 
-          if (argument.used > 0) {
-            f_resize_dynamic_strings(status, arguments, arguments.used + firewall_default_allocation_step);
-
-            if (f_error_is_error(status)) break;
-
-            arguments.array[arguments.used].string = argument.string;
-            arguments.array[arguments.used].size   = argument.size;
-            arguments.array[arguments.used].used   = argument.used;
-            arguments.used++;
-            argument.string = f_null;
-            argument.size   = 0;
-            argument.used   = 0;
+          firewall_macro_append_argument_to_arguments(status, arguments, argument)
+          if (f_error_is_error(status)) {
+            break;
           }
 
           if (protocol.used > 0) {
-            f_resize_dynamic_string(status, argument, protocol.used);
-            if (f_error_is_error(status)) break;
-
-            strncat(argument.string, protocol.string, protocol.used);
-          }
-
-          argument.used = protocol.used;
-
-          if (argument.used > 0) {
-            f_resize_dynamic_strings(status, arguments, arguments.used + firewall_default_allocation_step);
+            f_new_dynamic_string(status, argument, protocol.used);
 
             if (f_error_is_error(status)) break;
 
-            arguments.array[arguments.used].string = argument.string;
-            arguments.array[arguments.used].size   = argument.size;
-            arguments.array[arguments.used].used   = argument.used;
-            arguments.used++;
-            argument.string = f_null;
-            argument.size   = 0;
-            argument.used   = 0;
+            firewall_macro_concat_string(argument.string, protocol.string, protocol.used);
+            argument.used = protocol.used;
+
+            firewall_macro_append_argument_to_arguments(status, arguments, argument)
+            if (f_error_is_error(status)) {
+              break;
+            }
           }
         }
 
             // skip past the chain
             subcounter++;
 
-            length = (local.rule_contents.array[i].array[subcounter].stop - local.rule_contents.array[i].array[subcounter].start) + 1;
+            length = firewall_macro_structure_size(local.rule_contents.array[i], subcounter);
 
             if (length > 0) {
-              f_resize_dynamic_string(status, ip_list, (local.rule_contents.array[i].array[subcounter].stop - local.rule_contents.array[i].array[subcounter].start) + firewall_default_allocation_step);
+              f_new_dynamic_string(status, ip_list, length);
 
               if (f_error_is_error(status)) {
+                // prevent the loop below from being processed.
                 subcounter = local.rule_contents.array[i].used;
-              } else {
-                strncat(ip_list.string, local.buffer.string + local.rule_contents.array[i].array[subcounter].start, length);
+              }
+              else {
+                firewall_macro_concat_string(ip_list.string, local.buffer.string + local.rule_contents.array[i].array[subcounter].start, length);
                 ip_list.used = length;
 
                 subcounter++;
           }
 
           for (; subcounter < local.rule_contents.array[i].used; subcounter++) {
-            length = (local.rule_contents.array[i].array[subcounter].stop - local.rule_contents.array[i].array[subcounter].start) + 1;
+            length = firewall_macro_structure_size(local.rule_contents.array[i], subcounter);
 
             if (length > 0) {
-              f_resize_dynamic_string(status, argument, (local.rule_contents.array[i].array[subcounter].stop - local.rule_contents.array[i].array[subcounter].start) + firewall_default_allocation_step);
+              f_new_dynamic_string(status, argument, length);
 
               if (f_error_is_error(status)) break;
 
-              strncat(argument.string, local.buffer.string + local.rule_contents.array[i].array[subcounter].start, length);
-            }
-
-            argument.used = length;
-
-            if (length > 0) {
-              f_resize_dynamic_strings(status, arguments, arguments.used + firewall_default_allocation_step);
-
-              if (f_error_is_error(status)) break;
+              firewall_macro_concat_string(argument.string, local.buffer.string + local.rule_contents.array[i].array[subcounter].start, length);
+              argument.used = length;
 
-              arguments.array[arguments.used].string = argument.string;
-              arguments.array[arguments.used].size   = argument.size;
-              arguments.array[arguments.used].used   = argument.used;
-              arguments.used++;
-              argument.string = f_null;
-              argument.size   = 0;
-              argument.used   = 0;
+              firewall_macro_append_argument_to_arguments(status, arguments, argument)
+              if (f_error_is_error(status)) {
+                break;
+              }
             }
           } // for
-        } else {
-          length = (local.rule_objects.array[i].stop - local.rule_objects.array[i].start) + 1;
+        }
+        else {
+          length = firewall_macro_structure_size(local.rule_objects, i);
 
           fl_print_color_code(f_standard_warning, data.context.warning);
-          fprintf(f_standard_warning, "WARNING: At line %u, the object '", (unsigned int) i);
-          f_print_string(f_standard_warning, local.buffer.string + local.rule_objects.array[i].start, local.rule_objects.array[i].stop - local.rule_objects.array[i].start + 1);
+          fprintf(f_standard_warning, "WARNING: At line %i, the object '", i);
+          f_print_string(f_standard_warning, local.buffer.string + local.rule_objects.array[i].start, length);
           fprintf(f_standard_warning, "' has no content");
           fl_print_color_code(f_standard_warning, data.context.reset);
           fprintf(f_standard_warning, "\n");
             f_fss_objects  basic_objects  = f_fss_objects_initialize;
             f_fss_contents basic_contents = f_fss_objects_initialize;
 
-            f_resize_dynamic_string(status, file_path, network_path_length + ip_list.used + firewall_default_allocation_step);
+            f_new_dynamic_string(status, file_path, network_path_length + ip_list.used + firewall_default_allocation_step);
 
             if (status == f_none) {
-              strncat(file_path.string, network_path, network_path_length);
-              strncat(file_path.string + network_path_length, ip_list.string, ip_list.used);
+              firewall_macro_concat_string(file_path.string, network_path, network_path_length);
+              firewall_macro_concat_string(file_path.string + network_path_length, ip_list.string, ip_list.used);
               file_path.used = file_path.size;
               file_path.string[file_path.used] = 0;
 
                 fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: Invalid parameter when calling f_file_open()");
               } else if (status == f_file_not_found) {
                 // the file does not have to exist
-                fl_print_color_line(f_standard_warning, data.context.warning, data.context.reset, "WARNING: Cannot find the file '%s'", file_path.string);
+                fl_print_color_line(f_standard_warning, data.context.warning, data.context.reset, "WARNING: Cannot find the file '%.*s'", file_path.used, file_path.string);
                 status = f_none;
               } else if (status == f_file_open_error) {
-                fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: Unable to open the file '%s'", file_path.string);
+                fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: Unable to open the file '%.*s'", file_path.used, file_path.string);
               } else if (status == f_file_descriptor_error) {
-                fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: File descriptor error while trying to open the file '%s'", file_path.string);
+                fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: File descriptor error while trying to open the file '%.*s'", file_path.used, file_path.string);
               } else if (f_macro_test_for_allocation_errors(status)) {
                 fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "CRITICAL ERROR: unable to allocate memory");
               } else {
               }
 
               f_file_close(&file);
-            } else {
+            }
+            else {
               if (file_position.total_elements == 0) {
                 fseek(file.file, 0, SEEK_END);
                 file_position.total_elements = ftell(file.file);
 
                 if (status == f_invalid_parameter) {
                   fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_file_read()");
-                } else if (status == f_overflow) {
-                  fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: Integer overflow while trying to buffer the file '%s'", file_path.string);
-                } else if (status == f_file_not_open) {
-                  fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: The file '%s' is no longer open", file_path.string);
-                } else if (status == f_file_seek_error) {
-                  fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: A seek error occurred while accessing the file '%s'", file_path.string);
-                } else if (status == f_file_read_error) {
-                  fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: A read error occurred while accessing the file '%s'", file_path.string);
-                } else if (f_macro_test_for_allocation_errors(status)) {
+                }
+                else if (status == f_overflow) {
+                  fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: Integer overflow while trying to buffer the file '%.*s'", file_path.used, file_path.string);
+                }
+                else if (status == f_file_not_open) {
+                  fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: The file '%.*s' is no longer open", file_path.used, file_path.string);
+                }
+                else if (status == f_file_seek_error) {
+                  fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: A seek error occurred while accessing the file '%.*s'", file_path.used, file_path.string);
+                }
+                else if (status == f_file_read_error) {
+                  fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: A read error occurred while accessing the file '%.*s'", file_path.used, file_path.string);
+                }
+                else if (f_macro_test_for_allocation_errors(status)) {
                   fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "CRITICAL ERROR: unable to allocate memory");
-                } else {
+                }
+                else {
                   fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fl_file_read()", f_error_set_error(status));
                 }
 
                 status = f_error_set_error(status);
-              } else {
+              }
+              else {
                 {
                   f_string_location input = f_string_location_initialize;
 
                   status = f_error_set_fine(status);
 
                   if (status == f_invalid_parameter) {
-                    fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_fss_basic_read() for the file '%s'", file_path.string);
-                  } else if (status == f_no_data_on_eos || status == f_no_data || status == f_no_data_on_stop) {
+                    fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_fss_basic_read() for the file '%.*s'", file_path.used, file_path.string);
+                  }
+                  else if (status == f_no_data_on_eos || status == f_no_data || status == f_no_data_on_stop) {
                     // empty files are to be silently ignored
-                  } else if (f_macro_test_for_allocation_errors(status)) {
+                  }
+                  else if (f_macro_test_for_allocation_errors(status)) {
                     fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "CRITICAL ERROR: unable to allocate memory");
-                  } else {
-                    fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_fss_basic_read() for the file '%s'", f_error_set_error(status), file_path.string);
+                  }
+                  else {
+                    fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_fss_basic_read() for the file '%.*s'", f_error_set_error(status), file_path.used, file_path.string);
                   }
 
                   status = f_error_set_error(status);
-                } else {
+                }
+                else {
                   f_string_length  buffer_counter = 0;
                   f_string_length  ip_length      = 0;
-                  f_dynamic_string ip_argument    = f_dynamic_string_initialize;
                   f_dynamic_string ip_list_action = f_dynamic_string_initialize;
 
                   if (ip_list_direction) {
-                    f_resize_dynamic_string(status, ip_list_action, firewall_ip_list_destination_action_length + firewall_default_allocation_step);
-                    strncat(ip_list_action.string, firewall_ip_list_destination_action, firewall_ip_list_destination_action_length);
-                  } else {
-                    f_resize_dynamic_string(status, ip_list_action, firewall_ip_list_source_action_length + firewall_default_allocation_step);
-                    strncat(ip_list_action.string, firewall_ip_list_source_action, firewall_ip_list_source_action_length);
+                    f_resize_dynamic_string(status, ip_list_action, firewall_ip_list_destination_action_length);
+
+                    if (f_error_is_error(status)) break;
+
+                    firewall_macro_concat_string(ip_list_action.string, firewall_ip_list_destination_action, firewall_ip_list_destination_action_length);
+                    ip_list_action.used = firewall_ip_list_destination_action_length;
+                  }
+                  else {
+                    f_resize_dynamic_string(status, ip_list_action, firewall_ip_list_source_action_length);
+
+                    if (f_error_is_error(status)) break;
+
+                    firewall_macro_concat_string(ip_list_action.string, firewall_ip_list_source_action, firewall_ip_list_source_action_length);
+                    ip_list_action.used = firewall_ip_list_source_action_length;
                   }
 
-                  ip_list_action.used = ip_list_action.size;
-                  ip_list_action.string[ip_list_action.used] = 0;
+                  status = f_none;
+                  if (arguments.used + 2 > arguments.size) {
+                    f_resize_dynamic_strings(status, arguments, arguments.size + 2);
+                  }
 
                   if (f_error_is_error(status)) {
                     fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "CRITICAL ERROR: unable to allocate memory");
-                  } else {
-                    ip_list_action.used = ip_list_action.size;
 
-                    f_resize_dynamic_strings(status, arguments, arguments.used + 2);
+                    f_delete_dynamic_string(status2, ip_list_action);
+                  }
+                  else {
+                    f_dynamic_string ip_argument = f_dynamic_string_initialize;
 
+                    firewall_macro_append_argument_to_arguments(status, arguments, ip_list_action)
                     if (f_error_is_error(status)) {
-                      fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "CRITICAL ERROR: unable to allocate memory");
-                    } else {
-                      arguments.array[arguments.used].string = ip_list_action.string;
-                      arguments.array[arguments.used].size   = ip_list_action.size;
-                      arguments.array[arguments.used].used   = ip_list_action.used;
-                      arguments.used++;
-
-                      // the ip_list file contains objects and no content, all objects are what matter an nothing else
-                      for (; buffer_counter < basic_objects.used; buffer_counter++) {
-                        ip_length = (basic_objects.array[buffer_counter].stop - basic_objects.array[buffer_counter].start) + 1;
-
-                        f_resize_dynamic_string(status, ip_argument, (basic_objects.array[buffer_counter].stop - basic_objects.array[buffer_counter].start) + firewall_default_allocation_step);
-
-                        if (f_error_is_error(status)) {
-                          fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "CRITICAL ERROR: unable to allocate memory");
-                          break;
-                        }
+                      f_delete_dynamic_string(status2, ip_argument);
+                      break;
+                    }
 
-                        strncat(ip_argument.string, local_buffer.string + basic_objects.array[buffer_counter].start, ip_length);
-                        ip_argument.used = ip_argument.size;
-                        ip_argument.string[ip_argument.used] = 0;
-
-                        arguments.array[arguments.used].string = ip_argument.string;
-                        arguments.array[arguments.used].size   = ip_argument.size;
-                        arguments.array[arguments.used].used   = ip_argument.used;
-                        arguments.used++;
-
-                        // print command when debugging.
-                        #ifdef _en_firewall_debug_
-                          if (data.parameters[firewall_parameter_debug].result == f_console_result_found) {
-                            f_string_length i = 0;
-
-                            fprintf(f_standard_output, "DEBUG: ");
-                            for (; i < arguments.used; i++) {
-                              fprintf(f_standard_output, "%s ", arguments.array[i].string);
-                            }
-                            fprintf(f_standard_output, "\n");
-                          }
-                        #endif // _en_firewall_debug_
+                    // the ip_list file contains objects and no content, all objects are what matter an nothing else
+                    for (; buffer_counter < basic_objects.used; buffer_counter++) {
+                      ip_length = firewall_macro_structure_size(basic_objects, buffer_counter);
 
-                        status = fll_execute_program((f_string) current_tool, arguments, &results);
+                      f_new_dynamic_string(status, ip_argument, ip_length);
 
-                        if (status == f_failure) {
-                          fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: Failed to perform requested %s operation:", current_tool);
-                          fprintf(f_standard_error, "  ");
+                      if (f_error_is_error(status)) {
+                        fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "CRITICAL ERROR: unable to allocate memory");
+                        break;
+                      }
 
-                          f_string_length i = 0;
+                      firewall_macro_concat_string(ip_argument.string, local_buffer.string + basic_objects.array[buffer_counter].start, ip_length);
+                      ip_argument.used = ip_length;
 
-                          fl_print_color_code(f_standard_error, data.context.error);
+                      firewall_macro_append_argument_to_arguments(status, arguments, ip_argument)
+                      if (f_error_is_error(status)) break;
 
-                          for (; i < arguments.used; i++) {
-                            fprintf(f_standard_error, "%s ", arguments.array[i].string);
+                      // print command when debugging.
+                      #ifdef _en_firewall_debug_
+                        if (data.parameters[firewall_parameter_debug].result == f_console_result_found) {
+                          fl_print_color_code(f_standard_debug, data.context.warning);
+                          fprintf(f_standard_debug, "DEBUG: %s ", current_tool);
+
+                          for (f_string_length i = 0; i < arguments.used; i++) {
+                            fprintf(f_standard_debug, "%.*s ", arguments.array[i].used, arguments.array[i].string);
                           }
 
-                          fl_print_color_code(f_standard_error, data.context.reset);
-                          fprintf(f_standard_error, "\n");
+                          fl_print_color_code(f_standard_debug, data.context.reset);
+                          fprintf(f_standard_debug, "\n");
+                        }
+                      #endif // _en_firewall_debug_
 
-                          arguments.used--;
-                          arguments.array[arguments.used].string = 0;
-                          arguments.array[arguments.used].size   = 0;
-                          arguments.array[arguments.used].used   = 0;
+                      status = fll_execute_program((f_string) current_tool, arguments, &results);
 
-                          break;
-                        } else if (status == f_invalid_parameter) {
-                          fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_execute_path()");
+                      if (status == f_failure) {
+                        fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: Failed to perform requested %s operation:", current_tool);
+                        fprintf(f_standard_error, "  ");
 
-                          arguments.used--;
-                          arguments.array[arguments.used].string = 0;
-                          arguments.array[arguments.used].size   = 0;
-                          arguments.array[arguments.used].used   = 0;
+                        fl_print_color_code(f_standard_error, data.context.error);
 
-                          break;
+                        fprintf(f_standard_error, "%s ", current_tool);
+                        for (f_string_length i = 0; i < arguments.used; i++) {
+                          fprintf(f_standard_error, "%.*s ", arguments.array[i].used, arguments.array[i].string);
                         }
 
+                        fl_print_color_code(f_standard_error, data.context.reset);
+                        fprintf(f_standard_error, "\n");
+
+                        // remove ip_argument from arguments string.
+                        f_delete_dynamic_string(status2, arguments.array[arguments.used]);
                         arguments.used--;
-                        arguments.array[arguments.used].string = 0;
-                        arguments.array[arguments.used].size   = 0;
-                        arguments.array[arguments.used].used   = 0;
 
-                        f_delete_dynamic_string(status2, ip_argument);
+                        break;
                       }
+                      else if (status == f_invalid_parameter) {
+                        fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_execute_program()");
+
+                        // remove ip_argument from arguments string.
+                        f_delete_dynamic_string(status2, arguments.array[arguments.used]);
+                        arguments.used--;
+
+                        break;
+                      }
+
+                      // remove ip_argument from arguments string.
+                      f_delete_dynamic_string(status2, arguments.array[arguments.used]);
+                      arguments.used--;
                     }
-                  }
 
-                  f_delete_dynamic_string(status2, ip_argument);
-                  f_delete_dynamic_string(status2, ip_list_action);
+                    f_delete_dynamic_string(status2, ip_argument);
 
-                  arguments.used--;
-                  arguments.array[arguments.used].string = 0;
-                  arguments.array[arguments.used].size   = 0;
-                  arguments.array[arguments.used].used   = 0;
+                    // remove ip_list_action from arguments string.
+                    f_delete_dynamic_string(status2, arguments.array[arguments.used]);
+                    arguments.used--;
+                  }
                 }
               }
             }
             f_delete_fss_contents(status2, basic_contents);
 
             if (status == f_failure || status == f_invalid_parameter) break;
-          } else {
+          }
+          else {
             // print command when debugging.
             #ifdef _en_firewall_debug_
               if (data.parameters[firewall_parameter_debug].result == f_console_result_found) {
-                f_string_length i = 0;
+                fl_print_color_code(f_standard_debug, data.context.warning);
+                fprintf(f_standard_debug, "DEBUG: %s ", current_tool);
 
-                fprintf(f_standard_output, "DEBUG: ");
-                for (; i < arguments.used; i++) {
-                  fprintf(f_standard_output, "%s ", arguments.array[i].string);
+                for (f_string_length i = 0; i < arguments.used; i++) {
+                  fprintf(f_standard_debug, "%.*s ", arguments.array[i].used, arguments.array[i].string);
                 }
-                fprintf(f_standard_output, "\n");
+
+                fl_print_color_code(f_standard_debug, data.context.reset);
+                fprintf(f_standard_debug, "\n");
               }
             #endif // _en_firewall_debug_
 
             if (status == f_failure) {
               fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: Failed to perform requested %s operation:", current_tool);
               fprintf(f_standard_error, "  ");
-
-              f_string_length i = 0;
-
               fl_print_color_code(f_standard_error, data.context.error);
 
-              for (; i < arguments.used; i++) {
-                fprintf(f_standard_error, "%s ", arguments.array[i].string);
+              fprintf(f_standard_error, "%s ", current_tool);
+              for (f_string_length i = 0; i < arguments.used; i++) {
+                fprintf(f_standard_error, "%.*s ", arguments.array[i].used, arguments.array[i].string);
               }
 
               fl_print_color_code(f_standard_error, data.context.reset);
 
               break;
             } else if (status == f_invalid_parameter) {
-              fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_execute_path()");
+              fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_execute_program()");
               break;
             }
           }
 
     uint8_t tool = firewall_program_iptables;
     f_bool new_chain = f_false;
+    f_bool create_chain = f_false;
     f_s_int results = 0;
 
     f_array_length i = 0;
     f_string_location location = f_string_location_initialize;
     f_dynamic_strings arguments = f_dynamic_strings_initialize;
 
-    f_dynamic_string static_string = f_dynamic_string_initialize;
+    f_dynamic_string fixed_string = f_dynamic_string_initialize;
 
-    f_resize_array_lengths(status, local->chain_ids, local->chain_objects.used);
-
-    local->chain_ids.used = 0;
+    f_delete_array_lengths(status, local->chain_ids);
+    f_new_array_lengths(status, local->chain_ids, local->chain_objects.used);
 
     if (f_error_is_error(status)) {
       return status;
     }
 
-    f_resize_dynamic_strings(status, arguments, 3);
+    f_new_dynamic_strings(status, arguments, 2);
 
     if (f_error_is_error(status)) {
       return status;
     }
 
-    f_resize_dynamic_string(status, arguments.array[0], firewall_tool_ip6tables_length);
+    f_new_dynamic_string(status, arguments.array[0], firewall_chain_create_command_length);
 
     if (f_error_is_error(status)) {
       f_delete_dynamic_strings(status2, arguments);
       return status;
     }
 
-    f_resize_dynamic_string(status, arguments.array[1], firewall_chain_create_command_length);
+    firewall_macro_concat_string(arguments.array[0].string, firewall_chain_create_command, firewall_chain_create_command_length);
+
+    arguments.array[0].used = firewall_chain_create_command_length;
+
+    f_new_dynamic_string(status, arguments.array[1], firewall_default_allocation_step);
 
     if (f_error_is_error(status)) {
+      arguments.used = 1;
       f_delete_dynamic_strings(status2, arguments);
 
       return status;
     }
 
+    arguments.used = 2;
+
     reserved->has_lock = f_false;
     reserved->has_stop = f_false;
     reserved->has_main = f_false;
 
-    strncat(arguments.array[0].string, firewall_tool_iptables, firewall_tool_iptables_length);
-    strncat(arguments.array[1].string, firewall_chain_create_command, firewall_chain_create_command_length);
-    arguments.array[0].used = firewall_tool_iptables_length;
-    arguments.array[1].used = firewall_chain_create_command_length;
-    arguments.used = 3;
-
     while (i < local->chain_objects.used) {
       new_chain = f_true;
       j = 0;
       // skip globally reserved chain name: main
       location.start = 0;
       location.stop = firewall_group_main_length - 1;
-      static_string.string = firewall_group_main;
-      static_string.used = firewall_group_main_length;
-      if (fl_compare_partial_dynamic_strings(local->buffer, static_string, local->chain_objects.array[i], location) == f_equal_to) {
+      fixed_string.string = firewall_group_main;
+      fixed_string.used = firewall_group_main_length;
+      if (fl_compare_partial_dynamic_strings(local->buffer, fixed_string, local->chain_objects.array[i], location) == f_equal_to) {
         new_chain = f_false;
         reserved->has_main = f_true;
         reserved->main_at = i;
       // skip globally reserved chain name: stop
       location.start = 0;
       location.stop = firewall_group_stop_length - 1;
-      static_string.string = firewall_group_stop;
-      static_string.used = firewall_group_stop_length;
-      if (fl_compare_partial_dynamic_strings(local->buffer, static_string, local->chain_objects.array[i], location) == f_equal_to) {
+      fixed_string.string = firewall_group_stop;
+      fixed_string.used = firewall_group_stop_length;
+      if (fl_compare_partial_dynamic_strings(local->buffer, fixed_string, local->chain_objects.array[i], location) == f_equal_to) {
         new_chain = f_false;
         reserved->has_stop = f_true;
         reserved->stop_at = i;
       // skip globally reserved chain name: lock
       location.start = 0;
       location.stop = firewall_group_lock_length - 1;
-      static_string.string = firewall_group_lock;
-      static_string.used = firewall_group_lock_length;
-      if (fl_compare_partial_dynamic_strings(local->buffer, static_string, local->chain_objects.array[i], location) == f_equal_to) {
+      fixed_string.string = firewall_group_lock;
+      fixed_string.used = firewall_group_lock_length;
+      if (fl_compare_partial_dynamic_strings(local->buffer, fixed_string, local->chain_objects.array[i], location) == f_equal_to) {
         new_chain = f_false;
         reserved->has_lock = f_true;
         reserved->lock_at = i;
       }
 
-      // nullify the static string
-      static_string.string = f_null;
-      static_string.used = 0;
+      // skip globally reserved chain name: none
+      location.start = 0;
+      location.stop = firewall_group_lock_length - 1;
+      fixed_string.string = firewall_chain_none;
+      fixed_string.used = firewall_chain_none_length;
+      if (fl_compare_partial_dynamic_strings(local->buffer, fixed_string, local->chain_objects.array[i], location) == f_equal_to) {
+        new_chain = f_false;
+      }
+
+      f_clear_dynamic_string(fixed_string);
 
       if (new_chain) {
         while (j < data->chains.used) {
       }
 
       if (new_chain) {
-        length = local->chain_objects.array[i].stop - local->chain_objects.array[i].start + 1;
-
         if (data->chains.used >= data->chains.size) {
-          f_resize_dynamic_strings(status, data->chains, (local->chain_objects.array[i].stop - local->chain_objects.array[i].start) + firewall_default_allocation_step);
+          f_resize_dynamic_strings(status, data->chains, data->chains.used + firewall_default_allocation_step);
 
           if (f_error_is_error(status)) {
             f_delete_dynamic_strings(status2, arguments);
           }
         }
 
-        if (length >= arguments.array[2].size) {
-          f_resize_dynamic_string(status, arguments.array[2], length + firewall_default_allocation_step);
+        create_chain = f_true;
+        length = firewall_macro_structure_size(local->chain_objects, i);
+
+        arguments.array[1].used = 0;
+        if (length > arguments.array[1].size) {
+          f_resize_dynamic_string(status, arguments.array[1], length);
 
           if (f_error_is_error(status)) {
             f_delete_dynamic_strings(status2, arguments);
           }
         }
 
-        f_resize_dynamic_string(status, data->chains.array[data->chains.used], length);
+        f_new_dynamic_string(status, data->chains.array[data->chains.used], length);
 
         if (f_error_is_error(status)) {
           f_delete_dynamic_strings(status2, arguments);
 
         data->chains.array[data->chains.used].used = 0;
         local->chain_ids.array[i] = data->chains.used;
-        arguments.array[2].used = 0;
+        arguments.array[1].used = 0;
         j = local->chain_objects.array[i].start;
 
+        // copy the string character by character, ignoring placeholders.
         while (j <= local->chain_objects.array[i].stop) {
           if (local->buffer.string[j] == f_fss_delimit_placeholder) {
             j++;
 
           data->chains.array[data->chains.used].string[data->chains.array[data->chains.used].used] = local->buffer.string[j];
           data->chains.array[data->chains.used].used++;
-          arguments.array[2].string[arguments.array[2].used] = local->buffer.string[j];
-          arguments.array[2].used++;
+          arguments.array[1].string[arguments.array[1].used] = local->buffer.string[j];
+          arguments.array[1].used++;
           j++;
         } // while
 
-        f_resize_dynamic_string(status, data->chains.array[data->chains.used], data->chains.array[data->chains.used].used);
-
-        if (f_error_is_error(status)) {
-          f_delete_dynamic_strings(status2, arguments);
-
-          return status;
+        if (fl_compare_strings(arguments.array[1].string, firewall_chain_forward, arguments.array[1].used, firewall_chain_forward_length) == f_equal_to) {
+          create_chain = f_false;
+        }
+        else if (fl_compare_strings(arguments.array[1].string, firewall_chain_input, arguments.array[1].used, firewall_chain_input_length) == f_equal_to) {
+          create_chain = f_false;
+        }
+        else if (fl_compare_strings(arguments.array[1].string, firewall_chain_output, arguments.array[1].used, firewall_chain_output_length) == f_equal_to) {
+          create_chain = f_false;
+        }
+        else if (fl_compare_strings(arguments.array[1].string, firewall_chain_postrouting, arguments.array[1].used, firewall_chain_postrouting_length) == f_equal_to) {
+          create_chain = f_false;
+        }
+        else if (fl_compare_strings(arguments.array[1].string, firewall_chain_prerouting, arguments.array[1].used, firewall_chain_prerouting_length) == f_equal_to) {
+          create_chain = f_false;
         }
 
-        // print command when debugging.
-        #ifdef _en_firewall_debug_
-          if (data->parameters[firewall_parameter_debug].result == f_console_result_found) {
-            f_string_length i = 0;
-
-            fprintf(f_standard_output, "DEBUG: ");
-            for (; i < arguments.used; i++) {
-              fprintf(f_standard_output, "%s ", arguments.array[i].string);
-            }
-            fprintf(f_standard_output, "\n");
-          }
-        #endif // _en_firewall_debug_
-
-        tool = firewall_program_iptables;
-        status = fll_execute_program((f_string) firewall_tool_iptables, arguments, &results);
-
-        if (f_error_is_not_error(status)) {
-          memset(arguments.array[0].string, 0, sizeof(f_autochar) * firewall_tool_iptables_length);
-          strncat(arguments.array[0].string, firewall_tool_iptables, firewall_tool_ip6tables_length);
-          arguments.array[0].used = firewall_tool_ip6tables_length;
-          arguments.used = 3;
-
+        if (create_chain) {
           // print command when debugging.
           #ifdef _en_firewall_debug_
             if (data->parameters[firewall_parameter_debug].result == f_console_result_found) {
-              f_string_length i = 0;
+              fl_print_color_code(f_standard_debug, data->context.warning);
+              fprintf(f_standard_debug, "DEBUG: %s ", firewall_tool_iptables);
 
-              fprintf(f_standard_output, "DEBUG: ");
-              for (; i < arguments.used; i++) {
-                fprintf(f_standard_output, "%s ", arguments.array[i].string);
+              for (f_string_length i = 0; i < arguments.used; i++) {
+                fprintf(f_standard_debug, "%.*s ", arguments.array[i].used, arguments.array[i].string);
               }
-              fprintf(f_standard_output, "\n");
+
+              fl_print_color_code(f_standard_debug, data->context.reset);
+              fprintf(f_standard_debug, "\n");
             }
           #endif // _en_firewall_debug_
 
-          tool = firewall_program_ip6tables;
-          status = fll_execute_program((f_string) firewall_tool_ip6tables, arguments, &results);
-        }
+          tool = firewall_program_iptables;
+          status = fll_execute_program((f_string) firewall_tool_iptables, arguments, &results);
 
-        if (f_error_is_error(status)) {
-          status = f_error_set_fine(status);
+          if (f_error_is_not_error(status)) {
+            // print command when debugging.
+            #ifdef _en_firewall_debug_
+              if (data->parameters[firewall_parameter_debug].result == f_console_result_found) {
+                fl_print_color_code(f_standard_debug, data->context.warning);
+                fprintf(f_standard_debug, "DEBUG: %s ", firewall_tool_ip6tables);
 
-          if (status == f_failure) {
-            if (tool == firewall_program_iptables) {
-              fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Failed to perform requested %s operation:", firewall_tool_iptables);
-            } else if (tool == firewall_program_ip6tables) {
-              fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Failed to perform requested %s operation:", firewall_tool_ip6tables);
-            }
+                for (f_string_length i = 0; i < arguments.used; i++) {
+                  fprintf(f_standard_debug, "%.*s ", arguments.array[i].used, arguments.array[i].string);
+                }
 
-            fprintf(f_standard_error, "  ");
+                fl_print_color_code(f_standard_debug, data->context.reset);
+                fprintf(f_standard_debug, "\n");
+              }
+            #endif // _en_firewall_debug_
+
+            tool = firewall_program_ip6tables;
+            status = fll_execute_program((f_string) firewall_tool_ip6tables, arguments, &results);
+          }
+
+          if (f_error_is_error(status)) {
+            status = f_error_set_fine(status);
+
+            if (status == f_failure) {
+              if (tool == firewall_program_iptables) {
+                fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Failed to perform requested %s operation:", firewall_tool_iptables);
+              } else if (tool == firewall_program_ip6tables) {
+                fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Failed to perform requested %s operation:", firewall_tool_ip6tables);
+              }
+
+              fprintf(f_standard_error, "  ");
+              fl_print_color_code(f_standard_error, data->context.error);
 
-            f_string_length i = 0;
+              if (tool == firewall_program_iptables) {
+                fprintf(f_standard_error, "%s ", firewall_tool_iptables);
+              }
+              else if (tool == firewall_program_ip6tables) {
+                fprintf(f_standard_error, "%s ", firewall_tool_ip6tables);
+              }
 
-            fl_print_color_code(f_standard_error, data->context.error);
+              for (f_string_length i = 0; i < arguments.used; i++) {
+                fprintf(f_standard_error, "%.*s ", arguments.array[i].used, arguments.array[i].string);
+              }
 
-            for (; i < arguments.used; i++) {
-              fprintf(f_standard_error, "%s ", arguments.array[i].string);
+              fl_print_color_code(f_standard_error, data->context.reset);
+              fprintf(f_standard_error, "\n");
+            } else if (status == f_invalid_parameter) {
+              fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_execute_program()");
+            } else {
+              fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_execute_program()", f_error_set_error(status));
             }
 
-            fl_print_color_code(f_standard_error, data->context.reset);
-            fprintf(f_standard_error, "\n");
-          } else if (status == f_invalid_parameter) {
-            fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_execute_path()");
-          } else {
-            fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_execute_program()", f_error_set_error(status));
+            f_delete_dynamic_strings(status2, arguments);
+            return status;
           }
-
-          f_delete_dynamic_strings(status2, arguments);
-          return f_error_set_error(status);
         }
 
         data->chains.used++;
       i++;
     } // while
 
+    f_delete_dynamic_strings(status2, arguments);
+
     return status;
   }
 #endif // _di_firewall_create_custom_chains_
 
+#ifndef _di_firewall_delete_chains_
+  f_return_status firewall_delete_chains(const firewall_data data) {
+    const f_string tools[2] = { firewall_tool_iptables, firewall_tool_ip6tables };
+    f_status status = f_none;
+
+    for (f_string_length i = 0; i < 2; i++) {
+      f_dynamic_strings arguments = f_dynamic_strings_initialize;
+      f_dynamic_string argument[1] = f_dynamic_string_initialize;
+      f_s_int results = 0;
+
+      argument[0].string = (f_string) "-F";
+      argument[0].size = 2;
+      argument[0].used = 2;
+
+      arguments.array = argument;
+      arguments.size = 1;
+      arguments.used = 1;
+
+      // print command when debugging.
+      #ifdef _en_firewall_debug_
+        if (data.parameters[firewall_parameter_debug].result == f_console_result_found) {
+          fl_print_color_code(f_standard_debug, data.context.warning);
+          fprintf(f_standard_debug, "DEBUG: %s ", tools[i]);
+
+          for (f_string_length i = 0; i < arguments.used; i++) {
+            fprintf(f_standard_debug, "%.*s ", arguments.array[i].used, arguments.array[i].string);
+          }
+
+          fl_print_color_code(f_standard_debug, data.context.reset);
+          fprintf(f_standard_debug, "\n");
+        }
+      #endif // _en_firewall_debug_
+
+      status = fll_execute_program(tools[i], arguments, &results);
+
+      if (f_error_is_error(status)) {
+        status = f_error_set_fine(status);
+
+        if (status == f_failure) {
+          fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: Failed to perform requested %s operation:", tools[i]);
+
+          fprintf(f_standard_error, "  ");
+          fl_print_color_code(f_standard_error, data.context.error);
+
+          fprintf(f_standard_error, "%s ", tools[i]);
+          for (f_string_length i = 0; i < arguments.used; i++) {
+            fprintf(f_standard_error, "%.*s ", arguments.array[i].used, arguments.array[i].string);
+          }
+
+          fl_print_color_code(f_standard_error, data.context.reset);
+          fprintf(f_standard_error, "\n");
+        }
+        else if (status == f_invalid_parameter) {
+          fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_execute_program()");
+        }
+        else {
+          fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_execute_program()", f_error_set_error(status));
+        }
+
+        return status;
+      }
+    }
+
+    for (f_string_length i = 0; i < 2; i++) {
+      f_dynamic_strings arguments = f_dynamic_strings_initialize;
+      f_dynamic_string argument[1] = f_dynamic_string_initialize;
+      f_s_int results = 0;
+
+      argument[0].string = (f_string) firewall_chain_delete_command;
+      argument[0].size = firewall_chain_delete_command_length;
+      argument[0].used = firewall_chain_delete_command_length;
+
+      arguments.array = argument;
+      arguments.size = 1;
+      arguments.used = 1;
+
+      // print command when debugging.
+      #ifdef _en_firewall_debug_
+        if (data.parameters[firewall_parameter_debug].result == f_console_result_found) {
+          fl_print_color_code(f_standard_debug, data.context.warning);
+          fprintf(f_standard_debug, "DEBUG: %s ", tools[i]);
+
+          for (f_string_length i = 0; i < arguments.used; i++) {
+            fprintf(f_standard_debug, "%.*s ", arguments.array[i].used, arguments.array[i].string);
+          }
+
+          fl_print_color_code(f_standard_debug, data.context.reset);
+          fprintf(f_standard_debug, "\n");
+        }
+      #endif // _en_firewall_debug_
+
+      status = fll_execute_program(tools[i], arguments, &results);
+
+      if (f_error_is_error(status)) {
+        status = f_error_set_fine(status);
+
+        if (status == f_failure) {
+          fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: Failed to perform requested %s operation:", tools[i]);
+
+          fprintf(f_standard_error, "  ");
+          fl_print_color_code(f_standard_error, data.context.error);
+
+          fprintf(f_standard_error, "%s ", tools[i]);
+          for (f_string_length i = 0; i < arguments.used; i++) {
+            fprintf(f_standard_error, "%.*s ", arguments.array[i].used, arguments.array[i].string);
+          }
+
+          fl_print_color_code(f_standard_error, data.context.reset);
+          fprintf(f_standard_error, "\n");
+        }
+        else if (status == f_invalid_parameter) {
+          fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_execute_program()");
+        }
+        else {
+          fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_execute_program()", f_error_set_error(status));
+        }
+
+        return status;
+      }
+    }
+
+    return status;
+  }
+#endif // _di_firewall_delete_chains_
+
 #ifndef _di_firewall_process_rules_
   f_return_status firewall_buffer_rules(const f_string filename, const f_bool optional, firewall_local_data *local, firewall_data *data) {
     f_file file = f_file_initialize;
         }
       }
 
-      return f_error_set_error(status);
+      return status;
     }
 
     f_macro_file_reset_position(local->file_position, file)
         fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fl_file_read().", f_error_set_error(status));
       }
 
-      return f_error_set_error(status);
+      return status;
     } else {
       f_string_location input = f_string_location_initialize;
 
         fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_fss_basic_list_read() for the file '%s'.", f_error_set_error(status), filename);
       }
 
-      return f_error_set_error(status);
+      return status;
     }
 
     return status;
 
         f_delete_fss_objects(status2, local->rule_objects);
         f_delete_fss_contents(status2, local->rule_contents);
-        return f_error_set_error(status);
+        return status;
       }
     }
 
index 66b6883fc59af6ba31a8b7c627f2383e0b7cfcae..33fd1d6fa00b5313b757b040a68a651ee3792218 100644 (file)
@@ -74,6 +74,36 @@ extern "C"{
     f_delete_dynamic_string(status, buffer); \
     f_delete_fss_objects(status, objects); \
     f_delete_fss_contents(status, contents);
+
+  #define firewall_macro_concat_string(destination, source, length) \
+    memcpy((void *)(destination), source, sizeof(f_autochar) * length);
+
+  #define firewall_macro_rule_contents_has_incorrect_items(index, total_items) \
+    local.rule_contents.array[index].used <= 0 || local.rule_contents.array[index].used > total_items
+
+  // the buffer start to stop points are inclusive such that the size is ((stop - start) + 1).
+  #define firewall_macro_dynamic_string_size(structure, index) \
+    (structure.string[index].stop - structure.string[index].start) + 1
+
+  // the buffer start to stop points are inclusive such that the size is ((stop - start) + 1).
+  #define firewall_macro_structure_size(structure, index) \
+    (structure.array[index].stop - structure.array[index].start) + 1
+
+  // TODO: temporarily added, convert this to a function below.
+  // TODO: also report: fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "CRITICAL ERROR: unable to allocate memory");
+  #define firewall_macro_append_argument_to_arguments(status, arguments, argument) \
+    if (arguments.used >= arguments.size) { \
+      f_resize_dynamic_strings(status, arguments, arguments.used + firewall_default_allocation_step); \
+      \
+      if (f_error_is_error(status)) break; \
+    } \
+    \
+    arguments.array[arguments.used].string = argument.string; \
+    arguments.array[arguments.used].size   = argument.size; \
+    arguments.array[arguments.used].used   = argument.used; \
+    arguments.used++; \
+    \
+    f_clear_dynamic_string(argument);
 #endif // _di_firewall_macro_private_
 
 #ifndef _di_firewall_perform_commands_
@@ -84,6 +114,10 @@ extern "C"{
   f_return_status firewall_create_custom_chains(firewall_reserved_chains *reserved, firewall_local_data *local, firewall_data *data) __attribute__((visibility("internal")));
 #endif // _di_firewall_create_custom_chains_
 
+#ifndef _di_firewall_delete_chains_
+  f_return_status firewall_delete_chains(const firewall_data data) __attribute__((visibility("internal")));
+#endif // _di_firewall_delete_chains_
+
 #ifndef _di_firewall_buffer_rules_
   f_return_status firewall_buffer_rules(const f_string filename, const f_bool optional, firewall_local_data *local, firewall_data *data) __attribute__((visibility("internal")));
 #endif // _di_firewall_buffer_rules_
index f655c3bf1fff659cc93c64510ec805833c482cff..0ae4fa825b621120ddcd6f4dca8d6f273977ee7a 100644 (file)
@@ -2,8 +2,10 @@
 
 main:
   # initialize the firewall
-  direction none
   action none
+  direction none
+  protocol none
+  chain none
 
   rule -F
   rule -Z
@@ -13,133 +15,268 @@ main:
   rule -t mangle -F
   tool ip46tables
 
-  # setup initial operations
-  chain INPUT
+
+INPUT:
+  # main input chain, expect this to act as the final RETURN handler.
   direction input
-  action append
+  protocol none
 
-  # Enable ALL local connections (loopback)
+  # handle local (loopback) connections.
   device lo
-  chain OUTPUT
-  direction output
-  rule -j ACCEPT
-
-  chain INPUT
-  direction input
-  rule -j ACCEPT
+  rule -j input-loop
   device all
 
-
   # Drop all INVALID packets so they aren't even processed
-  chain OUTPUT
-  rule -m state --state INVALID -j DROP
+  rule -m conntrack --ctstate INVALID -j input-invalid
 
-  chain INPUT
-  rule -m state --state INVALID -j DROP
+  # Allow ALL connections that have already been established by this host
+  #rule -m state --state ESTABLISHED,RELATED -j ACCEPT
+  rule -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
 
+  # send to whitelist and blacklist, which should return here.
+  rule -j input-blacklist
+  rule -j input-whitelist
 
   # Drop multicasts and broadcasts, they should not exist for a router and in most cases should be avoided.
   # unicasts are the normal behavior and blocking them would be very unusual.
-  chain OUTPUT
-  rule -m pkttype --pkt-type broadcast -j output-casting
-  rule -m pkttype --pkt-type multicast -j output-casting
-  #rule -m pkttype --pkt-type unicast -j output-casting
-  chain INPUT
   rule -m pkttype --pkt-type broadcast -j input-casting
   rule -m pkttype --pkt-type multicast -j input-casting
   #rule -m pkttype --pkt-type unicast -j input-casting
 
+  # send all tcp packets to the tcp queue
+  protocol tcp
+  rule -m state --state NEW -j input-tcp
 
-  # Allow ALL input&output connections that have already been established by this host (using conntrack might be more efficient)
-  chain OUTPUT
-  rule -m state --state ESTABLISHED,RELATED -j ACCEPT
-  #rule -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
+  # send all udp packets to the udp queue
+  protocol udp
+  rule -m state --state NEW -j input-udp
+
+  # send all icmp packets to the icmp queue
+  protocol icmp
+  rule -m state --state NEW -j input-icmp
 
-  chain INPUT
-  rule -m state --state ESTABLISHED,RELATED -j ACCEPT
-  #rule -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
+  # send all icmpv6 packets to the icmpv6 queue
+  protocol icmpv6
+  rule -m state --state NEW -j input-icmpv6
 
+  # load custom device-specific rules
+  rule -j input-devices
 
-  # send all tcp packets to the tcp queue
-  chain OUTPUT
+  # remaining packets
+  rule -j DROP
+
+
+input-invalid:
+  direction input
+  protocol none
+
+  # silently drop invalid RST tcp packets instead of sending a RST back.
   protocol tcp
-  rule -m state --state NEW -j output-tcp
+  rule --tcp-flags RST RST -j DROP
 
-  chain INPUT
-  rule -m state --state NEW -j input-tcp
+  # invalid FIN,ACK (server is wanting a FIN response), silently DROP it, send RST back, or send a FIN back.
+  #rule --tcp-flags ALL ACK,FIN -j DROP
+  #rule --tcp-flags ALL ACK,FIN -j REJECT --reject-with tcp-reset
+  rule --tcp-flags ALL ACK,FIN -j ACCEPT
 
 
-  # send all udp packets to the udp queue
-  chain OUTPUT
-  protocol udp
-  rule -m state --state NEW -j output-udp
+  # remaining packets
+  protocol none
+  rule -j DROP
 
-  chain INPUT
-  rule -m state --state NEW -j input-udp
 
+input-invalid-stream:
+  direction input
+  protocol tcp
+
+  # remaining packets
+  rule -j REJECT --reject-with tcp-reset
 
-  # send all ipv4 icmp packets to the icmp queue
+
+input-loop:
+  direction input
+  protocol none
+
+  # allow cups via loopback.
+  protocol tcp
   tool iptables
-  chain OUTPUT
-  protocol icmp
-  rule -m state --state NEW -j output-icmp
+  rule --sport 631 -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT
+  rule --dport 631 -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT
 
-  chain INPUT
-  rule -m state --state NEW -j input-icmp
+  # allow local dns server
+  #protocol udp
+  #rule --dport 53 -s 127.0.0.0/8 -d 127.0.1.1 -j ACCEPT
 
-  # send all ipv6 icmp packets to the icmp queue (alternatively put this in its own chain, such as input-icmpv6 and output-icmpv6)
-  tool ip6tables
-  chain OUTPUT
-  protocol icmpv6
-  rule -m state --state NEW -j output-icmp
+  # this is the localhost address, valid localhost are allowed to return to the previous chain.
+  protocol none
+  rule -s 127.0.0.0/8 -d 127.0.0.0/8 -j RETURN
 
-  chain INPUT
-  rule -m state --state NEW -j input-icmp
+  # it may be necessay to add a return for individual ips because there are some cases that result in non-localhost addresses going through loopback.
+  #rule -s 192.168.0.1 -d 192.168.0.1 -j RETURN
+  tool ip46tables
+
+  # remaining packets
+  rule -j DROP
+
+
+input-blacklist:
+  direction input
+  protocol none
+
+
+input-whitelist:
+  direction input
+  protocol none
+
+
+input-devices:
+  direction input
+  protocol none
+
+  # add device-specific rules here.
 
 
 input-tcp:
   direction input
   protocol tcp
 
-  # Prevent an XMAS attack
-  rule --tcp-flags ALL ALL -j DROP
+  # Resist TCP sequence number spoof attacks.
+  rule --tcp-flags SYN,ACK SYN,ACK -m conntrack --ctstate NEW -j input-invalid
+
+  # TCP streams must always start with SYN, all others are invalid and may be an attack.
+  rule ! --syn -m conntrack --ctstate NEW -j input-invalid-stream
+
+  # Prevent an XMAS attacks
+  rule --tcp-flags ALL FIN,URG,PSH -j input-invalid
+  rule --tcp-flags ALL ALL -j input-invalid
+  rule --tcp-flags ALL SYN,RST,ACK,FIN,URG -j input-invalid
 
   # Prevent NULL attack
-  rule --tcp-flags ALL NONE -j DROP
+  rule --tcp-flags ALL NONE -j input-invalid
+
+  # Prevent Sync Reset Attacks
+  rule --tcp-flags SYN,RST SYN,RST -j input-invalid
+  rule --tcp-flags SYN,FIN SYN,FIN -j input-invalid
+
+  # Postgresql standard port
+  #rule --dport 5432 -j ACCEPT
+
+  # Mysql standard port
+  #rule --dport 5432 -j ACCEPT
+
+  # Oracle standard port
+  #rule --dport 1521 -j ACCEPT
+
+  # Web standard ports
+  #rule -m multiport --dports 80,443,8080,8181,8443,8099,9000 -j ACCEPT
+
+  # ldap standard ports
+  #rule -m multiport --dports 389,636,1636 -j ACCEPT
+
+  # mail standard ports
+  #rule -m multiport --dports 25,465,993 -j ACCEPT
+
+  # ssh standard port
+  #rule --dport 22 -j ACCEPT
+
+  # common chef ssh ports
+  #rule --dport 2200:2210 -j ACCEPT
+
+  # gpg standard port
+  #rule --dport 9050 -j ACCEPT
+
+  # ftp standard port
+  #rule --dport 21 -j ACCEPT
+
+  # dns standard port (via tcp)
+  #rule --dport 53 -j ACCEPT
+
+  # rdp standard port
+  #rule --dport 3389 -j ACCEPT
+
+  # spice standard ports
+  #rule -m multiport --dports 5900:5905 -j ACCEPT
+
+  # allow high ports
+  #rule -m multiport --dports 49152:65535 -j ACCEPT
+
+  # accept all loopback
+  tool iptables
+  rule -d 127.0.0.0/8 -j ACCEPT
+  tool ip6tables
+  rule -d ::1 -j ACCEPT
+  tool ip46tables
 
 
 input-udp:
   direction input
   protocol udp
 
-  # Allow dhcp client renewals (from server to client). If these are blocked, you will not be able to renew easily
+  # openvpn standard port
+  #rule --dport 1194 -j ACCEPT
+
+  # dns standard port
+  #rule --dport 53 -j ACCEPT
+
+  # mdns standard port
+  #rule --dport 5353 -j ACCEPT
+
+  # dhcp standard port
+  rule --sport 67:68 --dport 67:68 -j ACCEPT
+
+  # ntp standard port
+  #rule --dport 123 -j ACCEPT
+
+  # teeworlds game server and client
+  #rule --dport 8300:8310 -j ACCEPT
+
+  # allow high ports
+  #rule -m multiport --dports 49152:65535 -j ACCEPT
+
+  # accept all loopback
   tool iptables
-  rule -s 0.0.0.0 --sport 67 -d 255.255.255.255 --dport 68 -j ACCEPT
+  rule -d 127.0.0.0/8 -j ACCEPT
+  tool ip6tables
+  rule -d ::1 -j ACCEPT
   tool ip46tables
 
 
 input-icmp:
   direction input
   protocol icmp
+  tool iptables
 
+  # destination unreachable
+  rule --icmp-type 3 -j ACCEPT
 
-output-tcp:
-  direction output
-  protocol tcp
+  # redirect
+  rule --icmp-type 5 -j ACCEPT
 
+  # (outgoing) ping
+  rule --icmp-type 0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
 
-output-udp:
-  direction output
-  protocol udp
+  # time exceeded
+  rule --icmp-type 11 -j ACCEPT
 
+  # parameter problem
+  rule --icmp-type 12 -j ACCEPT
 
-output-icmp:
-  direction output
+  # all loopback ICMP traffic
+  tool iptables
+  rule -i lo -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT
+  tool ip46tables
+
+  # remaining packets
+  rule -j DROP
+
+
+input-icmpv6:
+  direction input
   protocol icmp
+  tool ip6tables
 
 
 input-casting:
-  # pre-process broadcasts and multicasts.
   direction input
   protocol none
   tool ip46tables
@@ -156,8 +293,285 @@ input-casting:
   rule -j DROP
 
 
+OUTPUT:
+  # main output chain, expect this to act as the final RETURN handler.
+  direction output
+  protocol none
+
+  # handle local (loopback) connections.
+  device lo
+  rule -j output-loop
+  device all
+
+  # Drop all INVALID packets so they aren't even processed
+  rule -m conntrack --ctstate INVALID -j output-invalid
+
+  # Allow ALL connections that have already been established by this host
+  #rule -m state --state ESTABLISHED,RELATED -j ACCEPT
+  rule -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
+
+  # send to whitelist and blacklist, which should return here.
+  rule -j input-blacklist
+  rule -j input-whitelist
+
+  # Drop multicasts and broadcasts, they should not exist for a router and in most cases should be avoided.
+  # unicasts are the normal behavior and blocking them would be very unusual.
+  rule -m pkttype --pkt-type broadcast -j output-casting
+  rule -m pkttype --pkt-type multicast -j output-casting
+  #rule -m pkttype --pkt-type unicast -j output-casting
+
+  # send all tcp packets to the tcp queue
+  protocol tcp
+  rule -m state --state NEW -j output-tcp
+
+  # send all udp packets to the udp queue
+  protocol udp
+  rule -m state --state NEW -j output-udp
+
+  # send all icmp packets to the icmp queue
+  protocol icmp
+  rule -m state --state NEW -j output-icmp
+
+  # send all icmpv6 packets to the icmpv6 queue
+  protocol icmpv6
+  rule -m state --state NEW -j output-icmpv6
+
+  # load custom device-specific rules
+  rule -j input-devices
+
+  # remaining packets
+  rule -j DROP
+
+
+output-invalid:
+  direction output
+  protocol none
+
+  # remaining packets
+  rule -j DROP
+
+
+output-invalid-stream:
+  direction input
+  protocol tcp
+
+  # remaining packets
+  rule -j REJECT --reject-with tcp-reset
+
+
+output-loop:
+  direction output
+  protocol none
+
+  # allow cups via loopback.
+  protocol tcp
+  tool iptables
+  rule --sport 631 -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT
+  rule --dport 631 -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT
+
+  # allow local dns server
+  #protocol udp
+  #rule --sport 53 -s 127.0.1.1 -d 127.0.0.0/8 -j ACCEPT
+
+  # this is the localhost address, valid localhost are allowed to return to the previous chain.
+  protocol none
+  rule -s 127.0.0.0/8 -d 127.0.0.0/8 -j RETURN
+
+  # it may be necessay to add a return for individual ips because there are some cases that result in non-localhost addresses going through loopback.
+  #rule -s 192.168.0.1 -d 192.168.0.1 -j RETURN
+  tool ip46tables
+
+  # remaining packets
+  rule -j DROP
+
+
+output-blacklist:
+  direction output
+  protocol none
+
+
+output-whitelist:
+  direction output
+  protocol none
+
+
+output-devices:
+  direction output
+  protocol none
+
+  # add device-specific rules here.
+
+
+output-tcp:
+  direction output
+  protocol tcp
+
+  # allow sending TCP RST even when there is no valid local connection
+  protocol tcp
+  rule --tcp-flags RST RST -j ACCEPT
+
+  # allow sending ACK,PSH,FIN even when there is no valid local connection.
+  # the connection may already be closed locally by the time this packet goes out and it could improperly be marked as invalid before it leaves the system.
+  # allowing this ensures that the client gets the final disconnect acknowledgment.
+  rule --tcp-flags ALL ACK,FIN -j ACCEPT
+  rule --tcp-flags ALL ACK,PSH,FIN -j ACCEPT
+
+  # Resist TCP sequence number spoof attacks.
+  rule --tcp-flags SYN,ACK SYN,ACK -m conntrack --ctstate NEW -j input-invalid
+
+  # TCP streams must always start with SYN, all others are invalid and may be an attack.
+  rule ! --syn -m conntrack --ctstate NEW -j output-invalid-stream
+
+  # Prevent an XMAS attacks
+  rule --tcp-flags ALL FIN,URG,PSH -j output-invalid
+  rule --tcp-flags ALL ALL -j output-invalid
+  rule --tcp-flags ALL SYN,RST,ACK,FIN,URG -j output-invalid
+
+  # Prevent NULL attack
+  rule --tcp-flags ALL NONE -j output-invalid
+
+  # Prevent Sync Reset Attacks
+  rule --tcp-flags SYN,RST SYN,RST -j output-invalid
+  rule --tcp-flags SYN,FIN SYN,FIN -j output-invalid
+
+  # Postgresql standard port
+  #rule --sport 5432 -j ACCEPT
+
+  # Mysql standard port
+  #rule --sport 5432 -j ACCEPT
+
+  # Oracle standard port
+  #rule --sport 1521 -j ACCEPT
+
+  # Web standard ports
+  rule -m multiport --dports 80,443,8080,8181,8443,8099,9000 -j ACCEPT
+  #rule -m multiport --sports 80,443,8080,8181,8443,8099,9000 -j ACCEPT
+
+  # ldap standard ports
+  rule -m multiport --dports 389,636,1636 -j ACCEPT
+  #rule -m multiport --sports 389,636,1636 -j ACCEPT
+
+  # mail standard ports
+  rule -m multiport --dports 25,465,993 -j ACCEPT
+  #rule -m multiport --sports 25,465,993 -j ACCEPT
+
+  # ssh standard port
+  rule --dport 22 -j ACCEPT
+  #rule --sport 22 -j ACCEPT
+
+  # common chef ssh ports
+  #rule --dport 2200:2210 -j ACCEPT
+  #rule --sport 2200:2210 -j ACCEPT
+
+  # gpg standard port
+  rule --dport 9050 -j ACCEPT
+  #rule --sport 9050 -j ACCEPT
+
+  # pgp keyserver port
+  rule --dport 11371 -j ACCEPT
+
+  # ftp standard port
+  rule --dport 21 -j ACCEPT
+  #rule --sport 21 -j ACCEPT
+
+  # dns standard port (via tcp)
+  rule --dport 53 -j ACCEPT
+  #rule --sport 53 -j ACCEPT
+
+  # rdp standard port
+  rule --dport 3389 -j ACCEPT
+  #rule --sport 3389 -j ACCEPT
+
+  # spice standard ports
+  rule -m multiport --dports 5900:5905 -j ACCEPT
+  #rule -m multiport --sports 5900:5905 -j ACCEPT
+
+  # allow high ports
+  rule -m multiport --sports 49152:65535 -j ACCEPT
+  #rule -m multiport --dports 49152:65535 -j ACCEPT
+
+  # accept all loopback
+  tool iptables
+  rule -s 127.0.0.0/8 -j ACCEPT
+  tool ip6tables
+  rule -d ::1 -j ACCEPT
+  tool ip46tables
+
+
+output-udp:
+  direction output
+  protocol udp
+
+  # openvpn standard port
+  rule --dport 1194 -j ACCEPT
+  #rule --sport 1194 -j ACCEPT
+
+  # dns standard port
+  rule --dport 53 -j ACCEPT
+  #rule --sport 53 -j ACCEPT
+
+  # mdns standard port
+  #rule --dport 5353 -j ACCEPT
+  #rule --sport 5353 -j ACCEPT
+
+  # allow high ports
+  rule -m multiport --sports 49152:65535 -j ACCEPT
+  #rule -m multiport --dports 49152:65535 -j ACCEPT
+
+  # dhcp standard port
+  rule --sport 67:68 --dport 67:68 -j ACCEPT
+
+  # ntp standard port
+  rule --dport 123 -j ACCEPT
+  #rule --sport 123 -j ACCEPT
+
+  # teeworlds game server and client
+  #rule --dport 8300:8310 -j ACCEPT
+
+  # accept all loopback
+  tool iptables
+  rule -s 127.0.0.0/8 -j ACCEPT
+  tool ip6tables
+  rule -d ::1 -j ACCEPT
+  tool ip46tables
+
+
+output-icmp:
+  direction output
+  protocol icmp
+  tool iptables
+
+  # destination unreachable
+  rule --icmp-type 3 -j ACCEPT
+
+  # redirect
+  rule --icmp-type 5 -j ACCEPT
+
+  # (outgoing) ping
+  rule --icmp-type 8 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT
+
+  # time exceeded
+  rule --icmp-type 11 -j ACCEPT
+
+  # parameter problem
+  rule --icmp-type 12 -j ACCEPT
+
+  # all loopback ICMP traffic
+  tool iptables
+  rule -o lo -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT
+  tool ip46tables
+
+  # remaining packets
+  rule -j DROP
+
+
+output-icmpv6:
+  direction output
+  protocol icmp
+  tool ip6tables
+
+
 output-casting:
-  # pre-process broadcasts and multicasts.
   direction output
   protocol none
   tool ip46tables
@@ -172,3 +586,14 @@ output-casting:
 
   # drop all remaining broadcasts and multicasts
   rule -j DROP
+
+
+FORWARD:
+
+  # load custom device-specific rules
+  rule -j forward-devices
+
+
+forward-devices:
+
+  # add device-specific rules here.
index 8f0f63411e75e8b0dd0fbb5cdd35e16075f73292..1f8375b90d78e0e90470297f6f74b82e7feb7fc0 100644 (file)
@@ -1,299 +1,2 @@
 # fss-0002
 
-main:
-  chain INPUT
-  device all
-  direction none
-
-  # Log everything else (input)
-  # everything that reaches this point without being accepted, reject, or otherwise handled will be logged
-  rule -m state --state NEW -j LOG --log-prefix "FIREWALL:INPUT "
-
-  chain OUTPUT
-
-  ## Log everything else (output)
-  #rule -j LOG --log-prefix "FIREWALL:OUTPUT "
-
-  # the catch-all policies
-  action policy
-  chain INPUT
-  rule DROP
-
-  chain OUTPUT
-  rule DROP
-
-  chain FORWARD
-  rule DROP
-
-
-input-tcp:
-  direction output
-  protocol tcp
-
-  ## allow Well-known port output: 0-1023
-  #rule --dport 0:1023 -m state --state NEW -j ACCEPT
-
-  ## allow registered ports: 1024-49151
-  #rule --dport 1024:49151 -m state --state NEW -j ACCEPT
-
-  ## allow all other ports: 49152-61000
-  #rule --dport 49152:61000 -m state --state NEW -j ACCEPT
-
-  ## allow all other ports: 61001-65535
-  #rule --dport 61001:65535 -m state --state NEW -j ACCEPT
-
-
-output-tcp:
-  direction output
-  protocol tcp
-
-  # allow Well-known port output: 0-1023
-  rule --dport 0:1023 -m state --state NEW -j ACCEPT
-
-  # allow registered ports: 1024-49151
-  rule --dport 1024:49151 -m state --state NEW -j ACCEPT
-
-  # allow all other ports: 49152-61000
-  rule --dport 49152:61000 -m state --state NEW -j ACCEPT
-
-  # allow all other ports: 61001-65535
-  rule --dport 61001:65535 -m state --state NEW -j ACCEPT
-
-
-input-udp:
-  direction input
-  protocol udp
-
-  ## allow Well-known port output: 0-1023
-  #rule --dport 0:1023 -m state --state NEW -j ACCEPT
-
-  ## allow registered ports: 1024-49151
-  #rule --dport 1024:49151 -m state --state NEW -j ACCEPT
-
-  ## allow all other ports: 49152-61000
-  #rule --dport 49152:61000 -m state --state NEW -j ACCEPT
-
-  ## allow all other ports: 61001-65535
-  #rule --dport 61001:65535 -m state --state NEW -j ACCEPT
-
-
-output-udp:
-  direction output
-  protocol udp
-
-  # allow Well-known port output: 0-1023
-  rule --dport 0:1023 -m state --state NEW -j ACCEPT
-
-  # allow registered ports: 1024-49151
-  rule --dport 1024:49151 -m state --state NEW -j ACCEPT
-
-  # allow all other ports: 49152-61000
-  rule --dport 49152:61000 -m state --state NEW -j ACCEPT
-
-  # allow all other ports: 61001-65535
-  rule --dport 61001:65535 -m state --state NEW -j ACCEPT
-
-
-input-icmp:
-  direction input
-
-
-  # ipv4 icmp
-  tool iptables
-  protocol icmp
-
-  # allow all icmp input, such as pings
-  #rule -m state --state NEW -j ACCEPT
-
-  # allow icmp: echo reply (outbound ping)
-  #rule --icmp-type 0 -m state --state NEW -j ACCEPT
-
-  # allow icmp: destination unreachable
-  rule --icmp-type 3 -m state --state NEW -j ACCEPT
-
-  # deny icmp: source quench (deprecated and should be blocked.)
-  rule --icmp-type 4 -m state --state NEW -j DROP
-
-  # allow icmp: redirect
-  rule --icmp-type 5 -m state --state NEW -j ACCEPT
-
-  # deny icmp: Alternate Host Address (deprecated and should be blocked.)
-  rule --icmp-type 6 -m state --state NEW -j DROP
-
-  # deny icmp: unknown
-  rule --icmp-type 7 -m state --state NEW -j DROP
-
-  # allow icmp: echo request (inbound ping)
-  rule --icmp-type 8 -m state --state NEW -j ACCEPT
-
-  # allow icmp: router advertisement
-  rule --icmp-type 9 -m state --state NEW -j ACCEPT
-
-  # allow icmp: router Solicitation
-  rule --icmp-type 10 -m state --state NEW -j ACCEPT
-
-  # allow icmp: time exceeded
-  rule --icmp-type 11 -m state --state NEW -j ACCEPT
-
-  # allow icmp: bad ip header
-  rule --icmp-type 12 -m state --state NEW -j ACCEPT
-
-  # allow icmp: timestamp
-  rule --icmp-type 13 -m state --state NEW -j ACCEPT
-
-  # allow icmp: timestamp reply
-  rule --icmp-type 14 -m state --state NEW -j ACCEPT
-
-  # deny icmp: information request (deprecated and should be blocked.)
-  rule --icmp-type 15 -m state --state NEW -j DROP
-
-  # deny icmp: information reply (deprecated and should be blocked.)
-  rule --icmp-type 16 -m state --state NEW -j DROP
-
-  # deny icmp: address request (deprecated and should be blocked.)
-  rule --icmp-type 17 -m state --state NEW -j DROP
-
-  # deny icmp: address reply (deprecated and should be blocked.)
-  rule --icmp-type 18 -m state --state NEW -j DROP
-
-  # deny icmp: unknown (19 throught 29)
-  #rule --icmp-type 19 -m state --state NEW -j DROP
-
-  # allow icmp: traceroute
-  #rule --icmp-type 30 -m state --state NEW -j ACCEPT
-
-  # deny icmp: unknown (31 throught 39) (deprecated and should be blocked.)
-  rule --icmp-type 31 -m state --state NEW -j DROP
-
-
-  # ipv6 icmp
-  tool ip6tables
-  protocol icmpv6
-
-  # allow all icmp input
-  #rule -m state --state NEW -j ACCEPT
-
-  # destination uncreachable
-  rule --icmpv6-type 1 -m state --state NEW -j ACCEPT
-
-  # packet too big
-  rule --icmpv6-type 2 -m state --state NEW -j ACCEPT
-
-  # time exceeded
-  rule --icmpv6-type 3 -m state --state NEW -j ACCEPT
-
-  # parameter problem
-  rule --icmpv6-type 4 -m state --state NEW -j ACCEPT
-
-  # Private experimentation
-  #rule --icmpv6-type 100 -m state --state NEW -j ACCEPT
-  #rule --icmpv6-type 101 -m state --state NEW -j ACCEPT
-
-  # echo request
-  rule --icmpv6-type 128 -m state --state NEW -j ACCEPT
-
-  # echo reply
-  #rule --icmpv6-type 129 -m state --state NEW -j ACCEPT
-
-  # multiclass listener
-  rule --icmpv6-type 130 -m state --state NEW -j ACCEPT
-
-  # multiclass listener report
-  rule --icmpv6-type 131 -m state --state NEW -j ACCEPT
-
-  # multiclass listener done
-  rule --icmpv6-type 132 -m state --state NEW -j ACCEPT
-
-  # router solicitation
-  rule --icmpv6-type 133 -m state --state NEW -j ACCEPT
-
-  # router advertisement
-  rule --icmpv6-type 134 -m state --state NEW -j ACCEPT
-
-  # neighbor solicitation
-  rule --icmpv6-type 135 -m state --state NEW -j ACCEPT
-
-  # neighbor advertisement
-  rule --icmpv6-type 136 -m state --state NEW -j ACCEPT
-
-  # redirect messages
-  rule --icmpv6-type 137 -m state --state NEW -j ACCEPT
-
-  # router renumbering
-  rule --icmpv6-type 138 -m state --state NEW -j ACCEPT
-
-  # icmp node information query
-  rule --icmpv6-type 139 -m state --state NEW -j ACCEPT
-
-  # icmp node information response
-  rule --icmpv6-type 140 -m state --state NEW -j ACCEPT
-
-  # inverse neighbor discoverey solicitation message
-  rule --icmpv6-type 141 -m state --state NEW -j ACCEPT
-
-  # inverse neighbor discoverey advertisement message
-  rule --icmpv6-type 142 -m state --state NEW -j ACCEPT
-
-  # multicast listener discovery reports
-  rule --icmpv6-type 143 -m state --state NEW -j ACCEPT
-
-  # home agent address discovery request message
-  rule --icmpv6-type 144 -m state --state NEW -j ACCEPT
-
-  # home agent address discovery reply message
-  rule --icmpv6-type 145 -m state --state NEW -j ACCEPT
-
-  # mobile prefix solicitation
-  rule --icmpv6-type 146 -m state --state NEW -j ACCEPT
-
-  # mobile prefix advertisement
-  rule --icmpv6-type 147 -m state --state NEW -j ACCEPT
-
-  # certification path solicitation
-  rule --icmpv6-type 148 -m state --state NEW -j ACCEPT
-
-  # certification path advertisement
-  rule --icmpv6-type 149 -m state --state NEW -j ACCEPT
-
-  # used by experimental protocol
-  #rule --icmpv6-type 150 -m state --state NEW -j ACCEPT
-
-  # multicast router solicitation
-  rule --icmpv6-type 151 -m state --state NEW -j ACCEPT
-
-  # multicast router advertisement
-  rule --icmpv6-type 152 -m state --state NEW -j ACCEPT
-
-  # multicast router termination
-  rule --icmpv6-type 153 -m state --state NEW -j ACCEPT
-
-  # fmipv6 control messages
-  rule --icmpv6-type 154 -m state --state NEW -j ACCEPT
-
-  # rpl control messages
-  rule --icmpv6-type 155 -m state --state NEW -j ACCEPT
-
-  # private experimentation
-  #rule --icmpv6-type 200 -m state --state NEW -j ACCEPT
-  #rule --icmpv6-type 201 -m state --state NEW -j ACCEPT
-
-
-output-icmp:
-  direction output
-  protocol icmp
-
-
-  # ipv4 icmp
-  tool iptables
-  protocol icmp
-
-  # allow icmp output, such as pings
-  rule -m state --state NEW -j ACCEPT
-
-
-  # ipv6 icmp
-  tool ip6tables
-  protocol icmpv6
-
-  # allow icmp output, such as pings
-  rule -m state --state NEW -j ACCEPT