]> Kevux Git Server - fll/commitdiff
Update: add support for custom user chains
authorKevin Day <kevin@kevux.org>
Sun, 1 Apr 2012 20:54:28 +0000 (15:54 -0500)
committerKevin Day <kevin@kevux.org>
Mon, 2 Apr 2012 18:07:43 +0000 (13:07 -0500)
Users should now be able to add their own custom chains.
Chains can be created by creating a new fss object that is not one of the following: first, last, stop, lock, or main.

level_3/firewall/c/firewall.c
level_3/firewall/c/firewall.h

index b87179222e8ba5503b59d905042017f095fae983..87e723a6f0b9d6026538c303b4fb4dd0294ee620 100644 (file)
@@ -106,7 +106,7 @@ extern "C"{
 #endif // _di_firewall_print_help_
 
 #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) __attribute__((visibility("internal")));
+  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")));
 
   f_return_status firewall_main(const f_s_int argc, const f_string argv[], firewall_data *data) {
     f_status status            = f_status_initialize;
@@ -564,27 +564,34 @@ extern "C"{
               first       = counter;
               found_first = f_true;
             }
-          }
-
-          if (!found_last && length >= firewall_group_last_length) {
+          } else if (!found_last && length >= firewall_group_last_length) {
             if (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;
             }
-          }
-
-          if (!found_stop && length >= firewall_group_stop_length) {
+          } else if (!found_stop && length >= firewall_group_stop_length) {
             if (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;
             }
-          }
-
-          if (!found_lock && length >= firewall_group_lock_length) {
+          } else if (!found_lock && length >= firewall_group_lock_length) {
             if (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 (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;
+              }
+            }
+
+            data->custom.array[data->custom.used] = counter;
+            data->custom.used++;
           }
         }
 
@@ -605,7 +612,7 @@ extern "C"{
             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, 0, data->buffer, *data);
+              status = firewall_perform_commands(extended_objects, extended_contents, f_true, 0, data->buffer, *data, f_null);
 
               if (status != f_none) {
                 if (f_macro_test_for_allocation_errors(status)) {
@@ -634,7 +641,7 @@ extern "C"{
               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, 0, data->buffer, *data);
+                status = firewall_perform_commands(extended_objects, extended_contents, f_true, 0, data->buffer, *data, f_null);
               }
             }
 
@@ -651,7 +658,7 @@ extern "C"{
               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, 0, data->buffer, *data);
+                status = firewall_perform_commands(extended_objects, extended_contents, f_true, 0, data->buffer, *data, f_null);
 
                 if (status != f_none) {
                   if (f_macro_test_for_allocation_errors(status)) {
@@ -671,7 +678,240 @@ extern "C"{
                   f_delete_fss_objects(status, extended_objects);
                   f_delete_fss_contents(status, extended_contents);
 
-                  f_string_length counter = f_string_length_initialize;
+                  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;
+
+                      // 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 = data->objects.array[data->custom.array[counter2]].start;
+                        max_size = data->objects.array[data->custom.array[counter2]].stop - data->objects.array[data->custom.array[counter2]].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);
+                            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;
+                          }
+
+                          custom_chain.string[custom_chain.used] = data->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);
+                            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);
+                              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
+                  }
+
+                  counter = 0;
 
                   for (; counter < data->devices.used; counter++) {
                     f_file           file          = f_file_initialize;
@@ -786,50 +1026,320 @@ extern "C"{
 
                     {
                       f_string_length buffer_counter = f_string_length_initialize;
-                      f_string_length name_length    = f_string_length_initialize;
+                      f_string_length length         = f_string_length_initialize;
 
-                      for (; buffer_counter < list_objects.used; buffer_counter++) {
-                        name_length = list_objects.array[buffer_counter].stop - list_objects.array[buffer_counter].start + 1;
+                      while (buffer_counter < list_objects.used) {
+                        length = list_objects.array[buffer_counter].stop - list_objects.array[buffer_counter].start + 1;
 
-                        if (name_length >= firewall_group_main_length) {
-                          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;
+                        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;
+                          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);
+                          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);
+                          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);
-                                }
+                            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 {
-                              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, "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
+                          // TODO: run a loop here and make sure to only add a chain if it does not already exist (avoids iptables error)
+                          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 fll_fss_extended_read() for the file '%s'", status, file_path.string);
+                                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);
                               }
                             }
-
-                            break;
                           }
 
-                          // TODO: consider supporting "lock" and "stop" rules for individual devices
+                          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);
@@ -847,7 +1357,7 @@ extern "C"{
                   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, 0, data->buffer, *data);
+                    status = firewall_perform_commands(extended_objects, extended_contents, f_true, 0, data->buffer, *data, f_null);
 
                     if (status != f_none) {
                       if (f_macro_test_for_allocation_errors(status)) {
@@ -933,7 +1443,7 @@ extern "C"{
     return status;
   }
 
-    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) {
+  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;
     f_status allocation_status = f_status_initialize;
 
@@ -1228,7 +1738,14 @@ extern "C"{
       }
 
       if (action != firewall_action_none_id) {
-        if (direction == firewall_direction_forward_id) {
+        if (custom_chain != f_null) {
+          f_resize_dynamic_string(status, argument, custom_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;
+        } else if (direction == firewall_direction_forward_id) {
           f_resize_dynamic_string(status, argument, firewall_direction_forward_command_length);
 
           if (f_macro_test_for_allocation_errors(status)) break;
@@ -1639,6 +2156,8 @@ extern "C"{
 
     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 296cd90455fa456c7487e0e3938e60d73ed392ba..7bea9dff1132d679ed38f129bc9ed068568fce36 100644 (file)
@@ -67,6 +67,10 @@ extern "C"{
   #define firewall_program_name_length 8
 #endif // _di_firewall_paths_
 
+#ifndef _di_firewall_default_allocation_step_
+  #define firewall_default_allocation_step f_memory_default_allocation_step
+#endif // _di_firewall_default_allocation_step_
+
 #ifndef _di_firewall_defines_
   #define firewall_group_first "first"
   #define firewall_group_last "last"
@@ -183,6 +187,10 @@ extern "C"{
   #define firewall_device_input_command_length  2
   #define firewall_device_output_command_length 2
 
+  #define firewall_chain_create_command  "-N"
+
+  #define firewall_chain_create_command_length 2
+
   enum {
     firewall_parameter_help,
     firewall_parameter_light,
@@ -228,6 +236,8 @@ extern "C"{
     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;
@@ -241,6 +251,8 @@ extern "C"{
       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, \