]> Kevux Git Server - fll/commitdiff
Update: rewrite firewall, adding support for custom chains
authorKevin Day <kevin@kevux.org>
Thu, 7 Jun 2012 23:06:57 +0000 (18:06 -0500)
committerKevin Day <kevin@kevux.org>
Thu, 7 Jun 2012 23:06:57 +0000 (18:06 -0500)
This is a major redesign of the firewall program.
Iptables chains are now supported automatically.
Each new basic list is itself a chain.
Reserved words not allowed for custom chains are:
- main
- stop
- lock

The 'main' chain signifies use of the default iptables chain.

The layout and structure of the files have been rewritten to utilize chains.
The default-firewall file has been removed and replaced with the following files:
- firewall-first
- firewall-last
- firewall-other

The newly written rules defines default firewall rules and chains such that there the following self-explanatory chains:
- input-tcp
- input-udp
- input-icmp
- output-tcp
- output-udp
- output-firewall

In addition to the above changes, the base functionality has been broken up into smaller functions to improve code quality.

level_3/firewall/c/firewall.c
level_3/firewall/c/firewall.h
level_3/firewall/c/private-firewall.c
level_3/firewall/c/private-firewall.h

index c4924d4de4a0773adfbf74739f8cbb5653c9ef26..ebb9a63a0b474ae0e84d5064694a559d845ae0a6 100644 (file)
@@ -108,21 +108,21 @@ extern "C"{
 
 #ifndef _di_firewall_main_
   f_return_status firewall_main(const f_s_int argc, const f_string argv[], firewall_data *data) {
-    f_status status            = f_status_initialize;
-    f_status allocation_status = f_status_initialize;
+    f_status status  = f_status_initialize;
+    f_status status2 = f_status_initialize;
 
     status = fl_process_parameters(argc, argv, data->parameters, firewall_total_parameters, &data->remaining);
 
     // load colors when not told to show no colors
     if (data->parameters[firewall_parameter_no_color].result == f_console_result_none) {
-      fll_new_color_context(allocation_status, data->context);
+      fll_new_color_context(status2, data->context);
 
-      if (allocation_status == f_none) {
+      if (status2 == f_none) {
         fll_colors_load_context(&data->context, data->parameters[firewall_parameter_light].result == f_console_result_found);
       } else {
         fprintf(f_standard_error, "Critical Error: unable to allocate memory\n");
         firewall_delete_data(data);
-        return allocation_status;
+        return status2;
       }
     }
 
@@ -204,82 +204,9 @@ extern "C"{
       }
 
       if (found_command) {
-        // load the global file
-        {
-          f_file file = f_file_initialize;
-
-          status = f_file_open(&file, (f_string) network_path firewall_file_default);
-
-          if (status != f_none) {
-            if (status == f_invalid_parameter) {
-              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) {
-              fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Unable to find the file '%s'", network_path firewall_file_default);
-            } 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'", network_path firewall_file_default);
-            } 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'", network_path firewall_file_default);
-            } else {
-              fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling f_file_open()", status);
-            }
-
-            firewall_delete_data(data);
-            return status;
-          }
-
-          // TODO: this file size set functionality might be turned into an fl_file (or f_file) function
-          if (data->file_position.total_elements == 0) {
-            fseek(file.file, 0, SEEK_END);
-            data->file_position.total_elements = ftell(file.file);
-            fseek(file.file, 0, SEEK_SET);
-          }
-
-          status = fl_file_read(file, data->file_position, &data->buffer);
-
-          f_file_close(&file);
-
-          if (status != f_none && status != f_none_on_eof) {
-            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'", network_path firewall_file_default);
-            } 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", network_path firewall_file_default);
-            } 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'", network_path firewall_file_default);
-            } 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'", network_path firewall_file_default);
-            } 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 fl_file_read()", status);
-            }
-
-            firewall_delete_data(data);
-            return status;
-          } else {
-            f_string_location input = f_string_location_initialize;
-
-            input.stop = data->buffer.used - 1;
-
-            status = fll_fss_basic_list_read(&data->buffer, &input, &data->objects, &data->contents);
-          }
-
-          if (status != f_none && status != f_none_on_eos && status != f_none_on_stop && status != fl_fss_found_object_no_content) {
-            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_list_read() for the file '%s'", network_path firewall_file_default);
-            } 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, "ERROR: No relevant data was found within the file '%s'", network_path firewall_file_default);
-            } 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_list_read() for the file '%s'", status, network_path firewall_file_default);
-            }
-
-            firewall_delete_data(data);
-            return status;
-          }
-        }
+        firewall_local_data local = firewall_local_data_initialize;
+        firewall_reserved_chains reserved = firewall_reserved_chains_initialize;
+        f_string_location input = f_string_location_initialize;
 
         if (command == firewall_parameter_command_show) {
           // Warning: these are hardcoded print commands (I am not certain how I am going to implement external 'show' rules as the default-firewall setting file is the wrong place to put this)
@@ -318,6 +245,7 @@ extern "C"{
 
           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");
+            firewall_delete_local_data(&local);
             firewall_delete_data(data);
             return status;
           }
@@ -440,8 +368,9 @@ extern "C"{
           arguments.array[4].used = 0;
           arguments.array[5].used = 0;
           arguments.array[6].used = 0;
-          f_delete_dynamic_strings(status, arguments);
 
+          f_delete_dynamic_strings(status, arguments);
+          firewall_delete_local_data(&local);
           firewall_delete_data(data);
           return f_none;
         }
@@ -451,30 +380,33 @@ extern "C"{
 
         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");
+          firewall_delete_local_data(&local);
           firewall_delete_data(data);
           return status;
         } else if (status == f_no_data) {
           fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: could not find any network devices");
+          firewall_delete_local_data(&local);
           firewall_delete_data(data);
           return status;
         } else if (status == f_failure) {
           fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: failed to read the device directory '%s'", network_devices);
+          firewall_delete_local_data(&local);
           firewall_delete_data(data);
           return status;
         }
 
         // remove "lo" (loopback) from the device listing
         {
-          f_string_length counter = f_string_length_initialize;
+          f_string_length i = f_string_length_initialize;
 
-          for (; counter < data->devices.used; counter++) {
-            if (fl_compare_strings((f_string) "lo", data->devices.array[counter].string, 3, data->devices.array[counter].used) == f_equal_to) {
-              f_dynamic_string swap_string = data->devices.array[counter];
+          for (; i < data->devices.used; i++) {
+            if (fl_compare_strings((f_string) firewall_device_loop, data->devices.array[i].string, firewall_device_loop_length + 1, data->devices.array[i].used) == f_equal_to) {
+              f_dynamic_string swap_string = data->devices.array[i];
 
               data->devices.used--;
 
-              for (; counter < data->devices.used; counter++) {
-                data->devices.array[counter] = data->devices.array[counter+1];
+              for (; i < data->devices.used; i++) {
+                data->devices.array[i] = data->devices.array[i+1];
               }
 
               data->devices.array[data->devices.used] = swap_string;
@@ -482,947 +414,252 @@ extern "C"{
           }
         }
 
-        // if at least one specific device was specified, then only use the specified devices, otherwise use all
-        if (data->remaining.used > 0) {
-          f_string_length device  = f_string_length_initialize;
-          f_string_length counter = f_string_length_initialize;
-          f_string_length total   = f_string_length_initialize;
-          f_string_length i       = f_string_length_initialize;
-          f_bool          matched = f_false;
+        if (command == firewall_parameter_command_stop || command == firewall_parameter_command_restart || command == firewall_parameter_command_lock) {
+          status = firewall_buffer_rules(network_path firewall_file_other, f_false, &local, data);
 
-          for (total = data->devices.used; device < total; device++) {
-            matched = f_false;
+          if (status != f_none && status != f_none_on_eof && status != f_none_on_eos && status != f_none_on_stop && status != fl_fss_found_object_no_content) {
+            firewall_delete_local_data(&local);
+            firewall_delete_data(data);
+            return status;
+          }
+
+          {
+            f_array_length i = f_array_length_initialize;
+            f_string_length length = f_string_length_initialize;
+
+            for (; i < local.chain_objects.used; i++) {
+              length = local.chain_objects.array[i].stop - local.chain_objects.array[i].start + 1;
 
-            for (counter = 0; counter < data->remaining.used; counter++) {
-              if (strncmp(data->devices.array[device].string, argv[data->remaining.array[counter]], strlen(argv[data->remaining.array[counter]])) == 0) {
-                matched = f_true;
+              if (!reserved.has_stop && fl_compare_strings((f_string) firewall_group_stop, local.buffer.string + local.chain_objects.array[i].start, firewall_group_stop_length, length) == f_equal_to) {
+                reserved.stop_at = i;
+                reserved.has_stop = f_true;
+              } else if (!reserved.has_lock && fl_compare_strings((f_string) firewall_group_lock, local.buffer.string + local.chain_objects.array[i].start, firewall_group_lock_length, length) == f_equal_to) {
+                reserved.lock_at = i;
+                reserved.has_lock = f_true;
               }
-            }
+            } // for
+          }
 
-            if (!matched) {
-              f_dynamic_string swap_string = data->devices.array[device];
+          if (command == firewall_parameter_command_lock) {
+            if (reserved.has_lock) {
+              local.is_main = f_false;
+              local.is_stop = f_false;
+              local.is_lock = f_true;
+              local.chain = reserved.lock_at;
 
-              data->devices.used--;
+              input.start = local.chain_contents.array[reserved.lock_at].array[0].start;
+              input.stop = local.chain_contents.array[reserved.lock_at].array[0].stop;
 
-              for (i = device; i < data->devices.used; i++) {
-                data->devices.array[i] = data->devices.array[i+1];
-              }
+              status = firewall_process_rules(&input, &local, data);
 
-              data->devices.array[data->devices.used] = swap_string;
+              firewall_delete_local_data(&local);
+              firewall_delete_data(data);
+              return status;
+            } 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);
 
-              total--;
-              device--;
+              firewall_delete_local_data(&local);
+              firewall_delete_data(data);
+              return f_invalid_data;
             }
           }
-        }
 
-        // report and remove all "invalid" devices that are specified in the "remaining" variable
-        {
-          f_string_length device  = f_string_length_initialize;
-          f_string_length counter = f_string_length_initialize;
-          f_bool          matched = f_false;
+          if (command == firewall_parameter_command_stop || command == firewall_parameter_command_restart) {
+            if (reserved.has_stop) {
+              local.is_global = f_true;
+              local.is_main = f_false;
+              local.is_stop = f_true;
+              local.is_lock = f_false;
+              local.chain = reserved.stop_at;
+
+              input.start = local.chain_contents.array[reserved.stop_at].array[0].start;
+              input.stop = local.chain_contents.array[reserved.stop_at].array[0].stop;
 
-          for (; counter < data->remaining.used; counter++) {
-            matched = f_false;
+              status = firewall_process_rules(&input, &local, data);
 
-            for (device = 0; device < data->devices.used; device++) {
-              if (strncmp(data->devices.array[device].string, argv[data->remaining.array[counter]], strlen(argv[data->remaining.array[counter]])) == 0) {
-                matched = f_true;
+              if (status != f_none || command == firewall_parameter_command_stop) {
+                firewall_delete_local_data(&local);
+                firewall_delete_data(data);
+                return status;
               }
-            }
+            } 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);
 
-            if (!matched) {
-              fl_print_color_line(f_standard_warning, data->context.warning, data->context.reset, "WARNING: There is no device by the name of '%s'", argv[data->remaining.array[counter]]);
+              firewall_delete_local_data(&local);
+              firewall_delete_data(data);
+              return f_invalid_data;
             }
           }
 
-          // cleanup, the 'remaining' parameters are no longer needed
-          f_delete_string_locations(status, data->remaining);
+          firewall_delete_local_data(&local);
         }
 
-        // identify global firewall settings
-        f_string_length first = f_string_length_initialize;
-        f_string_length last  = f_string_length_initialize;
-        f_string_length stop  = f_string_length_initialize;
-        f_string_length lock  = f_string_length_initialize;
-
-        f_bool found_first = f_false;
-        f_bool found_last  = f_false;
-        f_bool found_stop  = f_false;
-        f_bool found_lock  = f_false;
-
-        f_string_length length  = f_string_length_initialize;
-        f_string_length counter = f_string_length_initialize;
-
-        // identify which position is which
-        for (; counter < data->objects.used; counter++) {
-          length = data->objects.array[counter].stop - data->objects.array[counter].start + 1;
-
-          if (!found_first && fl_compare_strings((f_string) firewall_group_first, data->buffer.string + data->objects.array[counter].start, firewall_group_first_length, length) == f_equal_to) {
-            first = counter;
-            found_first = f_true;
-          } else if (!found_last && fl_compare_strings((f_string) firewall_group_last, data->buffer.string + data->objects.array[counter].start, firewall_group_last_length, length) == f_equal_to) {
-            last = counter;
-            found_last = f_true;
-          } else if (!found_stop && fl_compare_strings((f_string) firewall_group_stop, data->buffer.string + data->objects.array[counter].start, firewall_group_stop_length, length) == f_equal_to) {
-            stop = counter;
-            found_stop = f_true;
-          } else if (!found_lock && fl_compare_strings((f_string) firewall_group_lock, data->buffer.string + data->objects.array[counter].start, firewall_group_lock_length, length) == f_equal_to) {
-            lock = counter;
-            found_lock = f_true;
-          } else {
-            if (data->custom.used >= data->custom.size) {
-              f_resize_string_lengths(status, data->custom, data->custom.size + firewall_default_allocation_step);
+        if (command == firewall_parameter_command_start || command == firewall_parameter_command_restart) {
+          status = firewall_buffer_rules(network_path firewall_file_first, f_false, &local, data);
 
-              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");
-                firewall_delete_data(data);
-                return status;
-              }
-            }
+          if (status != f_none && status != f_none_on_eof && status != f_none_on_eos && status != f_none_on_stop && status != fl_fss_found_object_no_content) {
+            firewall_delete_local_data(&local);
+            firewall_delete_data(data);
+            return status;
+          };
 
-            data->custom.array[data->custom.used] = counter;
-            data->custom.used++;
+          status = firewall_create_custom_chains(&reserved, &local, data);
+
+          if (status != f_none) {
+            firewall_delete_local_data(&local);
+            firewall_delete_data(data);
+            return status;
           }
-        }
 
-        if (found_first && found_last && found_stop && found_lock) {
-          f_string_length error_file = f_string_length_initialize;
-          status = f_none;
+          f_array_length i = 0;
 
-          f_fss_objects  extended_objects  = f_fss_objects_initialize;
-          f_fss_contents extended_contents = f_fss_contents_initialize;
+          local.is_global = f_true;
+          local.is_stop = f_false;
+          local.is_lock = f_false;
 
-          if (command == firewall_parameter_command_lock) {
-            f_string_location input = f_string_location_initialize;
+          while (i < local.chain_contents.used) {
+            input.start = local.chain_contents.array[i].array[0].start;
+            input.stop = local.chain_contents.array[i].array[0].stop;
 
-            input.start = data->contents.array[lock].array[0].start;
-            input.stop  = data->contents.array[lock].array[0].stop;
-            error_file  = lock;
+            local.is_main = reserved.has_main && i == reserved.main_at ? f_true : f_false;
+            local.chain = i;
 
-            status = fll_fss_extended_read(&data->buffer, &input, &extended_objects, &extended_contents);
+            status = firewall_process_rules(&input, &local, data);
 
-            if (status == f_none || status == f_none_on_stop || status == f_none_on_eos) {
-              status = firewall_perform_commands(extended_objects, extended_contents, f_true, 0, data->buffer, *data, f_null);
+            if ((status != f_none && status != f_no_data && status != f_no_data_on_stop) || command == firewall_parameter_command_stop) {
+              firewall_delete_local_data(&local);
+              firewall_delete_data(data);
+              return status;
+            }
 
-              if (status != f_none) {
-                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", status);
-                } else if (status == f_failure) {
-                  // the error message has already been displayed
-                } else {
-                  fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling firewall_perform_commands()", status);
-                }
+            i++;
+          } // while
+
+          firewall_delete_local_data(&local);
+
+          for (i = 0; i < data->devices.used; i++) {
+            local.device = i;
 
-                f_delete_fss_objects(allocation_status, extended_objects);
-                f_delete_fss_contents(allocation_status, extended_contents);
+            {
+              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);
+
+              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.", status);
+                firewall_delete_local_data(&local);
                 firewall_delete_data(data);
                 return status;
               }
-            }
-          } else {
-            if (command == firewall_parameter_command_stop || command == firewall_parameter_command_restart) {
-              f_string_location input = f_string_location_initialize;
 
-              input.start = data->contents.array[stop].array[0].start;
-              input.stop  = data->contents.array[stop].array[0].stop;
-              error_file  = stop;
+              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;
+              file_path.string[file_path.used] = 0;
 
-              status = fll_fss_extended_read(&data->buffer, &input, &extended_objects, &extended_contents);
+              status = firewall_buffer_rules(file_path.string, f_true, &local, data);
 
-              if (status == f_none || status == f_none_on_stop || status == f_none_on_eos) {
-                status = firewall_perform_commands(extended_objects, extended_contents, f_true, 0, data->buffer, *data, f_null);
-              }
+              f_delete_dynamic_string(status2, file_path);
             }
 
-            if ((status == f_none || status == f_none_on_stop || status == f_none_on_eos) && (command == firewall_parameter_command_start || command == firewall_parameter_command_restart)) {
-              f_delete_fss_objects(status, extended_objects);
-              f_delete_fss_contents(status, extended_contents);
-
-              f_string_location input = f_string_location_initialize;
+            if (status != f_none && status != f_none_on_eof && status != f_none_on_eos && status != f_none_on_stop) {
+              firewall_delete_local_data(&local);
 
-              input.start = data->contents.array[first].array[0].start;
-              input.stop  = data->contents.array[first].array[0].stop;
-              error_file  = first;
+              if (status == f_file_not_found || status == f_file_open_error || status == f_file_descriptor_error || status == fl_fss_found_object_no_content) {
+                continue;
+              }
 
-              status = fll_fss_extended_read(&data->buffer, &input, &extended_objects, &extended_contents);
+              firewall_delete_data(data);
+              return status;
+            }
 
-              if (status == f_none || status == f_none_on_stop || status == f_none_on_eos) {
-                status = firewall_perform_commands(extended_objects, extended_contents, f_true, 0, data->buffer, *data, f_null);
+            status = firewall_create_custom_chains(&reserved, &local, data);
 
-                if (status != f_none) {
-                  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", status);
-                  } else if (status == f_failure) {
-                    // the error message has already been displayed
-                  } else {
-                    fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling firewall_perform_commands()", status);
-                  }
+            if (status != f_none) {
+              firewall_delete_local_data(&local);
+              firewall_delete_data(data);
+              return status;
+            }
 
-                  f_delete_fss_objects(allocation_status, extended_objects);
-                  f_delete_fss_contents(allocation_status, extended_contents);
+            f_array_length j = 0;
 
-                  firewall_delete_data(data);
-                  return status;
-                } else {
-                  f_delete_fss_objects(status, extended_objects);
-                  f_delete_fss_contents(status, extended_contents);
-
-                  f_string_length counter = 0;
-
-                  {
-                    f_dynamic_string chain_argument = f_dynamic_string_initialize;
-
-                    while (counter < data->custom.used) {
-                      f_dynamic_string custom_chain   = f_dynamic_string_initialize;
-                      f_string_length  chain_location = 0;
-
-                      input.start = data->objects.array[data->custom.array[counter]].start;
-                      input.stop  = data->objects.array[data->custom.array[counter]].stop;
+            local.is_global = f_false;
+            local.is_stop = f_false;
+            local.is_lock = f_false;
 
-                      // ensure that the chain exists
-                      if (counter < data->custom.used && data->custom.array[counter] < data->objects.used) {
-                        f_string_length counter2  = 0;
-                        f_string_length max_size  = 0;
-                        f_bool          new_chain = f_true;
-
-                        counter2 = input.start;
-                        max_size = input.stop - input.start + 1;
-
-                        if (max_size >= custom_chain.size) {
-                          f_resize_dynamic_string(status, custom_chain, max_size + firewall_default_allocation_step);
+            for (; j < local.chain_contents.used; j++) {
+              input.start = local.chain_contents.array[j].array[0].start;
+              input.stop = local.chain_contents.array[j].array[0].stop;
 
-                          if (f_macro_test_for_allocation_errors(status)) {
-                            f_status allocation_status = f_status_initialize;
-
-                            f_delete_dynamic_string(allocation_status, custom_chain);
-                            f_delete_dynamic_string(allocation_status, chain_argument);
-                            f_delete_fss_objects(allocation_status, extended_objects);
-                            f_delete_fss_contents(allocation_status, extended_contents);
-                            firewall_delete_data(data);
-                            return status;
-                          }
-                        }
-
-                        custom_chain.used = 0;
-                        counter2 = input.start;
-                        while (counter2 <= input.stop && custom_chain.used <= custom_chain.size) {
-                          if (data->buffer.string[counter2] == f_fss_delimit_placeholder) {
-                            counter2++;
-                            continue;
-                          }
+              local.is_main = reserved.has_main && j == reserved.main_at ? f_true : f_false;
+              local.chain = j;
 
-                          custom_chain.string[custom_chain.used] = data->buffer.string[counter2];
-                          custom_chain.used++;
-                          counter2++;
-                        } // while
+              status = firewall_process_rules(&input, &local, data);
 
-                        if (firewall_chain_create_command_length > chain_argument.size) {
-                          f_resize_dynamic_string(status, chain_argument, firewall_chain_create_command_length);
+              if ((status != f_none && status != f_no_data && status != f_no_data_on_stop) || command == firewall_parameter_command_stop) {
+                firewall_delete_local_data(&local);
+                firewall_delete_data(data);
+                return status;
+              }
+            } // for
 
-                          if (f_macro_test_for_allocation_errors(status)) {
-                            f_status allocation_status = f_status_initialize;
+            firewall_delete_local_data(&local);
+          } // for
 
-                            f_delete_dynamic_string(allocation_status, custom_chain);
-                            f_delete_dynamic_string(allocation_status, chain_argument);
-                            f_delete_fss_objects(allocation_status, extended_objects);
-                            f_delete_fss_contents(allocation_status, extended_contents);
-                            firewall_delete_data(data);
-                            return status;
-                          }
-                        }
+          // TODO: process each network device here.
+          // process the "main" rule.
+          // process all remaining rules in top-down order, skipping the main rule.
+          // pre-process the "network device" file, storing main location as well as creating&storing each of the custom chains.
+          // process the "main" rule.
+          // process all remaining rules in top-down order, skipping the main rule.
+          // pre-process the "last" file, storing main location as well as creating&storing each of the custom chains.
+          // process the "main" rule.
+          // process all remaining rules in top-down order, skipping the main rule.
 
-                        strncat(chain_argument.string, firewall_chain_create_command, firewall_chain_create_command_length);
-                        chain_argument.used = firewall_chain_create_command_length;
-                        chain_location = 0;
-
-
-                        while (chain_location < data->chains.used) {
-                          if (fl_compare_dynamic_strings(custom_chain, data->chains.array[chain_location]) == f_equal_to) {
-                            f_delete_dynamic_string(allocation_status, custom_chain);
-
-                            new_chain = f_false;
-                            break;
-                          }
-
-                          chain_location++;
-                        } // while
+          status = firewall_buffer_rules(network_path firewall_file_last, f_false, &local, data);
 
-                        if (new_chain) {
-                          if (data->chains.used >= data->chains.size) {
-                            f_resize_dynamic_strings(status, data->chains, data->chains.size + firewall_default_allocation_step);
-
-                            if (f_macro_test_for_allocation_errors(status)) {
-                              f_status allocation_status = f_status_initialize;
-
-                              f_delete_dynamic_string(allocation_status, custom_chain);
-                              f_delete_dynamic_string(allocation_status, chain_argument);
-                              f_delete_fss_objects(allocation_status, extended_objects);
-                              f_delete_fss_contents(allocation_status, extended_contents);
-                              firewall_delete_data(data);
-                              return status;
-                            }
-                          }
-
-                          f_s_int           results   = 0;
-                          f_dynamic_strings arguments = f_dynamic_strings_initialize;
-
-                          f_resize_dynamic_strings(status, arguments, 3);
-
-                          arguments.array[0].string = (f_string) firewall_chain_create_command;
-                          arguments.array[1].string = chain_argument.string;
-                          arguments.array[2].string = custom_chain.string;
-
-                          arguments.array[0].used = firewall_chain_create_command_length;
-                          arguments.array[1].used = chain_argument.used;
-                          arguments.array[2].used = custom_chain.used;
-
-                          arguments.used = 3;
-                          arguments.size = 3;
-
-                          if (f_macro_test_for_allocation_errors(status)) {
-                            f_status allocation_status = f_status_initialize;
-
-                            arguments.array[0].string = 0;
-                            arguments.array[1].string = 0;
-                            arguments.array[2].string = 0;
-
-                            arguments.array[0].used = 0;
-                            arguments.array[1].used = 0;
-                            arguments.array[2].used = 0;
-
-                            f_delete_dynamic_string(allocation_status, custom_chain);
-                            f_delete_dynamic_string(allocation_status, chain_argument);
-                            f_delete_dynamic_strings(allocation_status, arguments);
-                            f_delete_fss_objects(allocation_status, extended_objects);
-                            f_delete_fss_contents(allocation_status, extended_contents);
-                            firewall_delete_data(data);
-                            return status;
-                          }
-
-                          status = fll_execute_program((f_string) firewall_program_name, arguments, &results);
-
-                          if (status == f_failure) {
-                            f_status allocation_status = f_status_initialize;
-
-                            fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Failed to perform requested %s operation:", firewall_program_name);
-                            fprintf(f_standard_error, "  ");
-
-                            f_string_length i = f_string_length_initialize;
-
-                            fl_print_color_code(f_standard_error, data->context.error);
-
-                            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");
-
-                            arguments.array[0].string = 0;
-                            arguments.array[1].string = 0;
-                            arguments.array[2].string = 0;
-
-                            arguments.array[0].used = 0;
-                            arguments.array[1].used = 0;
-                            arguments.array[2].used = 0;
-
-                            f_delete_dynamic_string(allocation_status, custom_chain);
-                            f_delete_dynamic_string(allocation_status, chain_argument);
-                            f_delete_dynamic_strings(allocation_status, arguments);
-                            f_delete_fss_objects(allocation_status, extended_objects);
-                            f_delete_fss_contents(allocation_status, extended_contents);
-                            firewall_delete_data(data);
-                            return status;
-                          } else if (status == f_invalid_parameter) {
-                            f_status allocation_status = f_status_initialize;
-
-                            fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_execute_path()");
-
-                            arguments.array[0].string = 0;
-                            arguments.array[1].string = 0;
-                            arguments.array[2].string = 0;
-
-                            arguments.array[0].used = 0;
-                            arguments.array[1].used = 0;
-                            arguments.array[2].used = 0;
-
-                            f_delete_dynamic_string(allocation_status, custom_chain);
-                            f_delete_dynamic_string(allocation_status, chain_argument);
-                            f_delete_dynamic_strings(allocation_status, arguments);
-                            f_delete_fss_objects(allocation_status, extended_objects);
-                            f_delete_fss_contents(allocation_status, extended_contents);
-                            firewall_delete_data(data);
-                            return status;
-                          }
-
-                          arguments.array[0].string = 0;
-                          arguments.array[1].string = 0;
-                          arguments.array[2].string = 0;
-
-                          arguments.array[0].used = 0;
-                          arguments.array[1].used = 0;
-                          arguments.array[2].used = 0;
-
-                          f_delete_dynamic_strings(status, arguments);
-
-                          data->chains.array[data->chains.used] = custom_chain;
-                          custom_chain.string = 0;
-                          custom_chain.used = 0;
-                          chain_location = data->chains.used;
-                          data->chains.used++;
-                        }
-                      }
-
-                      input.start = data->contents.array[data->custom.array[counter]].array[0].start;
-                      input.stop  = data->contents.array[data->custom.array[counter]].array[0].stop;
-
-                      status = fll_fss_extended_read(&data->buffer, &input, &extended_objects, &extended_contents);
-
-                      if (status == f_none || status == f_none_on_stop || status == f_none_on_eos) {
-                        status = firewall_perform_commands(extended_objects, extended_contents, f_true, counter, data->buffer, *data, &data->chains.array[chain_location]);
-
-                        if (status != f_none) {
-                          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", status);
-                          } else if (status == f_failure) {
-                            // the error message has already been displayed
-                          } else {
-                            fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling firewall_perform_commands()", status);
-                          }
-                        }
-                      }
-
-                      f_delete_dynamic_string(status, chain_argument);
-                      f_delete_fss_objects(status, extended_objects);
-                      f_delete_fss_contents(status, extended_contents);
-
-                      counter++;
-                    } // while
-                  }
+          if (status != f_none && status != f_none_on_eof && status != f_none_on_eos && status != f_none_on_stop && status != fl_fss_found_object_no_content) {
+            firewall_delete_local_data(&local);
+            firewall_delete_data(data);
+            return status;
+          }
 
-                  counter = 0;
-
-                  for (; counter < data->devices.used; counter++) {
-                    f_file           file          = f_file_initialize;
-                    f_dynamic_string file_path     = f_dynamic_string_initialize;
-                    f_dynamic_string buffer        = f_dynamic_string_initialize;
-                    f_file_position  file_position = f_file_position_initialize;
-
-                    f_fss_objects  list_objects  = f_fss_objects_initialize;
-                    f_fss_contents list_contents = f_fss_objects_initialize;
-
-                    f_resize_dynamic_string(status, file_path, network_path_length + data->devices.array[counter].used + firewall_file_suffix_length + 1);
-
-                    if (status == f_none) {
-                      strncat(file_path.string, network_path, network_path_length);
-                      strncat(file_path.string + network_path_length, data->devices.array[counter].string, data->devices.array[counter].used);
-                      strncat(file_path.string, firewall_file_suffix, firewall_file_suffix_length);
-                      file_path.used = file_path.size;
-                      file_path.string[file_path.used] = 0;
-
-                      status = f_file_open(&file, file_path.string);
-                    }
-
-                    if (status != f_none) {
-                      if (status == f_invalid_parameter) {
-                        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) {
-                        // If these files do not exist, it is not a problem (they are not required)
-                      } 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);
-                      } 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);
-                      } 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", status);
-
-                        f_file_close(&file);
-                        f_delete_dynamic_string(allocation_status, file_path);
-                        firewall_delete_data(data);
-                        return status;
-                      } else {
-                        fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling f_file_open()", status);
-                      }
-
-                      f_file_close(&file);
-                      f_delete_dynamic_string(allocation_status, file_path);
-                      continue;
-                    }
-
-
-                    if (data->file_position.total_elements == 0) {
-                      fseek(file.file, 0, SEEK_END);
-                      data->file_position.total_elements = ftell(file.file);
-                      fseek(file.file, 0, SEEK_SET);
-                    }
-
-                    status = fl_file_read(file, file_position, &buffer);
-
-                    f_file_close(&file);
-
-                    if (status != f_none && status != f_none_on_eof) {
-                      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)) {
-                        fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory", status);
-
-                        f_delete_dynamic_string(allocation_status, buffer);
-                        f_delete_dynamic_string(allocation_status, file_path);
-                        firewall_delete_data(data);
-                        return status;
-                      } 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()", status);
-                      }
-
-                      f_delete_dynamic_string(allocation_status, buffer);
-                      f_delete_dynamic_string(allocation_status, file_path);
-                      continue;
-                    }
-
-                    {
-                      f_string_location input = f_string_location_initialize;
-
-                      input.stop = buffer.used - 1;
-
-                      status = fll_fss_basic_list_read(&buffer, &input, &list_objects, &list_contents);
-                    }
-
-                    if (status != f_none && status != f_none_on_eos && status != f_none_on_stop && status != fl_fss_found_object_no_content) {
-                      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_list_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, "ERROR: No relevant data was found within the file '%s'", 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", status);
-                      } 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_list_read() for the file '%s'", status, file_path.string);
-                      }
-
-                      f_delete_dynamic_string(allocation_status, buffer);
-                      f_delete_dynamic_string(allocation_status, file_path);
-                      f_delete_fss_objects(allocation_status, list_objects);
-                      f_delete_fss_contents(allocation_status, list_contents);
-                      firewall_delete_data(data);
-                      return status;
-                    }
-
-                    {
-                      f_string_length buffer_counter = f_string_length_initialize;
-                      f_string_length length         = f_string_length_initialize;
-
-                      while (buffer_counter < list_objects.used) {
-                        length = list_objects.array[buffer_counter].stop - list_objects.array[buffer_counter].start + 1;
-
-                        if (fl_compare_strings((f_string) firewall_group_main, buffer.string + list_objects.array[buffer_counter].start, firewall_group_main_length, length) == f_equal_to) {
-                          f_string_location input = f_string_location_initialize;
-
-                          input.start = list_contents.array[buffer_counter].array[0].start;
-                          input.stop  = list_contents.array[buffer_counter].array[0].stop;
-
-                          status = fll_fss_extended_read(&buffer, &input, &extended_objects, &extended_contents);
-
-                          if (status == f_none || status == f_none_on_stop || status == f_none_on_eos) {
-                            status = firewall_perform_commands(extended_objects, extended_contents, f_false, counter, buffer, *data, f_null);
-
-                            if (status != f_none) {
-                              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", status);
-                              } else if (status == f_failure) {
-                                // the error message has already been displayed
-                              } else {
-                                fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling firewall_perform_commands()", status);
-                              }
-                            }
-                          } 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_fss_extended_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, "ERROR: No relevant data was found within the file '%s'", 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", status);
-                            } 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_extended_read() for the file '%s'", status, file_path.string);
-                            }
-                          }
-                        } else if (fl_compare_strings((f_string) firewall_group_first, buffer.string + list_objects.array[buffer_counter].start, firewall_group_first_length, length) == f_equal_to) {
-                          // skip this, device-specific rules do not support this.
-                        } else if (fl_compare_strings((f_string) firewall_group_last, buffer.string + list_objects.array[buffer_counter].start, firewall_group_last_length, length) == f_equal_to) {
-                          // skip this, device-specific rules do not support this.
-                        } else if (fl_compare_strings((f_string) firewall_group_stop, buffer.string + list_objects.array[buffer_counter].start, firewall_group_stop_length, length) == f_equal_to) {
-                          // skip this, device-specific rules do not support this.
-                        } else if (fl_compare_strings((f_string) firewall_group_lock, buffer.string + list_objects.array[buffer_counter].start, firewall_group_lock_length, length) == f_equal_to) {
-                          // skip this, device-specific rules do not support this.
-                        } else {
-                          f_delete_fss_objects(allocation_status, extended_objects);
-                          f_delete_fss_contents(allocation_status, extended_contents);
-
-                          f_string_location input = f_string_location_initialize;
-
-                          f_dynamic_string custom_chain   = f_dynamic_string_initialize;
-                          f_dynamic_string chain_argument = f_dynamic_string_initialize;
-                          f_string_length  chain_location = 0;
-
-                          f_string_length counter2  = 0;
-                          f_string_length max_size  = 0;
-                          f_bool          new_chain = f_true;
-
-                          input.start = list_objects.array[buffer_counter].start;
-                          input.stop  = list_objects.array[buffer_counter].stop;
-
-                          if (data->chains.used >= data->chains.size) {
-                            f_resize_dynamic_strings(status, data->chains, data->chains.size + firewall_default_allocation_step);
-
-                            if (f_macro_test_for_allocation_errors(status)) {
-                              f_status allocation_status = f_status_initialize;
-
-                              f_delete_dynamic_string(allocation_status, custom_chain);
-                              f_delete_dynamic_string(allocation_status, chain_argument);
-                              f_delete_fss_objects(allocation_status, extended_objects);
-                              f_delete_fss_contents(allocation_status, extended_contents);
-                              firewall_delete_data(data);
-                              return status;
-                            }
-                          }
-
-                          // ensure that the chain exists
-                          counter2 = list_objects.array[buffer_counter].start;
-                          max_size = list_objects.array[buffer_counter].stop - list_objects.array[buffer_counter].start + 1;
-
-                          if (max_size >= custom_chain.size) {
-                            f_resize_dynamic_string(status, custom_chain, max_size + firewall_default_allocation_step);
-
-                            if (f_macro_test_for_allocation_errors(status)) {
-                              f_status allocation_status = f_status_initialize;
-
-                              f_delete_dynamic_string(allocation_status, custom_chain);
-                              f_delete_dynamic_string(allocation_status, chain_argument);
-                              f_delete_fss_objects(allocation_status, extended_objects);
-                              f_delete_fss_contents(allocation_status, extended_contents);
-                              f_delete_dynamic_string(allocation_status, buffer);
-                              f_delete_dynamic_string(allocation_status, file_path);
-                              f_delete_fss_objects(allocation_status, list_objects);
-                              f_delete_fss_contents(allocation_status, list_contents);
-                              firewall_delete_data(data);
-                              return status;
-                            }
-                          }
-
-                          custom_chain.used = 0;
-                          counter2 = input.start;
-                          while (counter2 <= input.stop && custom_chain.used <= custom_chain.size) {
-                            if (buffer.string[counter2] == f_fss_delimit_placeholder) {
-                              counter2++;
-                              continue;
-                            }
-
-                            custom_chain.string[custom_chain.used] = buffer.string[counter2];
-                            custom_chain.used++;
-                            counter2++;
-                          } // while
-
-                          if (firewall_chain_create_command_length > chain_argument.size) {
-                            f_resize_dynamic_string(status, chain_argument, firewall_chain_create_command_length);
-
-                            if (f_macro_test_for_allocation_errors(status)) {
-                              f_status allocation_status = f_status_initialize;
-
-                              f_delete_dynamic_string(allocation_status, custom_chain);
-                              f_delete_dynamic_string(allocation_status, chain_argument);
-                              f_delete_fss_objects(allocation_status, extended_objects);
-                              f_delete_fss_contents(allocation_status, extended_contents);
-                              f_delete_dynamic_string(allocation_status, buffer);
-                              f_delete_dynamic_string(allocation_status, file_path);
-                              f_delete_fss_objects(allocation_status, list_objects);
-                              f_delete_fss_contents(allocation_status, list_contents);
-                              firewall_delete_data(data);
-                              return status;
-                            }
-                          }
-
-                          strncat(chain_argument.string, firewall_chain_create_command, firewall_chain_create_command_length);
-                          chain_argument.used = firewall_chain_create_command_length;
-                          chain_location = 0;
-
-                          while (chain_location < data->chains.used) {
-                            if (fl_compare_dynamic_strings(custom_chain, data->chains.array[chain_location]) == f_equal_to) {
-                              f_delete_dynamic_string(allocation_status, custom_chain);
-
-                              new_chain = f_false;
-                              break;
-                            }
-
-                            chain_location++;
-                          } // while
-
-                          if (new_chain) {
-                            if (data->chains.used >= data->chains.size) {
-                              f_resize_dynamic_strings(status, data->chains, data->chains.size + firewall_default_allocation_step);
-
-                              if (f_macro_test_for_allocation_errors(status)) {
-                                f_status allocation_status = f_status_initialize;
-
-                                f_delete_dynamic_string(allocation_status, custom_chain);
-                                f_delete_dynamic_string(allocation_status, chain_argument);
-                                f_delete_fss_objects(allocation_status, extended_objects);
-                                f_delete_fss_contents(allocation_status, extended_contents);
-                                f_delete_dynamic_string(allocation_status, buffer);
-                                f_delete_dynamic_string(allocation_status, file_path);
-                                f_delete_fss_objects(allocation_status, list_objects);
-                                f_delete_fss_contents(allocation_status, list_contents);
-                                firewall_delete_data(data);
-                                return status;
-                              }
-                            }
-
-                            f_s_int           results   = 0;
-                            f_dynamic_strings arguments = f_dynamic_strings_initialize;
-
-                            f_resize_dynamic_strings(status, arguments, 3);
-
-                            arguments.array[0].string = (f_string) firewall_chain_create_command;
-                            arguments.array[1].string = chain_argument.string;
-                            arguments.array[2].string = custom_chain.string;
-
-                            arguments.array[0].used = firewall_chain_create_command_length;
-                            arguments.array[1].used = chain_argument.used;
-                            arguments.array[2].used = custom_chain.used;
-
-                            arguments.used = 3;
-                            arguments.size = 3;
-
-                            if (f_macro_test_for_allocation_errors(status)) {
-                              f_status allocation_status = f_status_initialize;
-
-                              arguments.array[0].string = 0;
-                              arguments.array[1].string = 0;
-                              arguments.array[2].string = 0;
-
-                              arguments.array[0].used = 0;
-                              arguments.array[1].used = 0;
-                              arguments.array[2].used = 0;
-
-                              f_delete_dynamic_string(allocation_status, custom_chain);
-                              f_delete_dynamic_string(allocation_status, chain_argument);
-                              f_delete_dynamic_strings(allocation_status, arguments);
-                              f_delete_fss_objects(allocation_status, extended_objects);
-                              f_delete_fss_contents(allocation_status, extended_contents);
-                              f_delete_dynamic_string(allocation_status, buffer);
-                              f_delete_dynamic_string(allocation_status, file_path);
-                              f_delete_fss_objects(allocation_status, list_objects);
-                              f_delete_fss_contents(allocation_status, list_contents);
-                              firewall_delete_data(data);
-                              return status;
-                            }
-
-                            status = fll_execute_program((f_string) firewall_program_name, arguments, &results);
-
-                            if (status == f_failure) {
-                              f_status allocation_status = f_status_initialize;
-
-                              fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Failed to perform requested %s operation:", firewall_program_name);
-                              fprintf(f_standard_error, "  ");
-
-                              f_string_length i = f_string_length_initialize;
-
-                              fl_print_color_code(f_standard_error, data->context.error);
-
-                              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");
-
-                              arguments.array[0].string = 0;
-                              arguments.array[1].string = 0;
-                              arguments.array[2].string = 0;
-
-                              arguments.array[0].used = 0;
-                              arguments.array[1].used = 0;
-                              arguments.array[2].used = 0;
-
-                              f_delete_dynamic_string(allocation_status, custom_chain);
-                              f_delete_dynamic_string(allocation_status, chain_argument);
-                              f_delete_dynamic_strings(allocation_status, arguments);
-                              f_delete_fss_objects(allocation_status, extended_objects);
-                              f_delete_fss_contents(allocation_status, extended_contents);
-                              f_delete_dynamic_string(allocation_status, buffer);
-                              f_delete_dynamic_string(allocation_status, file_path);
-                              f_delete_fss_objects(allocation_status, list_objects);
-                              f_delete_fss_contents(allocation_status, list_contents);
-                              firewall_delete_data(data);
-                              return status;
-                            } else if (status == f_invalid_parameter) {
-                              f_status allocation_status = f_status_initialize;
-
-                              fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_execute_path()");
-
-                              arguments.array[0].string = 0;
-                              arguments.array[1].string = 0;
-                              arguments.array[2].string = 0;
-
-                              arguments.array[0].used = 0;
-                              arguments.array[1].used = 0;
-                              arguments.array[2].used = 0;
-
-                              f_delete_dynamic_string(allocation_status, custom_chain);
-                              f_delete_dynamic_string(allocation_status, chain_argument);
-                              f_delete_dynamic_strings(allocation_status, arguments);
-                              f_delete_fss_objects(allocation_status, extended_objects);
-                              f_delete_fss_contents(allocation_status, extended_contents);
-                              f_delete_dynamic_string(allocation_status, buffer);
-                              f_delete_dynamic_string(allocation_status, file_path);
-                              f_delete_fss_objects(allocation_status, list_objects);
-                              f_delete_fss_contents(allocation_status, list_contents);
-                              firewall_delete_data(data);
-                              return status;
-                            }
-
-                            arguments.array[0].string = 0;
-                            arguments.array[1].string = 0;
-                            arguments.array[2].string = 0;
-
-                            arguments.array[0].used = 0;
-                            arguments.array[1].used = 0;
-                            arguments.array[2].used = 0;
-
-                            f_delete_dynamic_strings(status, arguments);
-
-                            data->chains.array[data->chains.used] = custom_chain;
-                            custom_chain.string = 0;
-                            custom_chain.used = 0;
-                            chain_location = data->chains.used;
-                            data->chains.used++;
-                          }
-
-                          input.start = list_contents.array[buffer_counter].array[0].start;
-                          input.stop  = list_contents.array[buffer_counter].array[0].stop;
-
-                          status = fll_fss_extended_read(&buffer, &input, &extended_objects, &extended_contents);
-
-                          if (status == f_none || status == f_none_on_stop || status == f_none_on_eos) {
-                            status = firewall_perform_commands(extended_objects, extended_contents, f_false, buffer_counter, buffer, *data, &data->chains.array[chain_location]);
-
-                            if (status != f_none) {
-                              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", status);
-                              } else if (status == f_failure) {
-                                // the error message has already been displayed
-                              } else {
-                                fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling firewall_perform_commands()", status);
-                              }
-                            }
-                          }
-
-                          f_delete_dynamic_string(allocation_status, chain_argument);
-                          f_delete_fss_objects(allocation_status, extended_objects);
-                          f_delete_fss_contents(allocation_status, extended_contents);
-                        }
-
-                        buffer_counter++;
-                      } // while
-                    }
-
-                    f_delete_dynamic_string(allocation_status, buffer);
-                    f_delete_dynamic_string(allocation_status, file_path);
-                    f_delete_fss_objects(allocation_status, list_objects);
-                    f_delete_fss_contents(allocation_status, list_contents);
-                    f_delete_fss_objects(allocation_status, extended_objects);
-                    f_delete_fss_contents(allocation_status, extended_contents);
-                  }
+          status = firewall_create_custom_chains(&reserved, &local, data);
 
-                  input.start = data->contents.array[last].array[0].start;
-                  input.stop  = data->contents.array[last].array[0].stop;
-                  error_file  = last;
+          if (status != f_none) {
+            firewall_macro_delete_fss_buffers(status2, local.buffer, local.chain_objects, local.chain_contents)
+            firewall_delete_data(data);
+            return status;
+          }
 
-                  status = fll_fss_extended_read(&data->buffer, &input, &extended_objects, &extended_contents);
+          i = 0;
 
-                  if (status == f_none || status == f_none_on_stop || status == f_none_on_eos) {
-                    status = firewall_perform_commands(extended_objects, extended_contents, f_true, 0, data->buffer, *data, f_null);
+          local.is_global = f_true;
+          local.is_stop = f_false;
+          local.is_lock = f_false;
 
-                    if (status != f_none) {
-                      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", status);
-                      } else if (status == f_failure) {
-                        // the error message has already been displayed
-                      } else {
-                        fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling firewall_perform_commands()", status);
-                      }
+          while (i < local.chain_contents.used) {
+            input.start = local.chain_contents.array[i].array[0].start;
+            input.stop = local.chain_contents.array[i].array[0].stop;
 
-                      f_delete_fss_objects(allocation_status, extended_objects);
-                      f_delete_fss_contents(allocation_status, extended_contents);
+            local.is_main = reserved.has_main && i == reserved.main_at ? f_true : f_false;
+            local.chain = i;
 
-                      firewall_delete_data(data);
-                      return status;
-                    }
-                  }
-                }
-              }
-            }
-          }
+            status = firewall_process_rules(&input, &local, data);
 
-          if (status != f_none && status != f_none_on_eos && status != f_none_on_stop && status != fl_fss_found_object_no_content) {
-            if (status == f_invalid_parameter) {
-              fl_print_color_code(f_standard_error, data->context.error);
-              fprintf(f_standard_error, "INTERNAL ERROR: Invalid parameter when calling fll_fss_extended_read() for the file '");
-              f_print_partial_dynamic_string(f_standard_error, data->buffer, data->contents.array[error_file].array[0]);
-              fprintf(f_standard_error, "'");
-              fl_print_color_code(f_standard_error, data->context.reset);
-              fprintf(f_standard_error, "\n");
-            } else if (status == f_no_data_on_eos || status == f_no_data || status == f_no_data_on_stop) {
-              if (error_file == first || error_file == last || error_file == stop || error_file == lock) {
-                fl_print_color_code(f_standard_error, data->context.error);
-                fprintf(f_standard_error, "ERROR: No relevant data was found within the file '");
-                f_print_partial_dynamic_string(f_standard_error, data->buffer, data->contents.array[error_file].array[0]);
-                fprintf(f_standard_error, "'");
-                fl_print_color_code(f_standard_error, data->context.reset);
-                fprintf(f_standard_error, "\n");
-              }
-            } 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", status);
-            } else if (status == f_failure) {
-              // the error message has already been displayed
-            } else {
-              fl_print_color_code(f_standard_error, data->context.error);
-              fprintf(f_standard_error, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_fss_extended_read() for the file '", status);
-              f_print_partial_dynamic_string(f_standard_error, data->buffer, data->contents.array[error_file].array[0]);
-              fprintf(f_standard_error, "'");
-              fl_print_color_code(f_standard_error, data->context.reset);
-              fprintf(f_standard_error, "\n");
+            if (status != f_none || command == firewall_parameter_command_stop) {
+              firewall_delete_local_data(&local);
+              firewall_delete_data(data);
+              return status;
             }
-          }
-
-          f_delete_fss_objects(allocation_status, extended_objects);
-          f_delete_fss_contents(allocation_status, extended_contents);
-        } else {
-          const f_autochar *string = f_null;
-
-          if (!found_first) {
-            string = firewall_group_first;
-          } else if (!found_last) {
-            string = firewall_group_last;
-          } else if (!found_stop) {
-            string = firewall_group_stop;
-          } else if (!found_lock) {
-            string = firewall_group_lock;
-          }
 
-          fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: The required basic list '%s' was not found inside of the file '%s'", string, network_path firewall_file_default);
+            i++;
+          } // while
         }
 
         // cleanup
-        f_delete_fss_contents(allocation_status, data->contents);
-        f_delete_fss_objects(allocation_status, data->objects);
-        f_delete_dynamic_string(allocation_status, data->buffer);
+        firewall_delete_local_data(&local);
       } else {
         fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: You did not pass a command");
         status = f_invalid_parameter;
@@ -1444,11 +681,7 @@ extern "C"{
       i++;
     } // while
 
-    f_delete_fss_contents(status, data->contents);
-    f_delete_fss_objects(status, data->objects);
-    f_delete_string_lengths(status, data->custom);
     f_delete_dynamic_strings(status, data->chains);
-    f_delete_dynamic_string(status, data->buffer);
     f_delete_string_lengths(status, data->remaining);
     f_delete_dynamic_strings(status, data->devices);
 
index 7bea9dff1132d679ed38f129bc9ed068568fce36..a8a6a44e0f66aeddb5640a13dfbbc97c345fe426 100644 (file)
@@ -18,6 +18,7 @@
 
 // fll-0 includes
 #include <level_0/types.h>
+#include <level_0/types_array.h>
 #include <level_0/strings.h>
 #include <level_0/file.h>
 #include <level_0/console.h>
@@ -56,13 +57,17 @@ extern "C"{
 #ifndef _di_firewall_paths_
   #define network_path          "/etc/network/" // TODO: this should be moved to a network project library, possibly the Paths project in fot the network project
   #define network_devices       "/sys/class/net/" // TODO: this should also be moved to a network project library
-  #define firewall_file_default "default-firewall"
+  #define firewall_file_first   "firewall-first"
+  #define firewall_file_last    "firewall-last"
+  #define firewall_file_other   "firewall-other"
   #define firewall_file_suffix  "-firewall"
   #define firewall_program_name "iptables"
 
   #define network_path_length          13
   #define network_devices_length       15
-  #define firewall_file_default_length 16
+  #define firewall_file_first_length   14
+  #define firewall_file_last_length    13
+  #define firewall_file_other_length   14
   #define firewall_file_suffix_length  9
   #define firewall_program_name_length 8
 #endif // _di_firewall_paths_
@@ -72,14 +77,10 @@ extern "C"{
 #endif // _di_firewall_default_allocation_step_
 
 #ifndef _di_firewall_defines_
-  #define firewall_group_first "first"
-  #define firewall_group_last "last"
   #define firewall_group_stop "stop"
   #define firewall_group_lock "lock"
   #define firewall_group_main "main"
 
-  #define firewall_group_first_length 5
-  #define firewall_group_last_length  4
   #define firewall_group_stop_length  4
   #define firewall_group_lock_length  4
   #define firewall_group_main_length  4
@@ -176,10 +177,12 @@ extern "C"{
   #define firewall_device      "device"
   #define firewall_device_all  "all"
   #define firewall_device_this "this"
+  #define firewall_device_loop "lo"
 
   #define firewall_device_length      6
   #define firewall_device_all_length  3
   #define firewall_device_this_length 4
+  #define firewall_device_loop_length 2
 
   #define firewall_device_input_command  "-i"
   #define firewall_device_output_command "-o"
@@ -188,8 +191,11 @@ extern "C"{
   #define firewall_device_output_command_length 2
 
   #define firewall_chain_create_command  "-N"
+  #define firewall_chain_unchain_command  "-X"
 
   #define firewall_chain_create_command_length 2
+  #define firewall_chain_unchain_command_length 2
+
 
   enum {
     firewall_parameter_help,
@@ -233,12 +239,7 @@ extern "C"{
   typedef struct {
     f_console_parameter parameters[firewall_total_parameters];
 
-    f_dynamic_string  buffer;
-    f_fss_objects     objects;
-    f_fss_contents    contents;
-    f_string_lengths  custom;
     f_dynamic_strings chains;
-    f_file_position   file_position;
     f_string_lengths  remaining;
     f_dynamic_strings devices;
 
@@ -248,12 +249,7 @@ extern "C"{
   #define firewall_data_initialize \
     { \
       f_console_parameter_initialize_firewall, \
-      f_dynamic_string_initialize, \
-      f_fss_objects_initialize, \
-      f_fss_contents_initialize, \
-      f_string_lengths_initialize, \
       f_dynamic_strings_initialize, \
-      f_file_position_initialize, \
       f_string_lengths_initialize, \
       f_dynamic_strings_initialize, \
       fll_color_context_initialize, \
index b846bde06cbac5d91042672d8d2142e37682dde0..50bc90a63bd30b1d367d1a0deced9945333fb851 100644 (file)
@@ -2,36 +2,37 @@
  * Private source file for firewall.c.
  */
 #include <level_3/firewall.h>
+#include "private-firewall.h"
 
-#ifndef _di_firewall_main_
-  f_return_status firewall_perform_commands(const f_fss_objects objects, const f_fss_contents contents, const f_bool is_global, const f_string_length this_device, const f_dynamic_string buffer, const firewall_data data, const f_dynamic_string *custom_chain) {
-    f_status status            = f_status_initialize;
+#ifndef _di_firewall_perform_commands_
+  f_return_status firewall_perform_commands(const firewall_local_data local, const firewall_data data) {
+    f_status status = f_status_initialize;
     f_status allocation_status = f_status_initialize;
 
-    f_string_length   counter   = f_string_length_initialize;
-    f_dynamic_string  argument  = f_dynamic_string_initialize;
+    f_string_length i = f_string_length_initialize;
+    f_dynamic_string argument = f_dynamic_string_initialize;
     f_dynamic_strings arguments = f_dynamic_strings_initialize;
 
-    f_s_int          results    = 0;
-    f_string_length  length     = f_string_length_initialize;
-    f_bool           invalid    = f_false;
-    f_bool           is_ip_list = f_false;
-    f_dynamic_string ip_list    = f_dynamic_string_initialize;
+    f_s_int results = 0;
+    f_string_length length = f_string_length_initialize;
+    f_bool invalid = f_false;
+    f_bool is_ip_list = f_false;
+    f_dynamic_string ip_list = f_dynamic_string_initialize;
 
     // iptables command arguments
-    f_bool direction_input   = f_true;
-    f_bool direction_output  = f_false;
-    f_bool device_all        = f_false;
+    f_bool direction_input = f_true;
+    f_bool direction_output = f_false;
+    f_bool device_all = f_false;
     f_bool ip_list_direction = f_false; // false = source, true = destination
 
-    f_string_length  direction = firewall_direction_none_id;
-    f_dynamic_string device    = f_dynamic_string_initialize;
-    f_string_length  action    = firewall_action_append_id;
+    f_string_length direction = firewall_direction_none_id;
+    f_dynamic_string device = f_dynamic_string_initialize;
+    f_string_length action = firewall_action_append_id;
 
-    if (is_global) {
+    if (local.is_global) {
       device_all = f_true;
     } else {
-      f_resize_dynamic_string(status, device, data.devices.array[this_device].used);
+      f_resize_dynamic_string(status, device, data.devices.array[local.device].used);
 
       if (f_macro_test_for_allocation_errors(status)) {
         f_delete_dynamic_string(allocation_status, device);
         return status;
       }
 
-      strncat(device.string, data.devices.array[this_device].string, data.devices.array[this_device].used);
-      device.used = data.devices.array[this_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;
     }
 
-    for (; counter < objects.used; counter++) {
-      length  = (objects.array[counter].stop - objects.array[counter].start) + 1;
+    for (; i < local.rule_objects.used; i++) {
+      length  = (local.rule_objects.array[i].stop - local.rule_objects.array[i].start) + 1;
       invalid = f_false;
 
       is_ip_list        = f_false;
 
       f_delete_dynamic_string(allocation_status, ip_list);
 
-      if (length >= firewall_direction_length && fl_compare_strings(buffer.string + objects.array[counter].start, (f_string) firewall_direction, length, firewall_direction_length) == f_equal_to) {
-        length = (contents.array[counter].array[0].stop - contents.array[counter].array[0].start) + 1;
+      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;
 
-        if (contents.array[counter].used <= 0 || contents.array[counter].used > 1) {
+        if (local.rule_contents.array[i].used <= 0 || local.rule_contents.array[i].used > 1) {
           invalid = f_true;
         } else {
-          if (length < firewall_direction_input_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_direction_input, length, firewall_direction_input_length) == f_not_equal_to) {
-            if (length < firewall_direction_output_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_direction_output, length, firewall_direction_output_length) == f_not_equal_to) {
-              if (length < firewall_direction_forward_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_direction_forward, length, firewall_direction_forward_length) == f_not_equal_to) {
-                if (length < firewall_direction_postrouting_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_direction_postrouting, length, firewall_direction_postrouting_length) == f_not_equal_to) {
-                  if (length < firewall_direction_prerouting_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_direction_prerouting, length, firewall_direction_prerouting_length) == f_not_equal_to) {
-                    if (length < firewall_direction_none_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_direction_none, length, firewall_direction_none_length) == f_not_equal_to) {
-                      if (length < firewall_direction_forward_input_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_direction_forward_input, length, firewall_direction_forward_input_length) == f_not_equal_to) {
-                        if (length < firewall_direction_forward_output_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_direction_forward_output, length, firewall_direction_forward_output_length) == f_not_equal_to) {
-                          if (length < firewall_direction_postrouting_input_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_direction_postrouting_input, length, firewall_direction_postrouting_input_length) == f_not_equal_to) {
-                            if (length < firewall_direction_postrouting_output_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_direction_postrouting_output, length, firewall_direction_postrouting_output_length) == f_not_equal_to) {
-                              if (length < firewall_direction_prerouting_input_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_direction_prerouting_input, length, firewall_direction_prerouting_input_length) == f_not_equal_to) {
-                                if (length < firewall_direction_prerouting_output_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_direction_prerouting_output, length, firewall_direction_prerouting_output_length) == f_not_equal_to) {
+          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_not_equal_to) {
+            if (length < firewall_direction_output_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_direction_output, length, firewall_direction_output_length) == f_not_equal_to) {
+              if (length < firewall_direction_forward_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_direction_forward, length, firewall_direction_forward_length) == f_not_equal_to) {
+                if (length < firewall_direction_postrouting_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_direction_postrouting, length, firewall_direction_postrouting_length) == f_not_equal_to) {
+                  if (length < firewall_direction_prerouting_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_direction_prerouting, length, firewall_direction_prerouting_length) == f_not_equal_to) {
+                    if (length < firewall_direction_none_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_direction_none, length, firewall_direction_none_length) == f_not_equal_to) {
+                      if (length < firewall_direction_forward_input_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_direction_forward_input, length, firewall_direction_forward_input_length) == f_not_equal_to) {
+                        if (length < firewall_direction_forward_output_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_direction_forward_output, length, firewall_direction_forward_output_length) == f_not_equal_to) {
+                          if (length < firewall_direction_postrouting_input_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_direction_postrouting_input, length, firewall_direction_postrouting_input_length) == f_not_equal_to) {
+                            if (length < firewall_direction_postrouting_output_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_direction_postrouting_output, length, firewall_direction_postrouting_output_length) == f_not_equal_to) {
+                              if (length < firewall_direction_prerouting_input_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_direction_prerouting_input, length, firewall_direction_prerouting_input_length) == f_not_equal_to) {
+                                if (length < firewall_direction_prerouting_output_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_direction_prerouting_output, length, firewall_direction_prerouting_output_length) == f_not_equal_to) {
                                   invalid = f_true;
                                 } else {
                                   direction_input  = f_false;
         }
 
         if (!invalid) continue;
-      } else if (length >= firewall_device_length && fl_compare_strings(buffer.string + objects.array[counter].start, (f_string) firewall_device, length, firewall_device_length) == f_equal_to) {
-        length = (contents.array[counter].array[0].stop - contents.array[counter].array[0].start) + 1;
+      } 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;
 
-        if (contents.array[counter].used <= 0 || contents.array[counter].used > 1) {
+        if (local.rule_contents.array[i].used <= 0 || local.rule_contents.array[i].used > 1) {
           invalid = f_true;
-        } else if (length >= firewall_device_all_length && fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_device_all, length, firewall_device_all_length) == f_equal_to) {
+        } 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(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_device_this, length, firewall_device_this_length) == f_equal_to) {
+        } 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);
-          f_resize_dynamic_string(status, device, data.devices.array[this_device].used);
+          f_resize_dynamic_string(status, device, data.devices.array[local.device].used);
 
           if (f_macro_test_for_allocation_errors(status)) break;
 
-          strncat(device.string, data.devices.array[this_device].string, data.devices.array[this_device].used);
-          device.used = data.devices.array[this_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;
           device_all  = f_false;
           continue;
         }
 
           if (f_macro_test_for_allocation_errors(status)) break;
 
-          strncat(device.string, buffer.string + contents.array[counter].array[0].start, length);
+          strncat(device.string, local.buffer.string + local.rule_contents.array[i].array[0].start, length);
           device.used  = length;
           device_all  = f_false;
           continue;
         }
-      } else if (length >= firewall_action_length && fl_compare_strings(buffer.string + objects.array[counter].start, (f_string) firewall_action, length, firewall_action_length) == f_equal_to) {
-        length = (contents.array[counter].array[0].stop - contents.array[counter].array[0].start) + 1;
+      } 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;
 
-        if (contents.array[counter].used <= 0 || contents.array[counter].used > 1) {
+        if (local.rule_contents.array[i].used <= 0 || local.rule_contents.array[i].used > 1) {
           invalid = f_true;
-        } else if (length < firewall_action_append_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_action_append, length, firewall_action_append_length) == f_not_equal_to) {
-          if (length < firewall_action_insert_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_action_insert, length, firewall_action_insert_length) == f_not_equal_to) {
-            if (length < firewall_action_policy_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_action_policy, length, firewall_action_policy_length) == f_not_equal_to) {
-              if (length < firewall_action_none_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_action_none, length, firewall_action_none_length) == f_not_equal_to) {
+        } 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_not_equal_to) {
+          if (length < firewall_action_insert_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_action_insert, length, firewall_action_insert_length) == f_not_equal_to) {
+            if (length < firewall_action_policy_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_action_policy, length, firewall_action_policy_length) == f_not_equal_to) {
+              if (length < firewall_action_none_length || fl_compare_strings(local.buffer.string + local.rule_contents.array[i].array[0].start, (f_string) firewall_action_none, length, firewall_action_none_length) == f_not_equal_to) {
                 invalid = f_true;
               } else {
                 action = firewall_action_none_id;
         }
 
         if (!invalid) continue;
-      } else if (length >= firewall_ip_list_length && fl_compare_strings(buffer.string + objects.array[counter].start, (f_string) firewall_ip_list, length, firewall_ip_list_length) == f_equal_to) {
-        length = (contents.array[counter].array[0].stop - contents.array[counter].array[0].start) + 1;
+      } 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;
         is_ip_list = f_true;
 
-        if (length >= firewall_ip_list_source_length && fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_ip_list_source, length, firewall_ip_list_source_length) == f_equal_to) {
+        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(buffer.string + contents.array[counter].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 {
           invalid = f_true;
         }
-      } else if (length < firewall_rule_length || fl_compare_strings(buffer.string + objects.array[counter].start, (f_string) firewall_rule, length, firewall_rule_length) == f_not_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) counter);
-          f_print_string(f_standard_warning, buffer.string + objects.array[counter].start, length);
+          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, 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) counter);
+          fprintf(f_standard_warning, "WARNING: At line %u, the object is missing", (unsigned int) i);
         }
 
         fprintf(f_standard_warning, "\n");
       }
 
       if (invalid) {
-        length = (objects.array[counter].stop - objects.array[counter].start) + 1;
+        length = (local.rule_objects.array[i].stop - local.rule_objects.array[i].start) + 1;
 
         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) counter);
-          f_print_string(f_standard_warning, buffer.string + objects.array[counter].start, length);
+          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, length);
           fprintf(f_standard_warning, "' has invalid content '");
-          f_print_string(f_standard_warning, buffer.string + contents.array[counter].array[0].start, contents.array[counter].array[0].stop - contents.array[counter].array[0].start + 1);
+          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);
           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) counter);
+          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);
         }
 
         continue;
       }
 
-
       // first add the program name
       f_delete_dynamic_strings(status, arguments);
       f_resize_dynamic_strings(status, arguments, arguments.used + 1);
         argument.used   = 0;
       }
 
+
       if (action != firewall_action_none_id) {
-        if (custom_chain != f_null) {
-          f_resize_dynamic_string(status, argument, custom_chain->used);
+        if (!(local.is_main || local.is_stop || local.is_lock)) {
+          f_resize_dynamic_string(status, argument, data.chains.array[local.chain_ids.array[local.chain]].used);
 
           if (f_macro_test_for_allocation_errors(status)) break;
 
-          strncat(argument.string, custom_chain->string, custom_chain->used);
-          argument.used = custom_chain->used;
+          strncat(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].used;
+
         } else if (direction == firewall_direction_forward_id) {
           f_resize_dynamic_string(status, argument, firewall_direction_forward_command_length);
 
       }
 
       if (device.used > 0) {
-        if (length < firewall_device_all_length || fl_compare_strings(buffer.string + contents.array[counter].array[0].start, (f_string) firewall_device_all, length, firewall_device_all_length) == f_not_equal_to) {
+        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_input) {
             f_resize_dynamic_string(status, argument, firewall_device_input_command_length);
             if (f_macro_test_for_allocation_errors(status)) break;
       }
 
       // last up is the "rule"
-      if ((!is_ip_list && contents.array[counter].used > 0) || (is_ip_list && contents.array[counter].used > 1)) {
+      if ((!is_ip_list && local.rule_contents.array[i].used > 0) || (is_ip_list && local.rule_contents.array[i].used > 1)) {
         f_string_length subcounter = f_string_length_initialize;
 
         if (is_ip_list) {
           // skip past the direction
           subcounter++;
 
-          length = (contents.array[counter].array[subcounter].stop - contents.array[counter].array[subcounter].start) + 1;
+          length = (local.rule_contents.array[i].array[subcounter].stop - local.rule_contents.array[i].array[subcounter].start) + 1;
 
           f_resize_dynamic_string(status, ip_list, length);
 
           if (f_macro_test_for_allocation_errors(status)) {
-            subcounter = contents.array[counter].used;
+            subcounter = local.rule_contents.array[i].used;
           } else {
-            strncat(ip_list.string, buffer.string + contents.array[counter].array[subcounter].start, length);
+            strncat(ip_list.string, local.buffer.string + local.rule_contents.array[i].array[subcounter].start, length);
             ip_list.used = length;
 
             subcounter++;
           }
         }
 
-        for (; subcounter < contents.array[counter].used; subcounter++) {
-          length = (contents.array[counter].array[subcounter].stop - contents.array[counter].array[subcounter].start) + 1;
+        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;
 
           f_resize_dynamic_string(status, argument, length);
 
           if (f_macro_test_for_allocation_errors(status)) break;
 
-          strncat(argument.string, buffer.string + contents.array[counter].array[subcounter].start, length);
+          strncat(argument.string, local.buffer.string + local.rule_contents.array[i].array[subcounter].start, length);
           argument.used = length;
 
           if (length > 0) {
           }
         }
       } else {
-        length = (objects.array[counter].stop - objects.array[counter].start) + 1;
+        length = (local.rule_objects.array[i].stop - local.rule_objects.array[i].start) + 1;
 
         fl_print_color_code(f_standard_warning, data.context.warning);
-        fprintf(f_standard_warning, "WARNING: At line %u, the object '", (unsigned int) counter);
-        f_print_string(f_standard_warning, buffer.string + objects.array[counter].start, objects.array[counter].stop - objects.array[counter].start + 1);
+        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, "' has no content");
         fl_print_color_code(f_standard_warning, data.context.reset);
         fprintf(f_standard_warning, "\n");
 
     return status;
   }
-#endif // _di_firewall_main_
+#endif // _di_firewall_perform_commands_
+
+#ifndef _di_firewall_create_custom_chains_
+  f_return_status firewall_create_custom_chains(firewall_reserved_chains *reserved, firewall_local_data *local, firewall_data *data) {
+    f_status status = f_none;
+    f_status status2 = f_none;
+
+    f_bool new_chain = f_false;
+    f_s_int results = 0;
+
+    f_array_length i = f_array_length_initialize;
+    f_array_length j = f_array_length_initialize;
+
+    f_string_length length = f_string_length_initialize;
+    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_resize_array_lengths(status, local->chain_ids, local->chain_objects.used);
+
+    local->chain_ids.used = 0;
+
+    if (f_macro_test_for_allocation_errors(status)) {
+      return status;
+    }
+
+    f_resize_dynamic_strings(status, arguments, 3);
+
+    if (f_macro_test_for_allocation_errors(status)) {
+      return status;
+    }
+
+    f_resize_dynamic_string(status, arguments.array[0], firewall_program_name_length);
+
+    if (f_macro_test_for_allocation_errors(status)) {
+      f_delete_dynamic_strings(status2, arguments);
+
+      return status;
+    }
+
+    f_resize_dynamic_string(status, arguments.array[1], firewall_chain_create_command_length);
+
+    if (f_macro_test_for_allocation_errors(status)) {
+      f_delete_dynamic_strings(status2, arguments);
+
+      return status;
+    }
+
+    reserved->has_lock = f_false;
+    reserved->has_stop = f_false;
+    reserved->has_main = f_false;
+
+    strncat(arguments.array[0].string, firewall_program_name, firewall_program_name_length);
+    strncat(arguments.array[1].string, firewall_chain_create_command, firewall_chain_create_command_length);
+    arguments.array[0].used = firewall_program_name_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) {
+        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) {
+        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) {
+        new_chain = f_false;
+        reserved->has_lock = f_true;
+        reserved->lock_at = i;
+      }
+
+      // nullify the static string
+      static_string.string = f_null;
+      static_string.used = 0;
+
+      if (new_chain) {
+        while (j < data->chains.used) {
+          location.start = 0;
+          location.stop = data->chains.array[j].used - 1;
+
+          if (fl_compare_partial_dynamic_strings(local->buffer, data->chains.array[j], local->chain_objects.array[i], location) == f_equal_to) {
+            new_chain = f_false;
+            local->chain_ids.array[i] = j;
+
+            break;
+          }
+
+          j++;
+        } // while
+      }
+
+      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, data->chains.used + firewall_default_allocation_step);
+
+          if (f_macro_test_for_allocation_errors(status)) {
+            f_delete_dynamic_strings(status2, arguments);
+
+            return status;
+          }
+        }
+
+        if (length >= arguments.array[2].size) {
+          f_resize_dynamic_string(status, arguments.array[2], length + firewall_default_allocation_step);
+
+          if (f_macro_test_for_allocation_errors(status)) {
+            f_delete_dynamic_strings(status2, arguments);
+
+            return status;
+          }
+        }
+
+        f_resize_dynamic_string(status, data->chains.array[data->chains.used], length);
+
+        if (f_macro_test_for_allocation_errors(status)) {
+          f_delete_dynamic_strings(status2, arguments);
+
+          return status;
+        }
+
+        data->chains.array[data->chains.used].used = 0;
+        local->chain_ids.array[i] = data->chains.used;
+        arguments.array[2].used = 0;
+        j = local->chain_objects.array[i].start;
+
+        while (j <= local->chain_objects.array[i].stop) {
+          if (local->buffer.string[j] == f_fss_delimit_placeholder) {
+            j++;
+            continue;
+          }
+
+          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++;
+          j++;
+        } // while
+
+        f_resize_dynamic_string(status, data->chains.array[data->chains.used], data->chains.array[data->chains.used].used);
+
+        if (f_macro_test_for_allocation_errors(status)) {
+          f_delete_dynamic_strings(status2, arguments);
+
+          return status;
+        }
+
+        status = fll_execute_program((f_string) firewall_program_name, arguments, &results);
+
+        if (status == f_failure) {
+          fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Failed to perform requested %s operation:", firewall_program_name);
+          fprintf(f_standard_error, "  ");
+
+          f_string_length i = f_string_length_initialize;
+
+          fl_print_color_code(f_standard_error, data->context.error);
+
+          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");
+
+          f_delete_dynamic_strings(status2, arguments);
+
+          return status;
+        } 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 fl_execute_path()");
+          f_delete_dynamic_strings(status2, arguments);
+
+          return status;
+        }
+
+        data->chains.used++;
+      }
+
+      i++;
+    } // while
+
+    return status;
+  }
+#endif // _di_firewall_create_custom_chains_
+
+#ifndef _di_firewall_process_rules_
+  f_return_status firewall_buffer_rules(const f_string filename, const f_bool optional, firewall_local_data *local, firewall_data *data) {
+    f_file file = f_file_initialize;
+    f_status status = f_none;
+
+    status = f_file_open(&file, filename);
+
+    if (optional && status != f_none) {
+      if (status == f_invalid_parameter) {
+        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 && status != f_file_open_error && status != f_file_descriptor_error) {
+        fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling f_file_open().", status);
+      }
+
+      return status;
+    } else if (status != f_none) {
+      if (status == f_invalid_parameter) {
+        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) {
+        fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Unable to find the file '%s'.", filename);
+      } 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'.", filename);
+      } 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'.", filename);
+      } else {
+        fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling f_file_open().", status);
+      }
+
+      return status;
+    }
+
+    f_macro_file_reset_position(local->file_position, file)
+    status = fl_file_read(file, local->file_position, &local->buffer);
+
+    f_file_close(&file);
+
+    if (status != f_none && status != f_none_on_eof) {
+      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'.", filename);
+      } 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.", filename);
+      } 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'.", filename);
+      } 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'.", filename);
+      } 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 fl_file_read().", status);
+      }
+
+      return status;
+    } else {
+      f_string_location input = f_string_location_initialize;
+
+      input.stop = local->buffer.used - 1;
+
+      status = fll_fss_basic_list_read(&local->buffer, &input, &local->chain_objects, &local->chain_contents);
+    }
+
+    if (status != f_none && status != f_none_on_eos && status != f_none_on_stop && status != fl_fss_found_object_no_content) {
+      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_list_read() for the file '%s'.", filename);
+      } 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, "ERROR: No relevant data was found within the file '%s'.", filename);
+      } 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_list_read() for the file '%s'.", status, filename);
+      }
+
+      return status;
+    }
+
+    return status;
+  }
+#endif // _di_firewall_buffer_rules_
+
+#ifndef _di_firewall_process_rules_
+  f_return_status firewall_process_rules(f_string_location *input, firewall_local_data *local, firewall_data *data) {
+    f_status status  = f_none;
+    f_status status2 = f_none;
+
+    status = fll_fss_extended_read(&local->buffer, input, &local->rule_objects, &local->rule_contents);
+
+
+    if (status == f_none || status == f_none_on_stop || status == f_none_on_eos) {
+      status = firewall_perform_commands(*local, *data);
+
+      if (status != f_none) {
+        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.", status);
+        } else if (status == f_failure) {
+          // the error message has already been displayed.
+        } else {
+          fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling firewall_perform_commands().", status);
+        }
+
+        f_delete_fss_objects(status2, local->rule_objects);
+        f_delete_fss_contents(status2, local->rule_contents);
+        return status;
+      }
+    }
+
+    f_delete_fss_objects(status2, local->rule_objects);
+    f_delete_fss_contents(status2, local->rule_contents);
+    return status;
+  }
+#endif // _di_firewall_process_rules_
+
+#ifndef _di_firewall_delete_local_data_
+  f_return_status firewall_delete_local_data(firewall_local_data *local) {
+    f_status status = f_status_initialize;
+
+    local->is_global = f_true;
+    local->is_main = f_false;
+    local->is_stop = f_false;
+    local->is_lock = f_false;
+
+    local->file_position.buffer_start = 0;
+    local->file_position.file_start = 0;
+    local->file_position.total_elements = 0;
+
+    local->device = 0;
+    local->chain = 0;
+
+    f_delete_dynamic_string(status, local->buffer);
+    f_delete_array_lengths(status, local->chain_ids);
+    f_delete_fss_objects(status, local->chain_objects);
+    f_delete_fss_contents(status, local->chain_contents);
+    f_delete_fss_objects(status, local->rule_objects);
+    f_delete_fss_contents(status, local->rule_contents);
+
+    return f_none;
+  }
+#endif // _di_firewall_delete_local_data_
index cd37595c6c1afa0c9e28274060101628200c6316..66b6883fc59af6ba31a8b7c627f2383e0b7cfcae 100644 (file)
@@ -2,6 +2,102 @@
  * Private include file for firewall.c.
  */
 
-#ifndef _di_firewall_main_
-  f_return_status firewall_perform_commands(const f_fss_objects objects, const f_fss_contents contents, const f_bool is_global, const f_string_length this_device, const f_dynamic_string buffer, const firewall_data data, const f_dynamic_string *custom_chain) __attribute__((visibility("internal")));
-#endif // _di_firewall_main_
+#ifndef _PRIVATE_firewall_h
+#define _PRIVATE_firewall_h
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#ifndef _di_firewall_local_data_
+  typedef struct {
+    f_bool is_global;
+    f_bool is_main;
+    f_bool is_stop;
+    f_bool is_lock;
+
+    f_file_position file_position;
+
+    f_array_length device;
+
+    f_dynamic_string buffer;
+    f_array_length   chain;
+    f_array_lengths  chain_ids;
+    f_fss_objects    chain_objects;
+    f_fss_contents   chain_contents;
+    f_fss_objects    rule_objects;
+    f_fss_contents   rule_contents;
+  } firewall_local_data;
+
+  #define firewall_local_data_initialize \
+    { \
+      f_true, \
+      f_false, \
+      f_false, \
+      f_false, \
+      f_file_position_initialize, \
+      0, \
+      f_dynamic_string_initialize, \
+      0, \
+      f_array_lengths_initialize, \
+      f_fss_objects_initialize, \
+      f_fss_contents_initialize, \
+      f_fss_objects_initialize, \
+      f_fss_contents_initialize, \
+    }
+#endif // _di_firewall_local_data_
+
+#ifndef _di_firewall_reserved_chains_
+  typedef struct {
+    f_bool has_main;
+    f_bool has_stop;
+    f_bool has_lock;
+
+    f_array_length main_at;
+    f_array_length stop_at;
+    f_array_length lock_at;
+  } firewall_reserved_chains;
+
+  #define firewall_reserved_chains_initialize \
+    { \
+      f_false, \
+      f_false, \
+      f_false, \
+      0, \
+      0, \
+      0, \
+    }
+#endif // _di_firewall_reserved_chains_
+
+#ifndef _di_firewall_macro_private_
+  #define firewall_macro_delete_fss_buffers(status, buffer, objects, contents) \
+    f_delete_dynamic_string(status, buffer); \
+    f_delete_fss_objects(status, objects); \
+    f_delete_fss_contents(status, contents);
+#endif // _di_firewall_macro_private_
+
+#ifndef _di_firewall_perform_commands_
+  f_return_status firewall_perform_commands(const firewall_local_data local, const firewall_data data) __attribute__((visibility("internal")));
+#endif // _di_firewall_perform_commands_
+
+#ifndef _di_firewall_create_custom_chains_
+  f_return_status firewall_create_custom_chains(firewall_reserved_chains *reserved, firewall_local_data *local, firewall_data *data) __attribute__((visibility("internal")));
+#endif // _di_firewall_create_custom_chains_
+
+#ifndef _di_firewall_buffer_rules_
+  f_return_status firewall_buffer_rules(const f_string filename, const f_bool optional, firewall_local_data *local, firewall_data *data) __attribute__((visibility("internal")));
+#endif // _di_firewall_buffer_rules_
+
+#ifndef _di_firewall_process_rules_
+  f_return_status firewall_process_rules(f_string_location *input, firewall_local_data *local, firewall_data *data) __attribute__((visibility("internal")));
+#endif // _di_firewall_process_rules_
+
+#ifndef _di_firewall_delete_local_data_
+  f_return_status firewall_delete_local_data(firewall_local_data *local) __attribute__((visibility("internal")));
+#endif // _di_firewall_delete_local_data_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_firewall_h