]> 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:32:46 +0000 (16:32 -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 cab0d10d2246213c34ee19f485f2b7a7103c2395..cdd98670bcef47c341b29254347a9e533be3e2ea 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 c4b152dd22133705cd3d882604030b779cb2bf49..b13d51202b2d44896bc7347df8934f864975d53e 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 9eb04254ee0b0307951c99c2a7c157ede6baf4f0..d49f11e4d54ca5428bfbdbe18237968520dbe8fa 100644 (file)
@@ -1,7 +1,12 @@
+#include <level_0/errors.h>
 #include <level_3/firewall.h>
 
 int main(f_const f_s_int argc, f_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 d8ec33154cd78e9d2af058095a6d3a13eabd4a31..18bb743fb81895397a7a172e6b1848f9f60c32b3 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 = 0;
-        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 = 0;
-            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 = 0;
-              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 = 0;
-              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 = 0;
-            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 = 0;
-            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 = 0;
-            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 = 0;
-              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);
+
+                      f_new_dynamic_string(status, ip_argument, ip_length);
 
-                        status = fll_execute_program((f_string) current_tool, arguments, &results);
+                      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;
+                      }
 
-                        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, "  ");
+                      firewall_macro_concat_string(ip_argument.string, local_buffer.string + basic_objects.array[buffer_counter].start, ip_length);
+                      ip_argument.used = ip_length;
 
-                          f_string_length i = 0;
+                      firewall_macro_append_argument_to_arguments(status, arguments, ip_argument)
+                      if (f_error_is_error(status)) break;
 
-                          fl_print_color_code(f_standard_error, data.context.error);
+                      // 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 (; i < arguments.used; i++) {
-                            fprintf(f_standard_error, "%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);
                           }
 
-                          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 = 0;
-      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_buffer_rules_
+#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(f_const f_string filename, f_const f_bool optional, firewall_local_data *local, firewall_data *data) {
     f_file file = f_file_initialize;
     f_status status = f_none;
         }
       }
 
-      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 6730a42772a56182917677d7aa1d55946803f383..5ca0411e8eecab90853c6c3041eb9fc395b8f204 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) f_gcc_attribute_visibility_internal;
 #endif // _di_firewall_create_custom_chains_
 
+#ifndef _di_firewall_delete_chains_
+  f_return_status firewall_delete_chains(const firewall_data data) f_gcc_attribute_visibility_internal;
+#endif // _di_firewall_delete_chains_
+
 #ifndef _di_firewall_buffer_rules_
   f_return_status firewall_buffer_rules(f_const f_string filename, f_const f_bool optional, firewall_local_data *local, firewall_data *data) f_gcc_attribute_visibility_internal;
 #endif // _di_firewall_buffer_rules_
index 821938704944dabc0a0ec4231fce5c244aecd055..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,170 +15,268 @@ main:
   rule -t mangle -F
   tool ip46tables
 
-  # setup initial operations
-  chain INPUT
-  direction input
-  action append
 
+INPUT:
+  # main input chain, expect this to act as the final RETURN handler.
+  direction input
+  protocol none
 
-  # Process all loopback connections and filter out (and log) invalid connections.
-  # Valid connections will return and follow all remaining rules below.
+  # handle local (loopback) connections.
   device lo
-  chain OUTPUT
-  direction output
-  rule -j output-loopback
-
-  chain INPUT
-  direction input
-  rule -j input-loopback
+  rule -j input-loop
   device all
 
-
-  # Handle all packets parked INVALID in separate chains.
-  chain OUTPUT
-  #rule -m state --state INVALID -j output-invalid
-  rule -m conntrack --ctstate INVALID -j output-invalid
-
-  chain INPUT
-  #rule -m state --state INVALID -j input-invalid
+  # Drop all INVALID packets so they aren't even processed
   rule -m conntrack --ctstate INVALID -j input-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.
-  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
 
-
-  # handle tcp-security before accepting established or related packets.
+  # send all tcp packets to the tcp queue
   protocol tcp
-  rule -j input-tcp-security
-  rule -j output-tcp-security
-  protocol none
+  rule -m state --state NEW -j input-tcp
 
+  # send all udp packets to the udp queue
+  protocol udp
+  rule -m state --state NEW -j input-udp
 
-  # Allow ALL input and output connections that have already been established by this host (and made it this far in the chain process).
-  chain OUTPUT
-  #rule -m state --state ESTABLISHED,RELATED -j ACCEPT
-  rule -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
+  # 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
 
-  # send all remaining packets to the unknown queue
-  chain OUTPUT
-  protocol udp
-  rule -m state --state NEW -j output-unknown
 
-  chain INPUT
-  rule -m state --state NEW -j input-unknown
+input-blacklist:
+  direction input
+  protocol none
 
 
-output-tcp:
-  direction output
-  protocol tcp
+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
 
-output-udp:
-  direction output
-  protocol udp
+  # 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.
-  tool iptables
-  rule -s 0.0.0.0 --sport 67 -d 255.255.255.255 --dport 68 -j ACCEPT
-  tool ip46tables
+  # openvpn standard port
+  #rule --dport 1194 -j ACCEPT
 
+  # dns standard port
+  #rule --dport 53 -j ACCEPT
 
-output-icmp:
-  direction output
-  protocol icmp
+  # 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 -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-unkown:
-  direction output
-  protocol none
+  # redirect
+  rule --icmp-type 5 -j ACCEPT
 
-  # drop unknown packets.
-  #rule -j DROP
+  # (outgoing) ping
+  rule --icmp-type 0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
 
+  # time exceeded
+  rule --icmp-type 11 -j ACCEPT
 
-input-unkown:
-  direction input
-  protocol none
+  # parameter problem
+  rule --icmp-type 12 -j ACCEPT
 
-  # drop unknown packets.
-  #rule -j DROP
+  # 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
@@ -193,151 +293,307 @@ input-casting:
   rule -j DROP
 
 
-output-casting:
-  # pre-process broadcasts and multicasts.
+OUTPUT:
+  # main output chain, expect this to act as the final RETURN handler.
   direction output
   protocol none
-  tool ip46tables
 
-  # do not auto-drop dhcp client messages sent to a dhcp server.
-  # dhcp discover/request (for the request, the dhcp server ip address is known but for some reason the dhcp standard states tat the src is 0.0.0.0.
+  # 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
-  tool iptables
-  rule --sport 68 -d 255.255.255.255 --dport 67 -j RETURN
+  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
-  tool ip46tables
 
-  # drop all remaining broadcasts and multicasts
+  # remaining packets
   rule -j DROP
 
 
-input-loopback:
+output-invalid-stream:
   direction input
+  protocol tcp
+
+  # remaining packets
+  rule -j REJECT --reject-with tcp-reset
+
+
+output-loop:
+  direction output
   protocol none
 
-  # send all valid loopback connections back to the main tree so that the remainder firewall rules apply.
+  # allow cups via loopback.
+  protocol tcp
   tool iptables
-  rule -s 127.0.0.0/8 -d 127.0.0.0/8 -j RETURN
-  tool ip6tables
-  rule -s ::1/128 -d ::1/128 -j RETURN
+  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
 
-  # this is a link-local address.
-  rule -s fe80::/10 -d fe80::/10 -j RETURN
-  tool ip46tables
+  # 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
 
-  # all packets to a known ethernet devices ip address are (incorrectly) sent to loopback by applications like apache.
-  # these specific rules may need to be allowed despite the ip address being incorrect.
-  # specifically, only 127.0.0.0/8 ip address should ever been sent to the loopback.
-  # this is an example rule using an example ip address.
-  #tool iptables
+  # 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
+  tool ip46tables
 
-  # the remaining loopback packets are therefore invalid, log them and then drop them. (these options might be handy: --log-uid --log-tcp-options --log-ip-options)
-  rule -j LOG --log-prefix "INVALID:INPUT:LOOP "
+  # remaining packets
   rule -j DROP
 
 
-output-loopback:
+output-blacklist:
   direction output
   protocol none
 
-  # send all valid loopback connections back to the main tree so that the remainder firewall rules apply.
-  tool iptables
-  rule -s 127.0.0.0/8 -d 127.0.0.0/8 -j RETURN
-  tool ip6tables
-  rule -s ::1/128 -d ::1/128 -j RETURN
 
-  # this is a link-local address.
-  rule -s fe80::/10 -d fe80::/10 -j RETURN
-  tool ip46tables
+output-whitelist:
+  direction output
+  protocol none
 
 
-  # all packets to a known ethernet devices ip address are (incorrectly) sent to loopback by applications like apache.
-  # these specific rules may need to be allowed despite the ip address being incorrect.
-  # specifically, only 127.0.0.0/8 ip address should ever been sent to the loopback.
-  # this is an example rule using an example ip address.
-  #tool iptables
-  #rule -s 192.168.0.1 -d 192.168.0.1 -j RETURN
-  #tool ip46tables
+output-devices:
+  direction output
+  protocol none
 
-  # the remaining loopback packets are therefore invalid, log them and then drop them. (these options might be handy: --log-uid --log-tcp-options --log-ip-options)
-  rule -j LOG --log-prefix "INVALID:OUTPUT:LOOP "
-  rule -j DROP
+  # add device-specific rules here.
 
 
-input-invalid:
-  direction input
+output-tcp:
+  direction output
   protocol tcp
 
-  # silently drop invalid RST tcp packets instead of sending a RST back.
-  rule --tcp-flags RST RST -j DROP
+  # allow sending TCP RST even when there is no valid local connection
+  protocol tcp
+  rule --tcp-flags RST RST -j ACCEPT
 
-  # Reject all remaining invalid tcp packets.
-  rule -j REJECT --reject-with tcp-reset
+  # 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
 
-  # Drop all remaining protocols with invalid data.
-  protocol none
-  rule -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 output-invalid-stream
 
-output-invalid:
+  # 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 tcp
+  protocol udp
 
-  # Allow sending TCP RST even when there is no valid local connection.
-  rule --tcp-flags RST RST -j ACCEPT
+  # openvpn standard port
+  rule --dport 1194 -j ACCEPT
+  #rule --sport 1194 -j ACCEPT
 
-  # Reject all remaining invalid tcp packets.
-  rule -j REJECT --reject-with tcp-reset
+  # dns standard port
+  rule --dport 53 -j ACCEPT
+  #rule --sport 53 -j ACCEPT
 
-  # Drop all remaining protocols with invalid data.
-  protocol none
-  rule -j DROP
+  # 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
 
-input-tcp-security:
-  direction input
-  protocol tcp
+  # dhcp standard port
+  rule --sport 67:68 --dport 67:68 -j ACCEPT
 
-  # Resist TCP sequence number spoof attacks (see: http://www.linuxtopia.org/Linux_Firewall_iptables/x6231.html).
-  rule --tcp-flags SYN,ACK SYN,ACK -m conntrack --ctstate NEW -j input-invalid
+  # 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
 
-  # TCP streams must always start with SYN, all others are invalid and may be an attack (see: http://www.linuxtopia.org/Linux_Firewall_iptables/x6193.html).
-  rule ! --syn -m conntrack --ctstate NEW -j input-invalid
+  # redirect
+  rule --icmp-type 5 -j ACCEPT
 
-  # Prevent an XMAS-type attacks (drop packets).
-  rule --tcp-flags ALL FIN,URG,PSH -j DROP
-  rule --tcp-flags ALL ALL -j DROP
-  rule --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
+  # (outgoing) ping
+  rule --icmp-type 8 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT
 
-  # Prevent NULL attack (drop packets).
-  rule --tcp-flags ALL NONE -j DROP
+  # time exceeded
+  rule --icmp-type 11 -j ACCEPT
 
-  # Prevent Sync Reset Attacks (drop packets).
-  rule --tcp-flags SYN,RST SYN,RST -j DROP
-  rule --tcp-flags SYN,FIN SYN,FIN -j DROP
+  # 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-tcp-security:
+output-icmpv6:
   direction output
-  protocol tcp
+  protocol icmp
+  tool ip6tables
+
+
+output-casting:
+  direction output
+  protocol none
+  tool ip46tables
+
+  # do not auto-drop dhcp client messages sent to a dhcp server.
+  # dhcp discover/request (for the request, the dhcp server ip address is known but for some reason the dhcp standard states tat the src is 0.0.0.0.
+  protocol udp
+  tool iptables
+  rule --sport 68 -d 255.255.255.255 --dport 67 -j RETURN
+  protocol none
+  tool ip46tables
+
+  # drop all remaining broadcasts and multicasts
+  rule -j DROP
+
 
-  # Resist TCP sequence number spoof attacks (see: http://www.linuxtopia.org/Linux_Firewall_iptables/x6231.html).
-  rule --tcp-flags SYN,ACK SYN,ACK -m conntrack --ctstate NEW -j output-invalid
+FORWARD:
 
-  # TCP streams must always start with SYN, all others are invalid and may be an attack (see: http://www.linuxtopia.org/Linux_Firewall_iptables/x6193.html).
-  rule ! --syn -m conntrack --ctstate NEW -j output-invalid
+  # load custom device-specific rules
+  rule -j forward-devices
 
-  # Prevent an XMAS-type attacks (drop packets).
-  rule --tcp-flags ALL FIN,URG,PSH -j DROP
-  rule --tcp-flags ALL ALL -j DROP
-  rule --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
 
-  # Prevent NULL attack (drop packets).
-  rule --tcp-flags ALL NONE -j DROP
+forward-devices:
 
-  # Prevent Sync Reset Attacks (drop packets).
-  rule --tcp-flags SYN,RST SYN,RST -j DROP
-  rule --tcp-flags SYN,FIN SYN,FIN -j DROP
+  # 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