From: Kevin Day Date: Sun, 11 Mar 2012 06:14:38 +0000 (-0600) Subject: Add Package: firewall X-Git-Tag: 0.3.0~82 X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=5a5ad3657b29afd6568d1150ae3dfba6f2688f74;p=fll Add Package: firewall This package was missed during the conversion from svn to git. --- diff --git a/level_3/firewall/c/firewall.c b/level_3/firewall/c/firewall.c new file mode 100644 index 0000000..dfd1366 --- /dev/null +++ b/level_3/firewall/c/firewall.c @@ -0,0 +1,1648 @@ +/* FLL - Level 3 + * Project: Firewall + * Version: 0.3.x + * Licenses: lgplv2.1 + * Programmers: Kevin Day + */ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +// version printed may be used by scripts, so this will only print the version number and a newline, no extra information or colors +#ifndef _di_firewall_print_version_ + f_return_status firewall_print_version(const firewall_data data){ + printf("%s\n", firewall_version); + + return f_none; + } +#endif // _firewall_print_version_ + +#ifndef _di_firewall_print_help_ + f_return_status firewall_print_help(const firewall_data data){ + printf("\n"); + fl_print_color(f_standard_output, data.context.title, data.context.reset, " %s", firewall_name_long); + + printf("\n"); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, " Version %s", firewall_version); + + printf("\n\n"); + fl_print_color(f_standard_output, data.context.important, data.context.reset, " Available Options: "); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_help); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_help); + printf(" Print this help message"); + + printf("\n %s", f_console_symbol_short_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_light); + + printf(", %s", f_console_symbol_long_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_light); + printf(" Output using colors that show up better on light backgrounds"); + + printf("\n %s", f_console_symbol_short_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_no_color); + + printf(", %s", f_console_symbol_long_disable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_no_color); + printf(" Do not output in color"); + + printf("\n %s", f_console_symbol_short_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_short_version); + + printf(", %s", f_console_symbol_long_enable); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, f_console_standard_long_version); + printf(" Print only the version number"); + + printf("\n\n"); + fl_print_color(f_standard_output, data.context.important, data.context.reset, " Available Commands: "); + + printf("\n "); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, firewall_command_start); + printf(" Turn on the firewall"); + + printf("\n "); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, firewall_command_stop); + printf(" Turn off the firewall"); + + printf("\n "); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, firewall_command_restart); + printf(" Turn off and then turn on the firewall"); + + printf("\n "); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, firewall_command_lock); + printf(" Prevent all communication"); + + printf("\n "); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, firewall_command_show); + printf(" Show active firewall settings"); + + printf("\n\n"); + fl_print_color(f_standard_output, data.context.important, data.context.reset, " Usage: "); + + printf("\n "); + fl_print_color(f_standard_output, data.context.standout, data.context.reset, firewall_name); + + printf(" "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "["); + + printf(" options "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "]"); + + printf(" "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "["); + + printf(" command "); + fl_print_color(f_standard_output, data.context.notable, data.context.reset, "]"); + + printf("\n\n"); + + return f_none; + } +#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_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; + + 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); + + if (allocation_status == 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; + } + } + + if (status != f_none){ + if (status == f_no_data){ + fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: One of the parameters you passed requires an additional parameter that you did not pass."); + // TODO: there is a way to identify which parameter is incorrect + // to do this, one must look for any "has_additional" and then see if the "additiona" location is set to 0 + // nothing can be 0 as that represents the program name, unless argv[] is improperly created + } 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 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_process_parameters()"); + } 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_process_parameters()", status); + } + + firewall_delete_data(data); + return status; + } + + // execute parameter results + if (data->parameters[firewall_parameter_help].result == f_console_result_found){ + firewall_print_help(*data); + } else if (data->parameters[firewall_parameter_version].result == f_console_result_found){ + firewall_print_version(*data); + } else { + // now determine which command was placed first + f_bool found_command = f_false; + f_u_int command = 0; + + if (data->parameters[firewall_parameter_command_start].result == f_console_result_found){ + command = firewall_parameter_command_start; + found_command = f_true; + } + + if (data->parameters[firewall_parameter_command_stop].result == f_console_result_found){ + if (found_command){ + if (data->parameters[command].additional > data->parameters[firewall_parameter_command_stop].additional){ + command = firewall_parameter_command_stop; + } + } else { + command = firewall_parameter_command_stop; + found_command = f_true; + } + } + + if (data->parameters[firewall_parameter_command_restart].result == f_console_result_found){ + if (found_command){ + if (data->parameters[command].additional > data->parameters[firewall_parameter_command_restart].additional){ + command = firewall_parameter_command_restart; + } + } else { + command = firewall_parameter_command_restart; + found_command = f_true; + } + } + + if (data->parameters[firewall_parameter_command_lock].result == f_console_result_found){ + if (found_command){ + if (data->parameters[command].additional > data->parameters[firewall_parameter_command_lock].additional){ + command = firewall_parameter_command_lock; + } + } else { + command = firewall_parameter_command_lock; + found_command = f_true; + } + } + + if (data->parameters[firewall_parameter_command_show].result == f_console_result_found){ + if (found_command){ + if (data->parameters[command].additional > data->parameters[firewall_parameter_command_show].additional){ + command = firewall_parameter_command_show; + } + } else { + command = firewall_parameter_command_show; + found_command = f_true; + } + } + + 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; + } + } + + 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) + f_bool show_nat = f_true; + f_bool show_mangle = f_true; + f_bool show_ports = f_true; + + f_dynamic_strings arguments = f_dynamic_strings_initialize; + f_s_int results = 0; + + if (data->remaining.used > 0){ + show_nat = f_false; + show_mangle = f_false; + show_ports = f_false; + + f_string_length counter = f_string_length_initialize; + + for (; counter < data->remaining.used; counter++){ + if (strncmp("nat", argv[data->remaining.array[counter]], 4) != 0){ + if (strncmp("mangle", argv[data->remaining.array[counter]], 7) != 0){ + if (strncmp("ports", argv[data->remaining.array[counter]], 6) != 0){ + fl_print_color_line(f_standard_warning, data->context.warning, data->context.reset, "WARNING: '%s' is not a valid show option", argv[data->remaining.array[counter]]); + } else { + show_ports = f_true; + } + } else { + show_mangle = f_true; + } + } else { + show_nat = f_true; + } + } // for + } + + f_resize_dynamic_strings(status, arguments, 7); + + 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 (show_nat){ + fl_print_color(f_standard_output, data->context.standout, data->context.reset, "=========================== "); + fl_print_color(f_standard_output, data->context.title, data->context.reset, "NAT"); + fl_print_color_line(f_standard_output, data->context.standout, data->context.reset, " ============================"); + fflush(f_standard_output); + + arguments.used = 7; + + arguments.array[0].string = (f_string) firewall_program_name; + arguments.array[1].string = (f_string) "-x"; + arguments.array[2].string = (f_string) "-v"; + arguments.array[3].string = (f_string) "-t"; + arguments.array[4].string = (f_string) "nat"; + arguments.array[5].string = (f_string) "--numeric"; + arguments.array[6].string = (f_string) "--list"; + + arguments.array[0].used = firewall_program_name_length; + arguments.array[1].used = 2; + arguments.array[2].used = 2; + arguments.array[3].used = 2; + arguments.array[4].used = 3; + arguments.array[5].used = 9; + arguments.array[6].used = 6; + + status = fll_execute_program((f_string) firewall_program_name, arguments, &results); + + fprintf(f_standard_output, "\n"); + fflush(f_standard_output); + } + + if (status != f_failure && show_mangle){ + fl_print_color(f_standard_output, data->context.standout, data->context.reset, "========================== "); + fl_print_color(f_standard_output, data->context.title, data->context.reset, "MANGLE"); + fl_print_color_line(f_standard_output, data->context.standout, data->context.reset, " =========================="); + fflush(f_standard_output); + + arguments.used = 7; + + arguments.array[0].string = (f_string) firewall_program_name; + arguments.array[1].string = (f_string) "-x"; + arguments.array[2].string = (f_string) "-v"; + arguments.array[3].string = (f_string) "-t"; + arguments.array[4].string = (f_string) "mangle"; + arguments.array[5].string = (f_string) "--numeric"; + arguments.array[6].string = (f_string) "--list"; + + arguments.array[0].used = firewall_program_name_length; + arguments.array[1].used = 2; + arguments.array[2].used = 2; + arguments.array[3].used = 2; + arguments.array[4].used = 3; + arguments.array[5].used = 9; + arguments.array[6].used = 6; + + status = fll_execute_program((f_string) firewall_program_name, arguments, &results); + + fprintf(f_standard_output, "\n"); + fflush(f_standard_output); + } + + if (status != f_failure && show_ports){ + fl_print_color(f_standard_output, data->context.standout, data->context.reset, "========================== "); + fl_print_color(f_standard_output, data->context.title, data->context.reset, "PORTS"); + fl_print_color_line(f_standard_output, data->context.standout, data->context.reset, " ==========================="); + fflush(f_standard_output); + + arguments.used = 5; + + arguments.array[0].string = (f_string) firewall_program_name; + arguments.array[1].string = (f_string) "-x"; + arguments.array[2].string = (f_string) "-v"; + arguments.array[3].string = (f_string) "--numeric"; + arguments.array[4].string = (f_string) "--list"; + + arguments.array[0].used = firewall_program_name_length; + arguments.array[1].used = 2; + arguments.array[2].used = 2; + arguments.array[3].used = 9; + arguments.array[4].used = 6; + + status = fll_execute_program((f_string) firewall_program_name, arguments, &results); + + fprintf(f_standard_output, "\n"); + fflush(f_standard_output); + } + + 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"); + } 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"); + } + + arguments.array[0].string = 0; + arguments.array[1].string = 0; + arguments.array[2].string = 0; + arguments.array[3].string = 0; + arguments.array[4].string = 0; + arguments.array[5].string = 0; + arguments.array[6].string = 0; + arguments.array[0].used = 0; + arguments.array[1].used = 0; + arguments.array[2].used = 0; + arguments.array[3].used = 0; + arguments.array[4].used = 0; + arguments.array[5].used = 0; + arguments.array[6].used = 0; + f_delete_dynamic_strings(status, arguments); + + firewall_delete_data(data); + return f_none; + } + + // load all network devices + status = fl_directory_list((f_string) network_devices, &data->devices); + + 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; + } 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_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_data(data); + return status; + } + + // remove "lo" (loopback) from the device listing + { + f_string_length counter = 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]; + + data->devices.used--; + + for (; counter < data->devices.used; counter++){ + data->devices.array[counter] = data->devices.array[counter+1]; + } + + data->devices.array[data->devices.used] = swap_string; + } + } + } + + // 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; + + for (total = data->devices.used; device < total; device++){ + matched = f_false; + + 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 (!matched){ + f_dynamic_string swap_string = data->devices.array[device]; + + data->devices.used--; + + for (i = device; i < data->devices.used; i++){ + data->devices.array[i] = data->devices.array[i+1]; + } + + data->devices.array[data->devices.used] = swap_string; + + total--; + device--; + } + } + } + + // 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; + + for (; counter < data->remaining.used; counter++){ + matched = f_false; + + 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 (!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]]); + } + } + + // cleanup, the 'remaining' parameters are no longer needed + f_delete_string_locations(status, data->remaining); + } + + // 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 && length >= firewall_group_first_length){ + if (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; + } + } + + 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){ + 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){ + 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; + } + } + } + + if (found_first && found_last && found_stop && found_lock){ + f_string_length error_file = f_string_length_initialize; + status = f_none; + + f_fss_objects extended_objects = f_fss_objects_initialize; + f_fss_contents extended_contents = f_fss_contents_initialize; + + if (command == firewall_parameter_command_lock){ + f_string_location input = f_string_location_initialize; + + input.start = data->contents.array[lock].array[0].start; + input.stop = data->contents.array[lock].array[0].stop; + error_file = lock; + + 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); + + 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(allocation_status, extended_objects); + f_delete_fss_contents(allocation_status, extended_contents); + + 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; + + 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); + } + } + + 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; + + input.start = data->contents.array[first].array[0].start; + input.stop = data->contents.array[first].array[0].stop; + error_file = first; + + 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); + + 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(allocation_status, extended_objects); + f_delete_fss_contents(allocation_status, extended_contents); + + 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 = f_string_length_initialize; + + 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 name_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; + + 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; + + 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); + + 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); + } + } + + break; + } + + // TODO: consider supporting "lock" and "stop" rules for individual devices + } + } + } + + 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); + } + + input.start = data->contents.array[last].array[0].start; + input.stop = data->contents.array[last].array[0].stop; + error_file = last; + + 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); + + 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(allocation_status, extended_objects); + f_delete_fss_contents(allocation_status, extended_contents); + + firewall_delete_data(data); + return status; + } + } + } + } + } + } + + 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"); + } + } + + 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); + } + + // 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); + } 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; + } + } + + firewall_delete_data(data); + 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_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_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; + + // iptables command arguments + 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; + + if (is_global){ + device_all = f_true; + } else { + f_resize_dynamic_string(status, device, data.devices.array[this_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; + } + + for (; counter < objects.used; counter++){ + length = (objects.array[counter].stop - objects.array[counter].start) + 1; + invalid = f_false; + + is_ip_list = f_false; + ip_list_direction = 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 (contents.array[counter].used <= 0 || contents.array[counter].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){ + invalid = f_true; + } else { + direction_input = f_false; + direction_output = f_true; + direction = firewall_direction_prerouting_id; + } + } else { + direction_input = f_true; + direction_output = f_false; + direction = firewall_direction_prerouting_id; + } + } else { + direction_input = f_false; + direction_output = f_true; + direction = firewall_direction_postrouting_id; + } + } else { + direction_input = f_true; + direction_output = f_false; + direction = firewall_direction_postrouting_id; + } + } else { + direction_input = f_false; + direction_output = f_true; + direction = firewall_direction_forward_id; + } + } else { + direction_input = f_true; + direction_output = f_false; + direction = firewall_direction_forward_id; + } + } else { + direction_input = f_false; + direction_output = f_false; + direction = firewall_direction_none_id; + } + } else { + direction_input = f_false; + direction_output = f_false; + direction = firewall_direction_postrouting_id; + } + } else { + direction_input = f_false; + direction_output = f_false; + direction = firewall_direction_prerouting_id; + } + } else { + direction_input = f_false; + direction_output = f_false; + direction = firewall_direction_forward_id; + } + } else { + direction_input = f_false; + direction_output = f_true; + direction = firewall_direction_none_id; + } + } else { + direction_input = f_true; + direction_output = f_false; + direction = firewall_direction_none_id; + } + } + + 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; + + if (contents.array[counter].used <= 0 || contents.array[counter].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){ + 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){ + f_delete_dynamic_string(status, device); + f_resize_dynamic_string(status, device, data.devices.array[this_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; + device_all = f_false; + continue; + } + + if (!invalid){ + f_delete_dynamic_string(status, device); + f_resize_dynamic_string(status, device, length); + + if (f_macro_test_for_allocation_errors(status)) break; + + strncat(device.string, buffer.string + contents.array[counter].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; + + if (contents.array[counter].used <= 0 || contents.array[counter].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){ + invalid = f_true; + } else { + action = firewall_action_none_id; + } + } else { + action = firewall_action_policy_id; + } + } else { + action = firewall_action_insert_id; + } + } else { + action = firewall_action_append_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; + 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){ + 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){ + 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){ + 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, "' 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, "\n"); + continue; + } + + if (invalid){ + length = (objects.array[counter].stop - objects.array[counter].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, "' 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); + 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); + } + + continue; + } + + + // first add the program name + f_delete_dynamic_strings(status, arguments); + f_resize_dynamic_strings(status, arguments, arguments.used + 1); + + if (f_macro_test_for_allocation_errors(status)) break; + + f_resize_dynamic_string(status, argument, firewall_program_name_length); + + if (f_macro_test_for_allocation_errors(status)) break; + + strncat(argument.string, firewall_program_name, firewall_program_name_length); + argument.used = firewall_program_name_length; + + arguments.array[arguments.used].string = argument.string; + arguments.array[arguments.used].size = argument.size; + arguments.array[arguments.used].used = argument.used; + arguments.used++; + argument.string = f_null; + argument.size = 0; + argument.used = 0; + + + // FIXME: (this issue is probably everywhere) Implement an strncat function for dynamic strings or if I already have one implement, make sure it is used in every applicable place + // (this way I can automatically handle updating the used buffer) + // also look into auto-allocated space if necessary with the said function + if (action == firewall_action_append_id){ + f_resize_dynamic_string(status, argument, firewall_action_append_command_length); + + if (f_macro_test_for_allocation_errors(status)) break; + + strncat(argument.string, firewall_action_append_command, firewall_action_append_command_length); + argument.used = firewall_action_append_command_length; + } else if (action == firewall_action_insert_id){ + f_resize_dynamic_string(status, argument, firewall_action_insert_command_length); + + if (f_macro_test_for_allocation_errors(status)) break; + + strncat(argument.string, firewall_action_insert_command, firewall_action_insert_command_length); + argument.used = firewall_action_insert_command_length; + } else if (action == firewall_action_policy_id){ + f_resize_dynamic_string(status, argument, firewall_action_policy_command_length); + + if (f_macro_test_for_allocation_errors(status)) break; + + strncat(argument.string, firewall_action_policy_command, firewall_action_policy_command_length); + argument.used = firewall_action_policy_command_length; + } + + if (argument.used > 0){ + f_resize_dynamic_strings(status, arguments, arguments.used + 1); + + if (f_macro_test_for_allocation_errors(status)) break; + + arguments.array[arguments.used].string = argument.string; + arguments.array[arguments.used].size = argument.size; + arguments.array[arguments.used].used = argument.used; + arguments.used++; + argument.string = f_null; + argument.size = 0; + argument.used = 0; + } + + if (action != firewall_action_none_id){ + 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; + + strncat(argument.string, firewall_direction_forward_command, firewall_direction_forward_command_length); + argument.used = firewall_direction_forward_command_length; + } else if (direction == firewall_direction_postrouting_id){ + f_resize_dynamic_string(status, argument, firewall_direction_postrouting_command_length); + + if (f_macro_test_for_allocation_errors(status)) break; + + strncat(argument.string, firewall_direction_postrouting_command, firewall_direction_postrouting_command_length); + argument.used += firewall_direction_postrouting_command_length; + } else if (direction == firewall_direction_prerouting_id){ + f_resize_dynamic_string(status, argument, firewall_direction_prerouting_command_length); + + if (f_macro_test_for_allocation_errors(status)) break; + + strncat(argument.string, firewall_direction_prerouting_command, firewall_direction_prerouting_command_length); + argument.used = firewall_direction_prerouting_command_length; + } else if (direction_input){ + f_resize_dynamic_string(status, argument, firewall_direction_input_command_length); + + if (f_macro_test_for_allocation_errors(status)) break; + + strncat(argument.string, firewall_direction_input_command, firewall_direction_input_command_length); + argument.used = firewall_direction_input_command_length; + } else if (direction_output){ + f_resize_dynamic_string(status, argument, firewall_direction_output_command_length); + + if (f_macro_test_for_allocation_errors(status)) break; + + strncat(argument.string, firewall_direction_output_command, firewall_direction_output_command_length); + argument.used = firewall_direction_output_command_length; + } + } + + if (argument.used > 0){ + f_resize_dynamic_strings(status, arguments, arguments.used + 1); + + if (f_macro_test_for_allocation_errors(status)) break; + + arguments.array[arguments.used].string = argument.string; + arguments.array[arguments.used].size = argument.size; + arguments.array[arguments.used].used = argument.used; + arguments.used++; + argument.string = f_null; + argument.size = 0; + argument.used = 0; + } + + 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 (direction_input){ + f_resize_dynamic_string(status, argument, firewall_device_input_command_length); + if (f_macro_test_for_allocation_errors(status)) break; + + strncat(argument.string, firewall_device_input_command, firewall_device_input_command_length); + argument.used = firewall_device_input_command_length; + } else if (direction_output){ + f_resize_dynamic_string(status, argument, firewall_device_output_command_length); + if (f_macro_test_for_allocation_errors(status)) break; + + strncat(argument.string, firewall_device_output_command, firewall_device_output_command_length); + argument.used = firewall_device_output_command_length; + } + } + + if (argument.used > 0){ + f_resize_dynamic_strings(status, arguments, arguments.used + 1); + + if (f_macro_test_for_allocation_errors(status)) break; + + arguments.array[arguments.used].string = argument.string; + arguments.array[arguments.used].size = argument.size; + arguments.array[arguments.used].used = argument.used; + arguments.used++; + argument.string = f_null; + argument.size = 0; + argument.used = 0; + } + + if (direction_input || direction_output){ + f_resize_dynamic_string(status, argument, device.used); + if (f_macro_test_for_allocation_errors(status)) break; + + strncat(argument.string, device.string, device.used); + argument.used = device.used; + } + } + + if (argument.used > 0){ + f_resize_dynamic_strings(status, arguments, arguments.used + 1); + + if (f_macro_test_for_allocation_errors(status)) break; + + arguments.array[arguments.used].string = argument.string; + arguments.array[arguments.used].size = argument.size; + arguments.array[arguments.used].used = argument.used; + arguments.used++; + argument.string = f_null; + argument.size = 0; + argument.used = 0; + } + + // last up is the "rule" + if ((!is_ip_list && contents.array[counter].used > 0) || (is_ip_list && contents.array[counter].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; + + f_resize_dynamic_string(status, ip_list, length); + + if (f_macro_test_for_allocation_errors(status)){ + subcounter = contents.array[counter].used; + } else { + strncat(ip_list.string, buffer.string + contents.array[counter].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; + + 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); + argument.used = length; + + if (length > 0){ + f_resize_dynamic_strings(status, arguments, arguments.used + 1); + + if (f_macro_test_for_allocation_errors(status)) break; + + arguments.array[arguments.used].string = argument.string; + arguments.array[arguments.used].size = argument.size; + arguments.array[arguments.used].used = argument.used; + arguments.used++; + argument.string = f_null; + argument.size = 0; + argument.used = 0; + } + } + } else { + length = (objects.array[counter].stop - objects.array[counter].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, "' has no content"); + fl_print_color_code(f_standard_warning, data.context.reset); + fprintf(f_standard_warning, "\n"); + + break; + } + + if (arguments.used > 1){ + if (is_ip_list){ + f_file file = f_file_initialize; + f_dynamic_string file_path = f_dynamic_string_initialize; + f_dynamic_string local_buffer = f_dynamic_string_initialize; + f_file_position file_position = f_file_position_initialize; + + f_fss_objects basic_objects = f_fss_objects_initialize; + f_fss_contents basic_contents = f_fss_objects_initialize; + + f_resize_dynamic_string(status, file_path, network_path_length + ip_list.used + 1); + + if (status == f_none){ + strncat(file_path.string, network_path, network_path_length); + strncat(file_path.string + network_path_length, ip_list.string, ip_list.used); + 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){ + // the file does not have to exist + fl_print_color_line(f_standard_warning, data.context.warning, data.context.reset, "WARNING: Cannot find the file '%s'", file_path.string); + status = f_none; + } else if (status == f_file_open_error){ + fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "ERROR: Unable to open the file '%s'", file_path.string); + } 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); + } 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); + } else { + if (file_position.total_elements == 0){ + fseek(file.file, 0, SEEK_END); + file_position.total_elements = ftell(file.file); + fseek(file.file, 0, SEEK_SET); + } + + status = fl_file_read(file, 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'", 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); + } 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); + } + } else { + { + f_string_location input = f_string_location_initialize; + + input.stop = local_buffer.used - 1; + + status = fll_fss_basic_read(&local_buffer, &input, &basic_objects, &basic_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_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){ + // empty files are to be silently ignored + } 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_read() for the file '%s'", status, file_path.string); + } + } else { + f_string_length buffer_counter = f_string_length_initialize; + f_string_length ip_length = f_string_length_initialize; + f_dynamic_string ip_argument = f_dynamic_string_initialize; + f_dynamic_string ip_list_action = f_dynamic_string_initialize; + + if (ip_list_direction){ + f_resize_dynamic_string(status, ip_list_action, firewall_ip_list_destination_action_length + 1); + strncat(ip_list_action.string, firewall_ip_list_destination_action, firewall_ip_list_destination_action_length); + } else { + f_resize_dynamic_string(status, ip_list_action, firewall_ip_list_source_action_length + 1); + strncat(ip_list_action.string, firewall_ip_list_source_action, firewall_ip_list_source_action_length); + } + + ip_list_action.used = ip_list_action.size; + ip_list_action.string[ip_list_action.used] = 0; + + 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 { + ip_list_action.used = ip_list_action.size; + + f_resize_dynamic_strings(status, arguments, arguments.used + 2); + + 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 { + arguments.array[arguments.used].string = ip_list_action.string; + arguments.array[arguments.used].size = ip_list_action.size; + arguments.array[arguments.used].used = ip_list_action.used; + arguments.used++; + + // the ip_list file contains objects and no content, all objects are what matter an nothing else + for (; buffer_counter < basic_objects.used; buffer_counter++){ + ip_length = (basic_objects.array[buffer_counter].stop - basic_objects.array[buffer_counter].start) + 1; + + f_resize_dynamic_string(status, ip_argument, ip_length); + + 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); + break; + } + + strncat(ip_argument.string, local_buffer.string + basic_objects.array[buffer_counter].start, ip_length); + ip_argument.used = ip_argument.size; + ip_argument.string[ip_argument.used] = 0; + + arguments.array[arguments.used].string = ip_argument.string; + arguments.array[arguments.used].size = ip_argument.size; + arguments.array[arguments.used].used = ip_argument.used; + arguments.used++; + + 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"); + + arguments.used--; + arguments.array[arguments.used].string = 0; + arguments.array[arguments.used].size = 0; + arguments.array[arguments.used].used = 0; + + break; + } else if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_execute_path()"); + + arguments.used--; + arguments.array[arguments.used].string = 0; + arguments.array[arguments.used].size = 0; + arguments.array[arguments.used].used = 0; + + break; + } + + arguments.used--; + arguments.array[arguments.used].string = 0; + arguments.array[arguments.used].size = 0; + arguments.array[arguments.used].used = 0; + + f_delete_dynamic_string(allocation_status, ip_argument); + } + } + } + + f_delete_dynamic_string(allocation_status, ip_argument); + f_delete_dynamic_string(allocation_status, ip_list_action); + + arguments.used--; + arguments.array[arguments.used].string = 0; + arguments.array[arguments.used].size = 0; + arguments.array[arguments.used].used = 0; + } + } + } + + f_delete_dynamic_string(allocation_status, local_buffer); + f_delete_dynamic_string(allocation_status, file_path); + f_delete_fss_objects(allocation_status, basic_objects); + f_delete_fss_contents(allocation_status, basic_contents); + + if (status == f_failure || status == f_invalid_parameter) break; + } else { + 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"); + + break; + } else if (status == f_invalid_parameter){ + fl_print_color_line(f_standard_error, data.context.error, data.context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_execute_path()"); + break; + } + } + } + } + + f_delete_dynamic_string(allocation_status, ip_list); + f_delete_dynamic_string(allocation_status, argument); + f_delete_dynamic_strings(allocation_status, arguments); + f_delete_dynamic_string(allocation_status, device); + + return status; + } +#endif // _di_firewall_main_ + +#ifndef _di_firewall_delete_data_ + f_return_status firewall_delete_data(firewall_data *data){ + f_status status = f_status_initialize; + + f_delete_fss_contents(status, data->contents); + f_delete_fss_objects(status, data->objects); + f_delete_dynamic_string(status, data->buffer); + f_delete_string_lengths(status, data->remaining); + f_delete_dynamic_strings(status, data->devices); + + fll_delete_color_context(status, data->context); + + return f_none; + } +#endif // _di_firewall_delete_data_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/firewall/c/firewall.h b/level_3/firewall/c/firewall.h new file mode 100644 index 0000000..a06ab4a --- /dev/null +++ b/level_3/firewall/c/firewall.h @@ -0,0 +1,272 @@ +/* FLL - Level 3 + * Project: Firewall + * Version: 0.3.x + * Licenses: lgplv2.1 + * Programmers: Kevin Day + * Documentation: + * + * This is the Kevux Operating System Firewall program. + * This program utilizes the Featureless Linux Library. + * This program processes firewall commands and passes them to iptables from netfiler.org + */ +#ifndef _firewall_h + +// libc includes +#include +#include +#include + +// fll-0 includes +#include +#include +#include +#include +#include + +// fll-1 includes +#include +#include +#include +#include +#include + +// fll-2 includes +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef _di_firewall_version_ + #define firewall_major_version "0" + #define firewall_minor_version "3" + #define firewall_micro_version "0" + #define firewall_version firewall_major_version "." firewall_minor_version "." firewall_micro_version +#endif // _di_firewall_version_ + +#ifndef _di_firewall_name_ + #define firewall_name "firewall" + #define firewall_name_long "Kevux Firewall Manager" +#endif // _di_firewall_name_ + +#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_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_suffix_length 9 + #define firewall_program_length 8 + #define firewall_program_name_length 8 +#endif // _di_firewall_paths_ + +#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 + + #define firewall_command_start "start" + #define firewall_command_stop "stop" + #define firewall_command_restart "restart" + #define firewall_command_lock "lock" + #define firewall_command_show "show" + + #define firewall_command_start_length 5 + #define firewall_command_stop_length 4 + #define firewall_command_restart_length 7 + #define firewall_command_lock_length 4 + #define firewall_command_show_length 4 + + #define firewall_ip_list "ip_list" + #define firewall_ip_list_source "source" + #define firewall_ip_list_source_action "-s" + #define firewall_ip_list_destination "destination" + #define firewall_ip_list_destination_action "-d" + + #define firewall_ip_list_length 7 + #define firewall_ip_list_source_length 6 + #define firewall_ip_list_source_action_length 2 + #define firewall_ip_list_destination_length 11 + #define firewall_ip_list_destination_action_length 2 + + #define firewall_rule "rule" + #define firewall_rule_length 4 + + #define firewall_direction "direction" + #define firewall_direction_input "input" + #define firewall_direction_output "output" + #define firewall_direction_forward "forward" + #define firewall_direction_postrouting "postrouting" + #define firewall_direction_prerouting "prerouting" + #define firewall_direction_none "none" + + #define firewall_direction_length 9 + #define firewall_direction_input_length 5 + #define firewall_direction_output_length 6 + #define firewall_direction_forward_length 7 + #define firewall_direction_postrouting_length 12 + #define firewall_direction_prerouting_length 11 + #define firewall_direction_none_length 4 + + #define firewall_direction_forward_input "forward-input" + #define firewall_direction_forward_output "forward-output" + #define firewall_direction_postrouting_input "postrouting-input" + #define firewall_direction_postrouting_output "postrouting-output" + #define firewall_direction_prerouting_input "prerouting-input" + #define firewall_direction_prerouting_output "prerouting-output" + + #define firewall_direction_forward_input_length 13 + #define firewall_direction_forward_output_length 14 + #define firewall_direction_postrouting_input_length 17 + #define firewall_direction_postrouting_output_length 18 + #define firewall_direction_prerouting_input_length 16 + #define firewall_direction_prerouting_output_length 17 + + #define firewall_direction_input_command "INPUT" + #define firewall_direction_output_command "OUTPUT" + #define firewall_direction_forward_command "FORWARD" + #define firewall_direction_postrouting_command "POSTROUTING" + #define firewall_direction_prerouting_command "PREROUTING" + + #define firewall_direction_input_command_length 5 + #define firewall_direction_output_command_length 6 + #define firewall_direction_forward_command_length 7 + #define firewall_direction_postrouting_command_length 12 + #define firewall_direction_prerouting_command_length 11 + + #define firewall_action "action" + #define firewall_action_append "append" + #define firewall_action_insert "insert" + #define firewall_action_policy "policy" + #define firewall_action_none "none" + + #define firewall_action_length 6 + #define firewall_action_append_length 6 + #define firewall_action_insert_length 6 + #define firewall_action_policy_length 6 + #define firewall_action_none_length 4 + + #define firewall_action_append_command "-A" + #define firewall_action_insert_command "-I" + #define firewall_action_policy_command "-P" + + #define firewall_action_append_command_length 2 + #define firewall_action_insert_command_length 2 + #define firewall_action_policy_command_length 2 + + #define firewall_device "device" + #define firewall_device_all "all" + #define firewall_device_this "this" + + #define firewall_device_length 6 + #define firewall_device_all_length 3 + #define firewall_device_this_length 4 + + #define firewall_device_input_command "-i" + #define firewall_device_output_command "-o" + + #define firewall_device_input_command_length 2 + #define firewall_device_output_command_length 2 + + enum { + firewall_parameter_help, + firewall_parameter_light, + firewall_parameter_no_color, + firewall_parameter_version, + firewall_parameter_command_start, + firewall_parameter_command_stop, + firewall_parameter_command_restart, + firewall_parameter_command_lock, + firewall_parameter_command_show, + + firewall_direction_forward_id, + firewall_direction_postrouting_id, + firewall_direction_prerouting_id, + firewall_direction_none_id, + + firewall_action_append_id, + firewall_action_insert_id, + firewall_action_policy_id, + firewall_action_none_id, + }; + + #define f_console_parameter_initialize_firewall \ + { \ + f_console_parameter_initialize(f_console_standard_short_help, f_console_standard_long_help, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(f_console_standard_short_light, f_console_standard_long_light, 0, 0, f_false, f_console_type_inverse, 0), \ + f_console_parameter_initialize(f_console_standard_short_no_color, f_console_standard_long_no_color, 0, 0, f_false, f_console_type_inverse, 0), \ + f_console_parameter_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_false, f_console_type_normal, 0), \ + f_console_parameter_initialize(0, 0, 0, firewall_command_start, f_false, f_console_type_other, firewall_command_start_length), \ + f_console_parameter_initialize(0, 0, 0, firewall_command_stop, f_false, f_console_type_other, firewall_command_stop_length), \ + f_console_parameter_initialize(0, 0, 0, firewall_command_restart, f_false, f_console_type_other, firewall_command_restart_length), \ + f_console_parameter_initialize(0, 0, 0, firewall_command_lock, f_false, f_console_type_other, firewall_command_lock_length), \ + f_console_parameter_initialize(0, 0, 0, firewall_command_show, f_false, f_console_type_other, firewall_command_show_length), \ + } + + #define firewall_total_parameters 9 +#endif // _di_firewall_defines_ + +#ifndef _di_firewall_data_ + typedef struct { + f_console_parameter parameters[firewall_total_parameters]; + + f_dynamic_string buffer; + f_fss_objects objects; + f_fss_contents contents; + f_file_position file_position; + f_string_lengths remaining; + f_dynamic_strings devices; + + fll_color_context context; + } firewall_data; + + #define firewall_data_initialize \ + { \ + f_console_parameter_initialize_firewall, \ + f_dynamic_string_initialize, \ + f_fss_objects_initialize, \ + f_fss_contents_initialize, \ + f_file_position_initialize, \ + f_string_lengths_initialize, \ + f_dynamic_strings_initialize, \ + fll_color_context_initialize, \ + } +#endif // _di_firewall_data_ + +#ifndef _di_firewall_print_version_ + extern f_return_status firewall_print_version(const firewall_data data); +#endif // _di_firewall_print_version_ + +#ifndef _di_firewall_print_help_ + extern f_return_status firewall_print_help(const firewall_data data); +#endif // _di_firewall_print_help_ + +#ifndef _di_firewall_main_ + extern f_return_status firewall_main(const f_s_int argc, const f_string argv[], firewall_data *data); +#endif // _di_firewall_main_ + +#ifndef _di_firewall_delete_data_ + extern f_return_status firewall_delete_data(firewall_data *data); +#endif // _di_firewall_delete_data_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_h diff --git a/level_3/firewall/c/main.c b/level_3/firewall/c/main.c new file mode 100644 index 0000000..de08204 --- /dev/null +++ b/level_3/firewall/c/main.c @@ -0,0 +1,7 @@ +#include + +int main(const f_s_int argc, const f_string argv[]){ + firewall_data data = firewall_data_initialize; + + return firewall_main(argc, argv, &data); +} diff --git a/level_3/firewall/data/build/settings b/level_3/firewall/data/build/settings new file mode 100644 index 0000000..4a71b85 --- /dev/null +++ b/level_3/firewall/data/build/settings @@ -0,0 +1,21 @@ +# fss-0000 + +project_name firewall +project_level 3 + +version_major 0 +version_minor 3 +version_micro 0 + +build_compiler gcc +build_libraries -lc -lf_memory -lf_console -lf_conversion -lf_output -lf_file -lfl_fss -lfl_console -lfl_file -lfl_strings -lfl_colors -lfl_directory -lfll_execute -lfll_fss -lfll_colors -lf_pipe +build_sources_library firewall.c +build_sources_program main.c +build_sources_headers firewall.h +build_shared yes + +flags_all -z now +flags_shared +flags_static +flags_library -fPIC +flags_program -fPIE -lfirewall diff --git a/level_3/firewall/data/settings/default-blacklist b/level_3/firewall/data/settings/default-blacklist new file mode 100644 index 0000000..4f13080 --- /dev/null +++ b/level_3/firewall/data/settings/default-blacklist @@ -0,0 +1 @@ +# fss-0000 diff --git a/level_3/firewall/data/settings/default-firewall b/level_3/firewall/data/settings/default-firewall new file mode 100644 index 0000000..37bf801 --- /dev/null +++ b/level_3/firewall/data/settings/default-firewall @@ -0,0 +1,340 @@ +# fss-0002 +# valid direction: input, output, forward, postrouting, prerouting, none +# valid device: all, this, (any device name goes here without parenthesis) +# valid action: append, insert, policy, none + +first: + # initialize the firewall + direction none + device all + action none + + rule -F + rule -X + rule -Z + rule -t nat -F + rule -t mangle -F + + # setup initial operations + direction input + device all + action append + + + # Enable ALL local connections (loopback) + device lo + direction output + rule -j ACCEPT + + direction input + rule -j ACCEPT + device all + + # the above loopback rules should catch all true loopback connections + # the following loopback rules will only catch anything if a loopback spoofing is happending + # therefore, do not allow spoof by REJECTing + device lo + direction input + rule -s 127.0.0.1 -j REJECT + rule -d 127.0.0.1 -j REJECT + device all + + + # the ip_list command will search for a file in the network settings directory and then apply an action of each of the ip addresses in the file + # the file is simply a set of ip addresses separated by whitespace, preferable each on a newline + # either 'source' or 'destination' must follow the ip_list + # following 'source' or 'destination' is the filename + # this is primarily for whitelisting and blacklisting, below are whitelist & blacklist usage cases + ip_list source default-whitelist -j ACCEPT + ip_list source default-blacklist -j REJECT + ip_list destination default-whitelist -j ACCEPT + ip_list destination default-blacklist -j REJECT + + + ## Explicitly deny dhcp renewals + #rule -p udp -s 0.0.0.0 --sport 67 -d 255.255.255.255 --dport 68 -j REJECT + + + ## Log Network Time Protocol Traffic + #direction output + #rule -p udp --sport 123 --dport 123 -j LOG --log-prefix "TRAFFIC:NTP " + # + #direction input + #rule -p udp --sport 123 --dport 123 -j LOG --log-prefix "TRAFFIC:NTP " + + + ## Log DHCP Client Traffic + #$I -p udp -s 0.0.0.0 --sport 67 -d 255.255.255.255 --dport 68 -j LOG --log-prefix "TRAFFIC:DHCP " + + + ## Log Web Traffic + #direction output + #rule -p tcp --sport 80 -j LOG --log-prefix "TRAFFIC:WEB " + # + #direction input + #rule -p tcp --dport 80 -j LOG --log-prefix "TRAFFIC:WEB " + + + ## Log SSH Traffic + #direction output + #rule -p tcp --sport 22 -j LOG --log-prefix "TRAFFIC:SSH " + # + #direction input + #rule -p tcp --dport 22 -j LOG --log-prefix "TRAFFIC:SSH " + + + ## Log VNC Traffic + # (uses more than just 5900, so this is a little incomplete) + #direction output + #rule -p tcp --sport 5900 -j LOG --log-prefix "TRAFFIC:VNC " + # + #direction input + #rule -p tcp --dport 5900 -j LOG --log-prefix "TRAFFIC:VNC " + + + # Allow ALL input connections that have already been established by this host + rule -m state --state ESTABLISHED,RELATED -j ACCEPT + + + ## Drop all broadcast and multicast packets sent to this machine + #rule -m addrtype --dst-type BROADCAST,MULTICAST -j REJECT + + + ## global forwarding (to/from eth1) + #direction forward + #rule -j ACCEPT -m state --state ESTABLISHED,RELATED -o eth1 + #rule -j ACCEPT -m state --state ESTABLISHED,RELATED -i eth1 + #direction input + + + ## masquerading + #direction postrouting + #rule -t nat -o eth0 -j MASQUERADE + #direction input + + + ## Supply a DMZ to all things to an entire subnet of 192.168.1.0 for eth0 + #direction prerouting + #rule -t nat -j DNAT --to-destination 192.168.1.0-192.168.1.254 -i eth0 + #direction input + + + ## Change the source address before packet leaves the machine + #direction postrouting + #rule -t nat -j SNAT --to-source 222.111.222.11 -o eth0 + #direction input + + # Prevent an XMAS attack + rule -p tcp --tcp-flags ALL ALL -j DROP + + # Prevent NULL attack + rule -p tcp --tcp-flags ALL NONE -j DROP + + # Force SYN packets check + rule -p tcp ! --syn -m state --state NEW -j DROP + + ## Open Moko usb network support (host=eth0 openmoko=usb0) + #direction postrouting + #rule -t nat -o eth0 -j MASQUERADE + #direction forward + #rule -j ACCEPT -o usb0 + #rule -j ACCEPT -i usb0 + #direction input + + + # 113 = identd, firewalling this is safer as well as reducing clutter from ftp-servers and chat programs + rule -p tcp --dport 113 -j REJECT + + + ## Log all dropped packets for debug purposes + #rule 1 -p tcp -m state --state INVALID -j LOG --log-prefix "FIREWALL:INVALID " + + + # Drop all INVALID packets so they aren't even processed + action insert + direction output + rule -m state --state INVALID -j REJECT + + direction input + rule -m state --state INVALID -j REJECT + action append + + + # Disable X's Open Port + # Will X server work with this blocked? Is this needed for X11 Fowarding? + #direction output + #rule -p tcp --dport 6000 -j REJECT + #direction input + rule -p tcp --dport 6000 -j REJECT + + + ## Prevent IP-Spoof attacks (should not come from outside the network, and therefore should only be enabled on a machine that has access outside network) (eth0 = outside network) + #rule -s 10.0.0.0/8 -j REJECT -i eth0 + #rule -s 172.16.0.0/12 -j REJECT -i eth0 + #rule -s 192.168.0.0/16 -j REJECT -i eth0 + + + # Allow dhcp client renewels. If these are blocked, you will not be able to renew easily + rule -p udp -s 0.0.0.0 --sport 67 -d 255.255.255.255 --dport 68 -j ACCEPT + + + # Allow Network Time Protocal Communication + #direction output + #rule -p udp --sport 123 --dport 123 -j ACCEPT + #direction input + + + ## Allows for Samba/Windows Shared Network Communication + ## By default this is set to REJECT, because window shares generally flood the network, which would then flood the firewall rules making them hard to see + ## Windows Ports Uses, and these should never be allowed on WORLD: + ## tcp 136 = Profile Naming System + ## UDP 137 = NETBIOS Name Service + ## UDP 138 = NETBIOS Datagram Service + ## TCP 139 = NETBIOS Session Service + ## TCP 445 = Windows File and Print Sharing + ## TCP/UDP 593 = DCE endpoint resolution, mirror of 135 + #rule -p tcp --dport 136 -j REJECT + #rule -p udp --dport 137 -j REJECT + #rule -p udp --dport 138 -j REJECT + #rule -p tcp --dport 139 -j REJECT + #rule -p tcp --dport 445 -j REJECT + #rule -p tcp --sport 136 -j REJECT + #rule -p udp --sport 137 -j REJECT + #rule -p udp --sport 138 -j REJECT + #rule -p tcp --sport 139 -j REJECT + #rule -p tcp --sport 445 -j REJECT + + + ## ICMP ping/pong (receiving pings) + #rule -p icmp --icmp-type 8 -m limit --limit 1/s -j ACCEPT + + + ## iSCSI Target + #rule -p tcp --dport 3260 -j ACCEPT + + +last: + # setup initial operations + direction input + device all + action append + + + ## allow Well-known port output: 0-1023 + #rule -p tcp --dport 0:1023 -j ACCEPT + #rule -p udp --dport 0:1023 -j ACCEPT + + + ## allow registered ports: 1024-49151 + #rule -p tcp --dport 1024:49151 -j ACCEPT + #rule -p udp --dport 1024:49151 -j ACCEPT + + + ## allow all other ports: 49152-61000 + ## For ease of the uneducated, enable these by default + rule -p tcp --dport 49152:61000 -j ACCEPT + rule -p udp --dport 49152:61000 -j ACCEPT + + + ## allow all other ports: 61001-65535 + ## For ease of the uneducated, enable these by default + rule -p tcp --dport 61001:65535 -j ACCEPT + rule -p udp --dport 61001:65535 -j ACCEPT + + # Log everything else (input) + # everything that reaches this point without being accepted, reject, or otherwise handled will be logged + rule -j LOG --log-prefix "FIREWALL:INPUT " + + # now handle output rules + direction output + + # allow Well-known port output: 0-1023 + rule -p tcp --dport 0:1023 -j ACCEPT + rule -p udp --dport 0:1023 -j ACCEPT + + + # allow registered ports: 1024-49151 + rule -p tcp --dport 1024:49151 -j ACCEPT + rule -p udp --dport 1024:49151 -j ACCEPT + + + # allow all other ports: 49152-61000 + # For ease of the uneducated, enable these by default + rule -p tcp --dport 49152:61000 -j ACCEPT + rule -p udp --dport 49152:61000 -j ACCEPT + + + # allow all other ports: 61001-65535 + # For ease of the uneducated, enable these by default + rule -p tcp --dport 61001:65535 -j ACCEPT + rule -p udp --dport 61001:65535 -j ACCEPT + + ## Log everything else (output) + #rule -j LOG --log-prefix "FIREWALL:OUTPUT " + + # allow icmp output, such as pings + rule -p icmp -j ACCEPT + + # the catch-all policies + action policy + direction input + rule DROP + + direction output + rule DROP + + direction forward + rule DROP + +stop: + device all + action policy + + direction input + rule ACCEPT + + direction output + rule ACCEPT + + direction forward + rule ACCEPT + + direction none + action none + rule --flush + rule -t nat --flush + rule -t mangle --flush + rule --delete-chain + rule -t nat --delete-chain + rule -t mangle --delete-chain + +lock: + device all + action policy + + direction input + rule DROP + + direction output + rule DROP + + direction forward + rule DROP + + direction none + action none + rule --flush + rule -t nat --flush + rule -t mangle --flush + rule --delete-chain + rule -t nat --delete-chain + rule -t mangle --delete-chain + + action insert + direction input + device lo + rule -j ACCEPT + + direction output + device lo + rule -j ACCEPT diff --git a/level_3/firewall/data/settings/default-whitelist b/level_3/firewall/data/settings/default-whitelist new file mode 100644 index 0000000..4f13080 --- /dev/null +++ b/level_3/firewall/data/settings/default-whitelist @@ -0,0 +1 @@ +# fss-0000 diff --git a/level_3/firewall/data/settings/example-device-firewall b/level_3/firewall/data/settings/example-device-firewall new file mode 100644 index 0000000..d5bf363 --- /dev/null +++ b/level_3/firewall/data/settings/example-device-firewall @@ -0,0 +1,80 @@ +# fss-0002 + +main: + # setup initial operations + direction input + device this + action append + + + # Define a blacklist and a whitelist, put ip addresses in the file named 'example-device-whitelist' separated by whitespace to whitelist an ip address + ip_list source example-device-whitelist -j ACCEPT + ip_list source example-device-blacklist -j REJECT + ip_list destination example-device-whitelist -j ACCEPT + ip_list destination example-device-blacklist -j REJECT + + + ## DNS Server (Bind or Maradns) (zoneserver from maradns does this portion) + ## is tcp needed? + #direction output + #rule -p udp --dport 53 -j ACCEPT + #direction input + #rule -p udp --dport 53 -j ACCEPT + + + ## Http / Web + #rule -p tcp --dport 80 --j LOG --log-prefix "TRAFFIC:WEB " + #rule -p tcp --dport 80 -j ACCEPT + + + ## Https / Secure Web + #rule -p tcp --dport 443 --j LOG --log-prefix "TRAFFIC:WEB " + #rule -p tcp --dport 443 -j ACCEPT + + + ## MySQL + #rule -p tcp --dport 3306 -j ACCEPT + + + ## Music Player Daemon + #rule -p tcp --dport 6600 -j ACCEPT + + + ## Camsource + #rule -p tcp --dport 9192 -j ACCEPT + + + ## Cups Printer Administration + #rule -p tcp --dport 631 -j ACCEPT + + + ## Ssh (OpenSSH) + #rule -p tcp --dport 22 -j LOG --log-prefix "TRAFFIC:SSH " + #rule -p tcp --dport 22 -j ACCEPT + + + ## clamd (Clam Antivirus) - remote access, not needed for normal + #rule -p tcp --dport 3310 -j ACCEPT + + + ## Virtual Network Client Server (add 1 for each seperat vnc server) + #rule -p tcp --dport 5900 -j ACCEPT + + + ## Printer Port, is probably open...safer to close unless you are SERVING a printer + #rule -p tcp --dport 515 -j REJECT + + + ## Subversion server + #rule -p tcp --dport 3690 -j ACCEPT + #rule -p udp --dport 3690 -j ACCEPT + + + ## Silc server + #rule -p tcp --dport 706 -j ACCEPT + + + ## Worms of Prey + #rule -p tcp --dport 47288 -j ACCEPT + #rule -p udp --sport 47288:47544 -j ACCEPT + #rule -p udp --dport 47288:47544 -j ACCEPT